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

Last change on this file since 610 was 610, checked in by alain, 5 years ago

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

File size: 9.4 KB
Line 
1/*
2 * rwlock.c - kernel local read/write lock implementation.
3 *
4 * Author  Alain Greiner     (2016,2017,2018)
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
24#include <kernel_config.h>
25#include <hal_kernel_types.h>
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
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 )
43{ 
44        lock->taken   = 0;
45    lock->count   = 0;
46
47    list_root_init( &lock->rd_root );
48    list_root_init( &lock->wr_root );
49
50    busylock_init( &lock->lock , type );
51
52#if DEBUG_RWLOCK_TYPE
53thread_t * this = CURRENT_THREAD;
54if( DEBUG_RWLOCK_TYPE == type )
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
60}
61
62/////////////////////////////////////////
63void rwlock_rd_acquire( rwlock_t * lock )
64{
65    thread_t * this = CURRENT_THREAD;
66
67    // check calling thread can yield
68    thread_assert_can_yield( this , __FUNCTION__ );
69
70    // get busylock
71    busylock_acquire( &lock->lock );
72
73    // block and deschedule if lock already taken
74    while( lock->taken )
75    {
76
77#if DEBUG_RWLOCK_TYPE
78uint32_t lock_type = lock->lock.type;
79if( DEBUG_RWLOCK_TYPE == lock_type )
80printk("\n[%s] thread[%x,%x] READ BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
81__FUNCTION__, this->process->pid, this->trdid, 
82lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
83#endif
84        // register reader thread in waiting queue
85        list_add_last( &lock->rd_root , &this->wait_list );
86
87        // block reader thread
88        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
89       
90        // release busylock
91        busylock_release( &lock->lock );
92
93        // deschedule
94        sched_yield("reader wait rwlock");
95       
96        // get busylock
97        busylock_acquire( &lock->lock );
98    }
99
100    // increment number of readers
101    lock->count++;
102
103#if DEBUG_RWLOCK_TYPE
104if( DEBUG_RWLOCK_TYPE == lock_type )
105printk("\n[%s] thread[%x,%x] READ ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
106__FUNCTION__, this->process->pid, this->trdid, 
107lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
108#endif
109
110    // release busylock
111    busylock_release( &lock->lock );
112
113}  // end rwlock_rd_acquire()
114
115/////////////////////////////////////////
116void rwlock_wr_acquire( rwlock_t * lock )
117{
118    thread_t * this = CURRENT_THREAD;
119
120    // check calling thread can yield
121    thread_assert_can_yield( this , __FUNCTION__ );
122
123    // get busylock
124    busylock_acquire( &lock->lock );
125
126    // block and deschedule if lock already taken or existing read access
127    while( lock->taken || lock->count )
128    {
129
130#if DEBUG_RWLOCK_TYPE
131uint32_t lock_type = lock->lock.type;
132if( DEBUG_RWLOCK_TYPE == lock_type )
133printk("\n[%s] thread[%x,%x] WRITE BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
134__FUNCTION__, this->process->pid, this->trdid, 
135lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
136#endif
137        // register writer in waiting queue
138        list_add_last( &lock->wr_root , &this->wait_list );
139
140        // block writer thread
141        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
142       
143        // release busylock
144        busylock_release( &lock->lock );
145
146        // deschedule
147        sched_yield("writer wait rwlock");
148       
149        // get busylock
150        busylock_acquire( &lock->lock );
151    }
152
153    // take the rwlock
154    lock->taken = 1;
155
156#if DEBUG_RWLOCK_TYPE
157if( DEBUG_RWLOCK_TYPE == lock_type )
158printk("\n[%s] thread[%x,%x] WRITE ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
159__FUNCTION__, this->process->pid, this->trdid, 
160lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
161#endif
162
163    // release busylock
164    busylock_release( &lock->lock );
165
166}  // end rwlock_wr_acquire()
167
168/////////////////////////////////////////
169void rwlock_rd_release( rwlock_t * lock )
170{
171    // synchronize memory before lock release
172    hal_fence();
173
174    // get busylock
175    busylock_acquire( &lock->lock );
176
177    // decrement number of readers
178    lock->count--;
179
180#if DEBUG_RWLOCK_TYPE
181thread_t * this = CURRENT_THREAD;
182uint32_t lock_type = lock->lock.type;
183if( DEBUG_RWLOCK_TYPE == lock_type )
184printk("\n[%s] thread[%x,%x] READ RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
185__FUNCTION__, this->process->pid, this->trdid, 
186lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
187#endif
188
189    // release first writer in waiting queue if no current readers
190    // and writers waiting queue non empty
191    if( (lock->count == 0) && (list_is_empty( &lock->wr_root ) == false) )
192    {
193        // get first writer thread
194        thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
195
196#if DEBUG_RWLOCK_TYPE
197if( DEBUG_RWLOCK_TYPE == lock_type )
198printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
199__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
200lock_type_str[lock_type], local_cxy, lock );
201#endif
202
203        // remove this waiting thread from waiting list
204        list_unlink( &thread->wait_list );
205
206        // unblock this waiting thread
207        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
208    }
209    // release all readers in waiting queue if writers waiting queue empty
210    // and readers waiting queue non empty
211    else if( list_is_empty( &lock->wr_root ) && (list_is_empty( &lock->rd_root ) == false) )
212    {
213        while( list_is_empty( &lock->rd_root ) == false )
214        {
215            // get first reader thread
216            thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
217
218#if DEBUG_RWLOCK_TYPE
219if( DEBUG_RWLOCK_TYPE == lock_type )
220printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
221__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
222lock_type_str[lock_type], local_cxy, lock );
223#endif
224   
225            // remove this waiting thread from waiting list
226            list_unlink( &thread->wait_list );
227
228            // unblock this waiting thread
229            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
230        }
231    }
232
233    // release busylock
234    busylock_release( &lock->lock );
235
236}  // end rwlock_rd_release()
237
238/////////////////////////////////////////
239void rwlock_wr_release( rwlock_t * lock )
240{
241    // synchronize memory before lock release
242    hal_fence();
243
244    // get busylock
245    busylock_acquire( &lock->lock );
246
247    // release the rwlock
248    lock->taken = 0;
249
250#if DEBUG_RWLOCK_TYPE
251thread_t * this = CURRENT_THREAD;
252uint32_t lock_type = lock->lock.type;
253if( DEBUG_RWLOCK_TYPE == lock_type )
254printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
255__FUNCTION__, this->process->pid, this->trdid, 
256lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
257#endif
258
259    // release first waiting writer thread if writers waiting queue non empty
260    if( list_is_empty( &lock->wr_root ) == false )
261    {
262        // get first writer thread
263        thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list );
264
265#if DEBUG_RWLOCK_TYPE
266if( DEBUG_RWLOCK_TYPE == lock_type )
267printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
268__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
269lock_type_str[lock_type], local_cxy, lock );
270#endif
271        // remove this waiting thread from waiting list
272        list_unlink( &thread->wait_list );
273
274        // unblock this waiting thread
275        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
276    }
277
278    // check readers waiting queue and release all if writers waiting queue empty
279    else 
280    {
281        while( list_is_empty( &lock->rd_root ) == false )
282        {
283            // get first reader thread
284            thread_t * thread = LIST_FIRST( &lock->rd_root , thread_t , wait_list );
285
286#if DEBUG_RWLOCK_TYPE
287if( DEBUG_RWLOCK_TYPE == lock_type )
288printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
289__FUNCTION__, this->process->pid, this->trdid, thread->process->pid, thread->trdid,
290lock_type_str[lock_type], local_cxy, lock );
291#endif
292            // remove this waiting thread from waiting list
293            list_unlink( &thread->wait_list );
294
295            // unblock this waiting thread
296            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
297        }
298    }
299
300    // release busylock
301    busylock_release( &lock->lock );
302
303}  // end rwlock_wr_release()
304
305
Note: See TracBrowser for help on using the repository browser.