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

Last change on this file since 655 was 629, checked in by alain, 6 years ago

Remove the "giant" rwlock protecting the GPT, and
use the GPT_LOCKED attribute in each PTE to prevent
concurrent modifications of one GPT entry.
The version number has been incremented to 2.1.

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