source: trunk/kernel/libk/remote_rwlock.c @ 666

Last change on this file since 666 was 666, checked in by alain, 4 years ago

Cosmetic.

File size: 15.8 KB
Line 
1/*
2 * remote_rwlock.c - kernel remote read/write lock implementation.
3 *
4 * Authors    Alain   Greiner (2016,2017,2018,2019)
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 <hal_kernel_types.h>
25#include <hal_remote.h>
26#include <hal_irqmask.h>
27#include <thread.h>
28#include <printk.h>
29#include <cluster.h>
30#include <scheduler.h>
31#include <remote_rwlock.h>
32
33//////////////////////////////////////////////////////////////////////////////
34//                Extern global variables
35//////////////////////////////////////////////////////////////////////////////
36
37extern char * lock_type_str[];          // allocated in kernel_init.c
38
39
40//////////////////////////////////////////
41void remote_rwlock_init( xptr_t   lock_xp,
42                         uint32_t type )
43{ 
44    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
45    cxy_t             lock_cxy = GET_CXY( lock_xp );
46
47    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->taken ) , 0 );
48    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->count ) , 0 );
49
50    xlist_root_init( XPTR( lock_cxy , &lock_ptr->rd_xroot ) );
51    xlist_root_init( XPTR( lock_cxy , &lock_ptr->wr_xroot ) );
52
53    remote_busylock_init( XPTR( lock_cxy , &lock_ptr->lock ) , type ); 
54
55#if DEBUG_RWLOCK_TYPE
56thread_t * this = CURRENT_THREAD;
57bool_t     cond = (type == DEBUG_RWLOCK_TYPE) &&
58                  (((lock_cxy == (cxt_t)DEBUG_RWLOCK_CXY) &&
59                    (lock_ptr == (remote_queuelock_t*)DEBUG_RWLOCK_PTR)) ||
60                   ((DEBUG_RWLOCK_CXY == 0) &&
61                    (DEBUG_RWLOCK_PTR == 0)));
62if( cond )
63printk("\n[%s] thread[%x,%x] initialise lock %s [%x,%x]\n",
64__FUNCTION__, this->process->pid, this->trdid,
65lock_type_str[type], local_cxy, lock_ptr );
66#endif
67
68}
69
70///////////////////////////////////////////////
71void remote_rwlock_rd_acquire( xptr_t lock_xp )
72{ 
73    thread_t * this = CURRENT_THREAD;
74
75    // check calling thread can yield
76    thread_assert_can_yield( this , __FUNCTION__ );
77
78    // get cluster and local pointer on remote_rwlock
79    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
80    cxy_t             lock_cxy = GET_CXY( lock_xp );
81
82#if DEBUG_RWLOCK_TYPE
83uint32_t lock_type   = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
84bool_t   cond        = (type == DEBUG_RWLOCK_TYPE) &&
85                       (((lock_cxy == (cxt_t)DEBUG_RWLOCK_CXY) &&
86                         (lock_ptr == (remote_queuelock_t*)DEBUG_RWLOCK_PTR)) ||
87                        ((DEBUG_RWLOCK_CXY == 0) &&
88                         (DEBUG_RWLOCK_PTR == 0)));
89xptr_t   wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
90#endif
91
92    // build useful extended pointers
93    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
94    xptr_t taken_xp    = XPTR( lock_cxy , &lock_ptr->taken );
95    xptr_t count_xp    = XPTR( lock_cxy , &lock_ptr->count );
96    xptr_t rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
97
98    // get busylock
99    remote_busylock_acquire( busylock_xp );
100
101    // block and deschedule if lock taken
102    while( hal_remote_l32( taken_xp ) )
103    {
104
105#if DEBUG_RWLOCK_TYPE
106if( cond )
107printk("\n[%s] thread[%x,%x] READ BLOCK on %s [%x,%x]\n"
108"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
109__FUNCTION__, this->process->pid, this->trdid, 
110lock_type_str[lock_type], lock_cxy, lock_ptr,
111hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
112xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
113#endif
114        // get pointer on calling thread
115        thread_t * this = CURRENT_THREAD;
116
117        // register reader thread in waiting queue
118        xlist_add_last( rd_root_xp , XPTR( local_cxy , &this->wait_xlist ) );
119
120        // block reader thread
121        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
122
123        // release busylock
124        remote_busylock_release( busylock_xp );
125
126        // deschedule
127        sched_yield("reader wait remote_rwlock");
128
129        // get busylock
130        remote_busylock_acquire( busylock_xp );
131    }
132
133    // increment number of readers
134    hal_remote_atomic_add( count_xp , 1 );
135
136    hal_fence();
137
138#if DEBUG_RWLOCK_TYPE
139if( cond )
140printk("\n[%s] thread[%x,%x] READ ACQUIRE %s [%x,%x]\n"
141"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
142__FUNCTION__, this->process->pid, this->trdid,
143lock_type_str[lock_type], lock_cxy, lock_ptr,
144hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
145xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
146#endif
147
148    // release busylock
149    remote_busylock_release( busylock_xp );
150
151}  // end remote_rwlock_rd_acquire()
152
153///////////////////////////////////////////////
154void remote_rwlock_wr_acquire( xptr_t lock_xp )
155{ 
156    thread_t * this = CURRENT_THREAD;
157
158    // check calling thread can yield
159    thread_assert_can_yield( this , __FUNCTION__ );
160
161    // get cluster and local pointer on remote_rwlock
162    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
163    cxy_t             lock_cxy = GET_CXY( lock_xp );
164
165#if DEBUG_RWLOCK_TYPE
166uint32_t lock_type   = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
167bool_t   cond        = (type == DEBUG_RWLOCK_TYPE) &&
168                       (((lock_cxy == (cxt_t)DEBUG_RWLOCK_CXY) &&
169                         (lock_ptr == (remote_queuelock_t*)DEBUG_RWLOCK_PTR)) ||
170                        ((DEBUG_RWLOCK_CXY == 0) &&
171                         (DEBUG_RWLOCK_PTR == 0)));
172xptr_t   rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
173#endif
174
175    // build useful extended pointers
176    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
177    xptr_t taken_xp    = XPTR( lock_cxy , &lock_ptr->taken );
178    xptr_t count_xp    = XPTR( lock_cxy , &lock_ptr->count );
179    xptr_t wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
180
181    // get busylock
182    remote_busylock_acquire( busylock_xp );
183
184    // block and deschedule if lock already taken or current readers
185    while( hal_remote_l32( taken_xp ) || hal_remote_l32( count_xp ) )
186    {
187
188#if DEBUG_RWLOCK_TYPE
189if( cond )
190printk("\n[%s] thread[%x,%x] WRITE BLOCK on %s [%x,%x]\n"
191"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
192__FUNCTION__, this->process->pid, this->trdid, 
193lock_type_str[lock_type], lock_cxy, lock_ptr, 
194hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
195xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
196#endif
197
198        // get local pointer on calling thread
199        thread_t * this = CURRENT_THREAD;
200
201        // register writer thread in waiting queue
202        xlist_add_last( wr_root_xp , XPTR( local_cxy , &this->wait_xlist ) );
203
204        // block writer thread
205        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
206
207        // release busylock
208        remote_busylock_release( busylock_xp );
209
210        // deschedule
211        sched_yield("writer wait remote_rwlock");
212
213        // get busylock
214        remote_busylock_acquire( busylock_xp );
215    }
216
217    // take rwlock for write
218    hal_remote_s32( taken_xp , 1 );
219
220#if DEBUG_RWLOCK_TYPE
221if( cond )
222printk("\n[%s] thread[%x,%x] WRITE ACQUIRE %s [%x,%x]\n"
223"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
224__FUNCTION__, this->process->pid, this->trdid, 
225lock_type_str[lock_type], lock_cxy, lock_ptr,
226hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
227xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
228#endif
229
230    // release busylock
231    remote_busylock_release( busylock_xp );
232
233}  // end remote_rwlock_wr_acquire()
234
235
236///////////////////////////////////////////////
237void remote_rwlock_rd_release( xptr_t lock_xp )
238{
239    // memory barrier before lock release
240    hal_fence();
241
242    // get cluster and local pointer on remote_rwlock
243    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
244    cxy_t             lock_cxy = GET_CXY( lock_xp );
245
246    // build useful extended pointers
247    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
248    xptr_t count_xp    = XPTR( lock_cxy , &lock_ptr->count );
249    xptr_t rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
250    xptr_t wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
251
252    // get busylock
253    remote_busylock_acquire( busylock_xp );
254
255        // decrement number of readers
256    hal_remote_atomic_add( count_xp , -1 );
257
258#if DEBUG_RWLOCK_TYPE
259thread_t * this      = CURRENT_THREAD;
260uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
261bool_t     cond      = (type == DEBUG_RWLOCK_TYPE) &&
262                       (((lock_cxy == (cxt_t)DEBUG_RWLOCK_CXY) &&
263                         (lock_ptr == (remote_queuelock_t*)DEBUG_RWLOCK_PTR)) ||
264                        ((DEBUG_RWLOCK_CXY == 0) &&
265                         (DEBUG_RWLOCK_PTR == 0)));
266xptr_t     taken_xp  = XPTR( lock_cxy , &lock_ptr->taken );
267#endif
268
269#if DEBUG_RWLOCK_TYPE
270if( cond )
271printk("\n[%s] thread[%x,%x] READ RELEASE %s [%x,%x]\n"
272"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
273__FUNCTION__, this->process->pid, this->trdid,
274lock_type_str[lock_type], lock_cxy, lock_ptr,
275hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
276xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
277#endif
278
279    // release first writer in waiting queue if no current readers
280    // and writers waiting queue non empty
281    if( (hal_remote_l32( count_xp ) == 0) && (xlist_is_empty( wr_root_xp ) == false) )
282    {
283        // get first writer thread
284        xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
285        cxy_t       thread_cxy = GET_CXY( thread_xp ); 
286        thread_t *  thread_ptr = GET_PTR( thread_xp ); 
287
288        // remove this waiting thread from waiting list
289        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
290
291        // unblock this waiting thread
292        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
293
294#if DEBUG_RWLOCK_TYPE
295if( cond )
296{
297    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
298    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
299    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
300    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
301    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
302    lock_type_str[lock_type], lock_cxy, lock_ptr );
303}
304#endif
305
306    }
307
308    // release all readers in waiting queue if writers waiting queue empty
309    // and readers waiting queue non empty
310    else if( xlist_is_empty( wr_root_xp ) && (xlist_is_empty( rd_root_xp ) == false) )
311    {
312        while( xlist_is_empty( rd_root_xp ) == false )
313        {
314            // get first writer thread
315            xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
316            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
317            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
318
319            // remove this waiting thread from waiting list
320            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
321
322            // unblock this waiting thread
323            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
324
325#if DEBUG_RWLOCK_TYPE
326if( cond )
327{
328    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
329    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
330    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
331    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
332    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
333    lock_type_str[lock_type], lock_cxy, lock_ptr );
334}
335#endif
336
337        }
338    }
339
340    // release busylock
341    remote_busylock_release( busylock_xp );
342
343}  // end remote_rwlock_rd_release()
344
345///////////////////////////////////////////////
346void remote_rwlock_wr_release( xptr_t lock_xp )
347{ 
348    // memory barrier before lock release
349    hal_fence();
350
351    // get cluster and local pointer on remote_rwlock
352    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
353    cxy_t             lock_cxy = GET_CXY( lock_xp );
354
355    // build useful extended pointers
356    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
357    xptr_t taken_xp    = XPTR( lock_cxy , &lock_ptr->taken );
358    xptr_t rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
359    xptr_t wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
360
361    // get busylock
362    remote_busylock_acquire( busylock_xp );
363
364    // release rwlock
365    hal_remote_s32( taken_xp , 0 );
366
367#if DEBUG_RWLOCK_TYPE
368thread_t * this      = CURRENT_THREAD;
369uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
370bool_t     cond      = (type == DEBUG_RWLOCK_TYPE) &&
371                       (((lock_cxy == (cxt_t)DEBUG_RWLOCK_CXY) &&
372                         (lock_ptr == (remote_queuelock_t*)DEBUG_RWLOCK_PTR)) ||
373                        ((DEBUG_RWLOCK_CXY == 0) &&
374                         (DEBUG_RWLOCK_PTR == 0)));
375xptr_t     count_xp  = XPTR( lock_cxy , &lock_ptr->count );
376#endif
377
378#if DEBUG_RWLOCK_TYPE
379if( cond )
380printk("\n[%s] thread[%x,%x] WRITE RELEASE %s [%x,%x]\n"
381"     taken %d / count %d / wr_empty %d / rd_empty %d\n",
382__FUNCTION__, this->process->pid, this->trdid,
383lock_type_str[lock_type], lock_cxy, lock_ptr,
384hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
385xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
386#endif
387
388    // unblock first waiting writer thread if writers waiting queue non empty
389    if( xlist_is_empty( wr_root_xp ) == false )
390    {
391        // get first writer thread
392        xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
393        cxy_t       thread_cxy = GET_CXY( thread_xp ); 
394        thread_t *  thread_ptr = GET_PTR( thread_xp ); 
395
396        // remove this waiting thread from waiting list
397        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
398
399        // unblock this waiting thread
400        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
401
402#if DEBUG_RWLOCK_TYPE
403if( cond )
404{
405    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
406    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
407    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
408    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
409    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
410    lock_type_str[lock_type], lock_cxy, lock_ptr );
411}
412#endif
413
414    }
415
416    // check readers waiting queue and unblock all if writers waiting queue empty
417    else 
418    {
419        while( xlist_is_empty( rd_root_xp ) == false )
420        {
421            // get first writer thread
422            xptr_t      thread_xp  = XLIST_FIRST( rd_root_xp , thread_t, wait_xlist );
423            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
424            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
425
426            // remove this waiting thread from waiting list
427            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
428
429            // unblock this waiting thread
430            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
431
432#if DEBUG_RWLOCK_TYPE
433if( cond )
434{
435    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
436    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
437    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
438    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
439    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
440    lock_type_str[lock_type], lock_cxy, lock_ptr );
441}
442#endif
443
444        }
445    }
446
447    // release busylock
448    remote_busylock_release( busylock_xp );
449
450}  // end remote_rwlock_wr_release()
451
452
453
Note: See TracBrowser for help on using the repository browser.