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

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