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

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

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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