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

Last change on this file since 576 was 563, checked in by alain, 6 years ago

Complete restructuration of kernel spinlocks.

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