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

Last change on this file since 617 was 610, checked in by alain, 6 years ago

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

File size: 14.0 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;
[610]57if( type == DEBUG_RWLOCK_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
95if( lock_type == DEBUG_RWLOCK_TYPE )
[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
126if( lock_type == DEBUG_RWLOCK_TYPE )
[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
168if( lock_type == DEBUG_RWLOCK_TYPE )
[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
198if( lock_type == DEBUG_RWLOCK_TYPE )
[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 );
[610]237if( lock_type == DEBUG_RWLOCK_TYPE )
[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
260if( lock_type == DEBUG_RWLOCK_TYPE )
[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
291if( lock_type == DEBUG_RWLOCK_TYPE )
[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 );
[610]336if( lock_type == DEBUG_RWLOCK_TYPE )
[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
358if( lock_type == DEBUG_RWLOCK_TYPE )
[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
388if( lock_type == DEBUG_RWLOCK_TYPE )
[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.