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

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

Cosmetic.

File size: 15.8 KB
RevLine 
[1]1/*
[600]2 * remote_rwlock.c - kernel remote read/write lock implementation.
[1]3 *
[627]4 * Authors    Alain   Greiner (2016,2017,2018,2019)
[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
[457]24#include <hal_kernel_types.h>
[1]25#include <hal_remote.h>
26#include <hal_irqmask.h>
27#include <thread.h>
[50]28#include <printk.h>
[1]29#include <cluster.h>
30#include <scheduler.h>
31#include <remote_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 remote_rwlock_init( xptr_t   lock_xp,
42                         uint32_t type )
[1]43{ 
[423]44    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]45    cxy_t             lock_cxy = GET_CXY( lock_xp );
46
[563]47    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->taken ) , 0 );
48    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->count ) , 0 );
[409]49
[563]50    xlist_root_init( XPTR( lock_cxy , &lock_ptr->rd_xroot ) );
51    xlist_root_init( XPTR( lock_cxy , &lock_ptr->wr_xroot ) );
[409]52
[563]53    remote_busylock_init( XPTR( lock_cxy , &lock_ptr->lock ) , type ); 
[603]54
[610]55#if DEBUG_RWLOCK_TYPE
[603]56thread_t * this = CURRENT_THREAD;
[666]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 )
[603]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
[1]68}
69
[563]70///////////////////////////////////////////////
71void remote_rwlock_rd_acquire( xptr_t lock_xp )
[1]72{ 
[563]73    thread_t * this = CURRENT_THREAD;
[1]74
[563]75    // check calling thread can yield
76    thread_assert_can_yield( this , __FUNCTION__ );
77
[1]78    // get cluster and local pointer on remote_rwlock
[423]79    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]80    cxy_t             lock_cxy = GET_CXY( lock_xp );
81
[610]82#if DEBUG_RWLOCK_TYPE
[666]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 );
[600]90#endif
91
[563]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 );
[1]97
[563]98    // get busylock
99    remote_busylock_acquire( busylock_xp );
[1]100
[563]101    // block and deschedule if lock taken
102    while( hal_remote_l32( taken_xp ) )
103    {
[1]104
[610]105#if DEBUG_RWLOCK_TYPE
[666]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",
[600]109__FUNCTION__, this->process->pid, this->trdid, 
[603]110lock_type_str[lock_type], lock_cxy, lock_ptr,
[666]111hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
112xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[563]113#endif
114        // get pointer on calling thread
115        thread_t * this = CURRENT_THREAD;
[1]116
[563]117        // register reader thread in waiting queue
118        xlist_add_last( rd_root_xp , XPTR( local_cxy , &this->wait_xlist ) );
[1]119
[563]120        // block reader thread
121        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
[1]122
[563]123        // release busylock
124        remote_busylock_release( busylock_xp );
[1]125
[563]126        // deschedule
127        sched_yield("reader wait remote_rwlock");
[318]128
[563]129        // get busylock
130        remote_busylock_acquire( busylock_xp );
131    }
132
[603]133    // increment number of readers
134    hal_remote_atomic_add( count_xp , 1 );
135
136    hal_fence();
137
[610]138#if DEBUG_RWLOCK_TYPE
[666]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",
[600]142__FUNCTION__, this->process->pid, this->trdid,
[603]143lock_type_str[lock_type], lock_cxy, lock_ptr,
[666]144hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
145xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[409]146#endif
147
[563]148    // release busylock
149    remote_busylock_release( busylock_xp );
[1]150
[563]151}  // end remote_rwlock_rd_acquire()
[1]152
[563]153///////////////////////////////////////////////
154void remote_rwlock_wr_acquire( xptr_t lock_xp )
155{ 
156    thread_t * this = CURRENT_THREAD;
[1]157
[563]158    // check calling thread can yield
159    thread_assert_can_yield( this , __FUNCTION__ );
[1]160
161    // get cluster and local pointer on remote_rwlock
[423]162    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]163    cxy_t             lock_cxy = GET_CXY( lock_xp );
164
[610]165#if DEBUG_RWLOCK_TYPE
[666]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 );
[600]173#endif
174
[563]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 );
[1]180
[563]181    // get busylock
182    remote_busylock_acquire( busylock_xp );
[1]183
[563]184    // block and deschedule if lock already taken or current readers
185    while( hal_remote_l32( taken_xp ) || hal_remote_l32( count_xp ) )
186    {
[1]187
[610]188#if DEBUG_RWLOCK_TYPE
[666]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",
[600]192__FUNCTION__, this->process->pid, this->trdid, 
[603]193lock_type_str[lock_type], lock_cxy, lock_ptr, 
[666]194hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
195xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[563]196#endif
[603]197
[563]198        // get local pointer on calling thread
199        thread_t * this = CURRENT_THREAD;
[318]200
[563]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
[603]217    // take rwlock for write
218    hal_remote_s32( taken_xp , 1 );
219
[610]220#if DEBUG_RWLOCK_TYPE
[666]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",
[600]224__FUNCTION__, this->process->pid, this->trdid, 
[603]225lock_type_str[lock_type], lock_cxy, lock_ptr,
[666]226hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
227xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[409]228#endif
229
[563]230    // release busylock
231    remote_busylock_release( busylock_xp );
[1]232
[563]233}  // end remote_rwlock_wr_acquire()
[1]234
[563]235
236///////////////////////////////////////////////
237void remote_rwlock_rd_release( xptr_t lock_xp )
238{
239    // memory barrier before lock release
240    hal_fence();
241
[1]242    // get cluster and local pointer on remote_rwlock
[423]243    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]244    cxy_t             lock_cxy = GET_CXY( lock_xp );
245
[563]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 );
[1]251
[563]252    // get busylock
253    remote_busylock_acquire( busylock_xp );
[1]254
[603]255        // decrement number of readers
256    hal_remote_atomic_add( count_xp , -1 );
257
[610]258#if DEBUG_RWLOCK_TYPE
[600]259thread_t * this      = CURRENT_THREAD;
260uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
[666]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)));
[603]266xptr_t     taken_xp  = XPTR( lock_cxy , &lock_ptr->taken );
[666]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",
[600]273__FUNCTION__, this->process->pid, this->trdid,
[603]274lock_type_str[lock_type], lock_cxy, lock_ptr,
[666]275hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
276xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[563]277#endif
[1]278
[563]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 ); 
[1]287
[563]288        // remove this waiting thread from waiting list
289        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[1]290
[563]291        // unblock this waiting thread
292        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
293
[610]294#if DEBUG_RWLOCK_TYPE
[666]295if( cond )
[563]296{
[600]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 );
[563]303}
304#endif
305
[1]306    }
307
[563]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 ); 
[1]318
[563]319            // remove this waiting thread from waiting list
320            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[318]321
[563]322            // unblock this waiting thread
323            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[1]324
[610]325#if DEBUG_RWLOCK_TYPE
[666]326if( cond )
[1]327{
[600]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 );
[563]334}
335#endif
[1]336
[563]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
[1]351    // get cluster and local pointer on remote_rwlock
[423]352    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]353    cxy_t             lock_cxy = GET_CXY( lock_xp );
354
[563]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 );
[1]360
[563]361    // get busylock
362    remote_busylock_acquire( busylock_xp );
[1]363
[603]364    // release rwlock
365    hal_remote_s32( taken_xp , 0 );
366
[610]367#if DEBUG_RWLOCK_TYPE
[600]368thread_t * this      = CURRENT_THREAD;
369uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
[666]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)));
[603]375xptr_t     count_xp  = XPTR( lock_cxy , &lock_ptr->count );
[666]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",
[600]382__FUNCTION__, this->process->pid, this->trdid,
[603]383lock_type_str[lock_type], lock_cxy, lock_ptr,
[666]384hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ),
385xlist_is_empty( wr_root_xp ), xlist_is_empty( rd_root_xp ) );
[409]386#endif
387
[563]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 ); 
[318]395
[563]396        // remove this waiting thread from waiting list
397        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[1]398
[563]399        // unblock this waiting thread
400        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[1]401
[610]402#if DEBUG_RWLOCK_TYPE
[666]403if( cond )
[50]404{
[600]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 );
[563]411}
412#endif
[1]413
[563]414    }
[50]415
[563]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 ); 
[50]425
[563]426            // remove this waiting thread from waiting list
427            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[50]428
[563]429            // unblock this waiting thread
430            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[50]431
[610]432#if DEBUG_RWLOCK_TYPE
[666]433if( cond )
[563]434{
[600]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 );
[563]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.