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

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

Cosmetic: improve debug.

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