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

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

Complete restructuration of kernel spinlocks.

File size: 9.5 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 );
[1]51}
52
[563]53/////////////////////////////////////////
54void rwlock_rd_acquire( rwlock_t * lock )
[1]55{
[563]56    thread_t * this = CURRENT_THREAD;
[1]57
[563]58    // check calling thread can yield
59    thread_assert_can_yield( this , __FUNCTION__ );
[1]60
[563]61    // get busylock
62    busylock_acquire( &lock->lock );
63
64    // block and deschedule if lock already taken
65    while( lock->taken )
[1]66    {
[563]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 );
[1]93    }
94
[563]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
[1]103
104    // increment number of readers
105    lock->count++;
106
[563]107    // release busylock
108    busylock_release( &lock->lock );
[409]109
[563]110}  // end rwlock_rd_acquire()
[1]111
[563]112/////////////////////////////////////////
113void rwlock_wr_acquire( rwlock_t * lock )
114{
115    thread_t * this = CURRENT_THREAD;
[1]116
[563]117    // check calling thread can yield
118    thread_assert_can_yield( this , __FUNCTION__ );
[1]119
[563]120    // get busylock
121    busylock_acquire( &lock->lock );
[1]122
[563]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() )
[1]129{
[563]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;
[1]137
[563]138        // register writer in waiting queue
139        list_add_last( &lock->wr_root , &this->wait_list );
[1]140
[563]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}
[409]161#endif
162
[563]163    // take the rwlock
164    lock->taken = 1;
[337]165
[563]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 );
[1]187}
[563]188#endif
[1]189
[563]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() )
[1]202{
[563]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
[1]210
[563]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) )
[1]220    {
[563]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 );
[1]225
[563]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 );
[1]239
[563]240            // unblock this waiting thread
241            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
242        }
[1]243    }
244
[563]245    // release busylock
246    busylock_release( &lock->lock );
[1]247
[563]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}
[409]267#endif
268
[563]269    // release the rwlock
270    lock->taken = 0;
[1]271
[563]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 );
[1]277
[563]278#if DEBUG_RWLOCK
279if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() )
[1]280{
[563]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}
[409]287#endif
[563]288        // remove this waiting thread from waiting list
289        list_unlink( &thread->wait_list );
[409]290
[563]291        // unblock this waiting thread
292        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
293    }
[337]294
[563]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 );
[1]311}
[563]312#endif
313            // remove this waiting thread from waiting list
314            list_unlink( &thread->wait_list );
[1]315
[563]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.