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

Last change on this file since 625 was 625, checked in by alain, 5 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 14.4 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
[625]253printk("\n@@@ in %s : release first waiting writer[%x,%x]\n",
254__FUNCTION__, thread_cxy, thread_ptr );
255
[563]256        // remove this waiting thread from waiting list
257        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[1]258
[563]259        // unblock this waiting thread
260        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
261
[610]262#if DEBUG_RWLOCK_TYPE
[623]263if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
[563]264{
[600]265    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
266    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
267    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
268    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
269    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
270    lock_type_str[lock_type], lock_cxy, lock_ptr );
[563]271}
272#endif
273
[1]274    }
275
[563]276    // release all readers in waiting queue if writers waiting queue empty
277    // and readers waiting queue non empty
278    else if( xlist_is_empty( wr_root_xp ) && (xlist_is_empty( rd_root_xp ) == false) )
279    {
280        while( xlist_is_empty( rd_root_xp ) == false )
281        {
282            // get first writer thread
283            xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
284            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
285            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
[1]286
[563]287            // remove this waiting thread from waiting list
288            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[318]289
[563]290            // unblock this waiting thread
291            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[1]292
[610]293#if DEBUG_RWLOCK_TYPE
[623]294if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
[1]295{
[600]296    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
297    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
298    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
299    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
300    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
301    lock_type_str[lock_type], lock_cxy, lock_ptr );
[563]302}
303#endif
[1]304
[563]305        }
306    }
307
308    // release busylock
309    remote_busylock_release( busylock_xp );
310
311}  // end remote_rwlock_rd_release()
312
313///////////////////////////////////////////////
314void remote_rwlock_wr_release( xptr_t lock_xp )
315{ 
316    // memory barrier before lock release
317    hal_fence();
318
[1]319    // get cluster and local pointer on remote_rwlock
[423]320    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
[1]321    cxy_t             lock_cxy = GET_CXY( lock_xp );
322
[563]323    // build useful extended pointers
324    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
325    xptr_t taken_xp    = XPTR( lock_cxy , &lock_ptr->taken );
326    xptr_t rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
327    xptr_t wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
[1]328
[563]329    // get busylock
330    remote_busylock_acquire( busylock_xp );
[1]331
[603]332    // release rwlock
333    hal_remote_s32( taken_xp , 0 );
334
[610]335#if DEBUG_RWLOCK_TYPE
[600]336thread_t * this      = CURRENT_THREAD;
337uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
[603]338xptr_t     count_xp  = XPTR( lock_cxy , &lock_ptr->count );
[623]339if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
[603]340printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
[600]341__FUNCTION__, this->process->pid, this->trdid,
[603]342lock_type_str[lock_type], lock_cxy, lock_ptr,
343hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
[409]344#endif
345
[563]346    // unblock first waiting writer thread if writers waiting queue non empty
347    if( xlist_is_empty( wr_root_xp ) == false )
348    {
349        // get first writer thread
350        xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
351        cxy_t       thread_cxy = GET_CXY( thread_xp ); 
352        thread_t *  thread_ptr = GET_PTR( thread_xp ); 
[318]353
[563]354        // remove this waiting thread from waiting list
355        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[1]356
[563]357        // unblock this waiting thread
358        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[1]359
[610]360#if DEBUG_RWLOCK_TYPE
[623]361if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
[50]362{
[600]363    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
364    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
365    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
366    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
367    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
368    lock_type_str[lock_type], lock_cxy, lock_ptr );
[563]369}
370#endif
[1]371
[563]372    }
[50]373
[563]374    // check readers waiting queue and unblock all if writers waiting queue empty
375    else 
376    {
377        while( xlist_is_empty( rd_root_xp ) == false )
378        {
379            // get first writer thread
380            xptr_t      thread_xp  = XLIST_FIRST( rd_root_xp , thread_t, wait_xlist );
381            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
382            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
[50]383
[563]384            // remove this waiting thread from waiting list
385            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[50]386
[563]387            // unblock this waiting thread
388            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
[50]389
[610]390#if DEBUG_RWLOCK_TYPE
[623]391if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
[563]392{
[600]393    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
394    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
395    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
396    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
397    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
398    lock_type_str[lock_type], lock_cxy, lock_ptr );
[563]399}
400#endif
401
402        }
403    }
404
405    // release busylock
406    remote_busylock_release( busylock_xp );
407
408}  // end remote_rwlock_wr_release()
409
410
411
Note: See TracBrowser for help on using the repository browser.