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

Last change on this file since 626 was 623, checked in by alain, 6 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
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#if DEBUG_RWLOCK_TYPE
74uint32_t lock_type = lock->lock.type;
75#endif
76
77    // block and deschedule if lock already taken
78    while( lock->taken )
79    {
80
81#if DEBUG_RWLOCK_TYPE
82if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
83printk("\n[%s] thread[%x,%x] READ BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
84__FUNCTION__, this->process->pid, this->trdid, 
85lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
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 );
101    }
102
103    // increment number of readers
104    lock->count++;
105
106#if DEBUG_RWLOCK_TYPE
107if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
108printk("\n[%s] thread[%x,%x] READ ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
109__FUNCTION__, this->process->pid, this->trdid, 
110lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
111#endif
112
113    // release busylock
114    busylock_release( &lock->lock );
115
116}  // end rwlock_rd_acquire()
117
118/////////////////////////////////////////
119void rwlock_wr_acquire( rwlock_t * lock )
120{
121    thread_t * this = CURRENT_THREAD;
122
123    // check calling thread can yield
124    thread_assert_can_yield( this , __FUNCTION__ );
125
126    // get busylock
127    busylock_acquire( &lock->lock );
128
129#if DEBUG_RWLOCK_TYPE
130uint32_t lock_type = lock->lock.type;
131#endif
132
133    // block and deschedule if lock already taken or existing read access
134    while( lock->taken || lock->count )
135    {
136
137#if DEBUG_RWLOCK_TYPE
138if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
139printk("\n[%s] thread[%x,%x] WRITE BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
140__FUNCTION__, this->process->pid, this->trdid, 
141lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
142#endif
143        // register writer in waiting queue
144        list_add_last( &lock->wr_root , &this->wait_list );
145
146        // block writer thread
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
159    // take the rwlock
160    lock->taken = 1;
161
162#if DEBUG_RWLOCK_TYPE
163if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
164printk("\n[%s] thread[%x,%x] WRITE ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
165__FUNCTION__, this->process->pid, this->trdid, 
166lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
167#endif
168
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
183    // decrement number of readers
184    lock->count--;
185
186#if DEBUG_RWLOCK_TYPE
187thread_t * this = CURRENT_THREAD;
188uint32_t lock_type = lock->lock.type;
189if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
190printk("\n[%s] thread[%x,%x] READ RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
191__FUNCTION__, this->process->pid, this->trdid, 
192lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
193#endif
194
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
202#if DEBUG_RWLOCK_TYPE
203if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
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,
206lock_type_str[lock_type], local_cxy, lock );
207#endif
208
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) )
218    {
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 );
223
224#if DEBUG_RWLOCK_TYPE
225if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
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,
228lock_type_str[lock_type], local_cxy, lock );
229#endif
230   
231            // remove this waiting thread from waiting list
232            list_unlink( &thread->wait_list );
233
234            // unblock this waiting thread
235            thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
236        }
237    }
238
239    // release busylock
240    busylock_release( &lock->lock );
241
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
253    // release the rwlock
254    lock->taken = 0;
255
256#if DEBUG_RWLOCK_TYPE
257thread_t * this = CURRENT_THREAD;
258uint32_t lock_type = lock->lock.type;
259if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
260printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
261__FUNCTION__, this->process->pid, this->trdid, 
262lock_type_str[lock_type], local_cxy, lock, lock->taken, lock->count );
263#endif
264
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 );
270
271#if DEBUG_RWLOCK_TYPE
272if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
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,
275lock_type_str[lock_type], local_cxy, lock );
276#endif
277        // remove this waiting thread from waiting list
278        list_unlink( &thread->wait_list );
279
280        // unblock this waiting thread
281        thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK );
282    }
283
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
292#if DEBUG_RWLOCK_TYPE
293if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
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,
296lock_type_str[lock_type], local_cxy, lock );
297#endif
298            // remove this waiting thread from waiting list
299            list_unlink( &thread->wait_list );
300
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.