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

Last change on this file since 593 was 563, checked in by alain, 6 years ago

Complete restructuration of kernel spinlocks.

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