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

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

Complete restructuration of kernel spinlocks.

File size: 14.2 KB
Line 
1/*
2 * remote_rwlock.c - kernel remote rwlock implementation.
3 *
4 * Authors    Alain   Greiner (2016,2017,2018)
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
24#include <hal_kernel_types.h>
25#include <hal_remote.h>
26#include <hal_irqmask.h>
27#include <thread.h>
28#include <printk.h>
29#include <cluster.h>
30#include <scheduler.h>
31#include <remote_rwlock.h>
32
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 )
43{ 
44    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
45    cxy_t             lock_cxy = GET_CXY( lock_xp );
46
47    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->taken ) , 0 );
48    hal_remote_s32 ( XPTR( lock_cxy , &lock_ptr->count ) , 0 );
49
50    xlist_root_init( XPTR( lock_cxy , &lock_ptr->rd_xroot ) );
51    xlist_root_init( XPTR( lock_cxy , &lock_ptr->wr_xroot ) );
52
53    remote_busylock_init( XPTR( lock_cxy , &lock_ptr->lock ) , type ); 
54}
55
56///////////////////////////////////////////////
57void remote_rwlock_rd_acquire( xptr_t lock_xp )
58{ 
59    thread_t * this = CURRENT_THREAD;
60
61    // check calling thread can yield
62    thread_assert_can_yield( this , __FUNCTION__ );
63
64    // get cluster and local pointer on remote_rwlock
65    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
66    cxy_t             lock_cxy = GET_CXY( lock_xp );
67
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 );
73
74    // get busylock
75    remote_busylock_acquire( busylock_xp );
76
77    // block and deschedule if lock taken
78    while( hal_remote_l32( taken_xp ) )
79    {
80
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;
92
93        // register reader thread in waiting queue
94        xlist_add_last( rd_root_xp , XPTR( local_cxy , &this->wait_xlist ) );
95
96        // block reader thread
97        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
98
99        // release busylock
100        remote_busylock_release( busylock_xp );
101
102        // deschedule
103        sched_yield("reader wait remote_rwlock");
104
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}
117#endif
118
119    // increment number of readers
120    hal_remote_atomic_add( count_xp , 1 );
121
122    // release busylock
123    remote_busylock_release( busylock_xp );
124
125}  // end remote_rwlock_rd_acquire()
126
127///////////////////////////////////////////////
128void remote_rwlock_wr_acquire( xptr_t lock_xp )
129{ 
130    thread_t * this = CURRENT_THREAD;
131
132    // check calling thread can yield
133    thread_assert_can_yield( this , __FUNCTION__ );
134
135    // get cluster and local pointer on remote_rwlock
136    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
137    cxy_t             lock_cxy = GET_CXY( lock_xp );
138
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 );
144
145    // get busylock
146    remote_busylock_acquire( busylock_xp );
147
148    // block and deschedule if lock already taken or current readers
149    while( hal_remote_l32( taken_xp ) || hal_remote_l32( count_xp ) )
150    {
151
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;
163
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}
188#endif
189
190    // take rwlock
191    hal_remote_s32( taken_xp , 1 );
192
193    // release busylock
194    remote_busylock_release( busylock_xp );
195
196}  // end remote_rwlock_wr_acquire()
197
198
199///////////////////////////////////////////////
200void remote_rwlock_rd_release( xptr_t lock_xp )
201{
202    // memory barrier before lock release
203    hal_fence();
204
205    // get cluster and local pointer on remote_rwlock
206    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
207    cxy_t             lock_cxy = GET_CXY( lock_xp );
208
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 );
214
215    // get busylock
216    remote_busylock_acquire( busylock_xp );
217
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
228
229        // decrement number of readers
230    hal_remote_atomic_add( count_xp , -1 );
231
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 ); 
240
241        // remove this waiting thread from waiting list
242        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
243
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
261    }
262
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 ); 
273
274            // remove this waiting thread from waiting list
275            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
276
277            // unblock this waiting thread
278            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
279
280#if DEBUG_RWLOCK
281if( (uint32_t)hal_get_cycles() > DEBUG_RWLOCK )
282{
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
293
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
308    // get cluster and local pointer on remote_rwlock
309    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
310    cxy_t             lock_cxy = GET_CXY( lock_xp );
311
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 );
317
318    // get busylock
319    remote_busylock_acquire( busylock_xp );
320
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}
330#endif
331
332    // release rwlock
333    hal_remote_s32( taken_xp , 0 );
334
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 ); 
342
343        // remove this waiting thread from waiting list
344        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
345
346        // unblock this waiting thread
347        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
348
349#if DEBUG_RWLOCK
350if( (uint32_t)hal_get_cycles() > DEBUG_RWLOCK )
351{
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
362
363    }
364
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 ); 
374
375            // remove this waiting thread from waiting list
376            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
377
378            // unblock this waiting thread
379            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
380
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.