source: trunk/kernel/libk/rwlock.c @ 605

Last change on this file since 605 was 603, checked in by alain, 6 years ago

Improve the FAT32 file system to support cat, rm, cp commands.

File size: 9.4 KB
RevLine 
[1]1/*
[563]2 * rwlock.c - kernel local read/write lock implementation.
[1]3 *
[436]4 * Author  Alain Greiner     (2016,2017,2018)
[1]5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[14]24#include <kernel_config.h>
[457]25#include <hal_kernel_types.h>
[1]26#include <hal_atomic.h>
27#include <hal_special.h>
28#include <hal_irqmask.h>
29#include <thread.h>
30#include <printk.h>
31#include <rwlock.h>
32
[563]33//////////////////////////////////////////////////////////////////////////////
34//                Extern global variables
35//////////////////////////////////////////////////////////////////////////////
36
37extern char * lock_type_str[];          // allocated in kernel_init.c
38
39
40//////////////////////////////////
41void rwlock_init( rwlock_t * lock,
42                  uint32_t   type )
[1]43{ 
[563]44        lock->taken   = 0;
[1]45    lock->count   = 0;
[409]46
[563]47    list_root_init( &lock->rd_root );
48    list_root_init( &lock->wr_root );
[409]49
[563]50    busylock_init( &lock->lock , type );
[603]51
52#if DEBUG_RWLOCK
53thread_t * this = CURRENT_THREAD;
54if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
55printk("\n[%s] thread[%x,%x] initialise lock %s [%x,%x]\n",
56__FUNCTION__, this->process->pid, this->trdid,
57lock_type_str[type], local_cxy, lock );
58#endif
59
[1]60}
61
[563]62/////////////////////////////////////////
63void rwlock_rd_acquire( rwlock_t * lock )
[1]64{
[563]65    thread_t * this = CURRENT_THREAD;
[1]66
[563]67    // check calling thread can yield
68    thread_assert_can_yield( this , __FUNCTION__ );
[1]69
[563]70    // get busylock
71    busylock_acquire( &lock->lock );
72
73    // block and deschedule if lock already taken
74    while( lock->taken )
[1]75    {
[563]76
77#if DEBUG_RWLOCK
78if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]79printk("\n[%s] thread[%x,%x] READ BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
[600]80__FUNCTION__, this->process->pid, this->trdid, 
[603]81lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[563]82#endif
83        // register reader thread in waiting queue
84        list_add_last( &lock->rd_root , &this->wait_list );
85
86        // block reader thread
87        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
88       
89        // release busylock
90        busylock_release( &lock->lock );
91
92        // deschedule
93        sched_yield("reader wait rwlock");
94       
95        // get busylock
96        busylock_acquire( &lock->lock );
[1]97    }
98
[603]99    // increment number of readers
100    lock->count++;
101
[563]102#if DEBUG_RWLOCK
103if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]104printk("\n[%s] thread[%x,%x] READ ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
[600]105__FUNCTION__, this->process->pid, this->trdid, 
[603]106lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[563]107#endif
[1]108
[563]109    // release busylock
110    busylock_release( &lock->lock );
[409]111
[563]112}  // end rwlock_rd_acquire()
[1]113
[563]114/////////////////////////////////////////
115void rwlock_wr_acquire( rwlock_t * lock )
116{
117    thread_t * this = CURRENT_THREAD;
[1]118
[563]119    // check calling thread can yield
120    thread_assert_can_yield( this , __FUNCTION__ );
[1]121
[563]122    // get busylock
123    busylock_acquire( &lock->lock );
[1]124
[563]125    // block and deschedule if lock already taken or existing read access
126    while( lock->taken || lock->count )
127    {
128
129#if DEBUG_RWLOCK
130if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]131printk("\n[%s] thread[%x,%x] WRITE BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
[600]132__FUNCTION__, this->process->pid, this->trdid, 
[603]133lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[563]134#endif
135        // register writer in waiting queue
136        list_add_last( &lock->wr_root , &this->wait_list );
[1]137
[603]138        // block writer thread
[563]139        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
140       
141        // release busylock
142        busylock_release( &lock->lock );
143
144        // deschedule
145        sched_yield("writer wait rwlock");
146       
147        // get busylock
148        busylock_acquire( &lock->lock );
149    }
150
[603]151    // take the rwlock
152    lock->taken = 1;
153
[563]154#if DEBUG_RWLOCK
155if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]156printk("\n[%s] thread[%x,%x] WRITE ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
[600]157__FUNCTION__, this->process->pid, this->trdid, 
[603]158lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[409]159#endif
160
[563]161    // release busylock
162    busylock_release( &lock->lock );
163
164}  // end rwlock_wr_acquire()
165
166/////////////////////////////////////////
167void rwlock_rd_release( rwlock_t * lock )
168{
169    // synchronize memory before lock release
170    hal_fence();
171
172    // get busylock
173    busylock_acquire( &lock->lock );
174
[603]175    // decrement number of readers
176    lock->count--;
177
[563]178#if DEBUG_RWLOCK
[600]179thread_t * this = CURRENT_THREAD;
[563]180if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]181printk("\n[%s] thread[%x,%x] READ RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
[600]182__FUNCTION__, this->process->pid, this->trdid, 
[603]183lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[563]184#endif
[1]185
[563]186    // release first writer in waiting queue if no current readers
187    // and writers waiting queue non empty
188    if( (lock->count == 0) && (list_is_empty( &lock->wr_root ) == false) )
189    {
190        // get first writer thread
191        thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
192
193#if DEBUG_RWLOCK
194if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[600]195printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
196__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
197lock_type_str[lock->lock.type], local_cxy, lock );
[563]198#endif
[1]199
[563]200        // remove this waiting thread from waiting list
201        list_unlink( &thread->wait_list );
202
203        // unblock this waiting thread
204        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
205    }
206    // release all readers in waiting queue if writers waiting queue empty
207    // and readers waiting queue non empty
208    else if( list_is_empty( &lock->wr_root ) && (list_is_empty( &lock->rd_root ) == false) )
[1]209    {
[563]210        while( list_is_empty( &lock->rd_root ) == false )
211        {
212            // get first reader thread
213            thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
[1]214
[563]215#if DEBUG_RWLOCK
216if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[600]217printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
218__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
219lock_type_str[lock->lock.type], local_cxy, lock );
[563]220#endif
221   
222            // remove this waiting thread from waiting list
223            list_unlink( &thread->wait_list );
[1]224
[563]225            // unblock this waiting thread
226            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
227        }
[1]228    }
229
[563]230    // release busylock
231    busylock_release( &lock->lock );
[1]232
[563]233}  // end rwlock_rd_release()
234
235/////////////////////////////////////////
236void rwlock_wr_release( rwlock_t * lock )
237{
238    // synchronize memory before lock release
239    hal_fence();
240
241    // get busylock
242    busylock_acquire( &lock->lock );
243
[603]244    // release the rwlock
245    lock->taken = 0;
246
[563]247#if DEBUG_RWLOCK
[600]248thread_t * this = CURRENT_THREAD;
[563]249if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[603]250printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
[600]251__FUNCTION__, this->process->pid, this->trdid, 
[603]252lock_type_str[lock->lock.type], local_cxy, lock, lock->taken, lock->count );
[409]253#endif
254
[563]255    // release first waiting writer thread if writers waiting queue non empty
256    if( list_is_empty( &lock->wr_root ) == false )
257    {
258        // get first writer thread
259        thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
[1]260
[563]261#if DEBUG_RWLOCK
262if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[600]263printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
264__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
265lock_type_str[lock->lock.type], local_cxy, lock );
[409]266#endif
[563]267        // remove this waiting thread from waiting list
268        list_unlink( &thread->wait_list );
[409]269
[563]270        // unblock this waiting thread
271        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
272    }
[337]273
[563]274    // check readers waiting queue and release all if writers waiting queue empty
275    else 
276    {
277        while( list_is_empty( &lock->rd_root ) == false )
278        {
279            // get first reader thread
280            thread_t * thread = LIST_FIRST( &lock->rd_root , thread_t , wait_list );
281
282#if DEBUG_RWLOCK
283if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[600]284printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
285__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
286lock_type_str[lock->lock.type], local_cxy, lock );
[563]287#endif
288            // remove this waiting thread from waiting list
289            list_unlink( &thread->wait_list );
[1]290
[563]291            // unblock this waiting thread
292            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
293        }
294    }
295
296    // release busylock
297    busylock_release( &lock->lock );
298
299}  // end rwlock_wr_release()
300
301
Note: See TracBrowser for help on using the repository browser.