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

Last change on this file since 632 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
Line 
1/*
2 * remote_rwlock.c - kernel remote read/write lock implementation.
3 *
4 * Authors    Alain   Greiner (2016,2017,2018,2019)
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#if DEBUG_RWLOCK_TYPE
56thread_t * this = CURRENT_THREAD;
57if( (type               == DEBUG_RWLOCK_TYPE) && 
58    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
59    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
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
65}
66
67///////////////////////////////////////////////
68void remote_rwlock_rd_acquire( xptr_t lock_xp )
69{ 
70    thread_t * this = CURRENT_THREAD;
71
72    // check calling thread can yield
73    thread_assert_can_yield( this , __FUNCTION__ );
74
75    // get cluster and local pointer on remote_rwlock
76    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
77    cxy_t             lock_cxy = GET_CXY( lock_xp );
78
79#if DEBUG_RWLOCK_TYPE
80uint32_t lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
81#endif
82
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 );
88
89    // get busylock
90    remote_busylock_acquire( busylock_xp );
91
92    // block and deschedule if lock taken
93    while( hal_remote_l32( taken_xp ) )
94    {
95
96#if DEBUG_RWLOCK_TYPE
97if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
98    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
99    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
100printk("\n[%s] thread[%x,%x] READ BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
101__FUNCTION__, this->process->pid, this->trdid, 
102lock_type_str[lock_type], lock_cxy, lock_ptr,
103hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
104#endif
105        // get pointer on calling thread
106        thread_t * this = CURRENT_THREAD;
107
108        // register reader thread in waiting queue
109        xlist_add_last( rd_root_xp , XPTR( local_cxy , &this->wait_xlist ) );
110
111        // block reader thread
112        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
113
114        // release busylock
115        remote_busylock_release( busylock_xp );
116
117        // deschedule
118        sched_yield("reader wait remote_rwlock");
119
120        // get busylock
121        remote_busylock_acquire( busylock_xp );
122    }
123
124    // increment number of readers
125    hal_remote_atomic_add( count_xp , 1 );
126
127    hal_fence();
128
129#if DEBUG_RWLOCK_TYPE
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",
134__FUNCTION__, this->process->pid, this->trdid,
135lock_type_str[lock_type], lock_cxy, lock_ptr,
136hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
137#endif
138
139    // release busylock
140    remote_busylock_release( busylock_xp );
141
142}  // end remote_rwlock_rd_acquire()
143
144///////////////////////////////////////////////
145void remote_rwlock_wr_acquire( xptr_t lock_xp )
146{ 
147    thread_t * this = CURRENT_THREAD;
148
149    // check calling thread can yield
150    thread_assert_can_yield( this , __FUNCTION__ );
151
152    // get cluster and local pointer on remote_rwlock
153    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
154    cxy_t             lock_cxy = GET_CXY( lock_xp );
155
156#if DEBUG_RWLOCK_TYPE
157uint32_t lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
158#endif
159
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 );
165
166    // get busylock
167    remote_busylock_acquire( busylock_xp );
168
169    // block and deschedule if lock already taken or current readers
170    while( hal_remote_l32( taken_xp ) || hal_remote_l32( count_xp ) )
171    {
172
173#if DEBUG_RWLOCK_TYPE
174if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
175    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
176    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
177printk("\n[%s] thread[%x,%x] WRITE BLOCK on rwlock %s [%x,%x] / taken %d / count %d\n",
178__FUNCTION__, this->process->pid, this->trdid, 
179lock_type_str[lock_type], lock_cxy, lock_ptr, 
180hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
181#endif
182
183        // get local pointer on calling thread
184        thread_t * this = CURRENT_THREAD;
185
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
202    // take rwlock for write
203    hal_remote_s32( taken_xp , 1 );
204
205#if DEBUG_RWLOCK_TYPE
206if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
207    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
208    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
209printk("\n[%s] thread[%x,%x] WRITE ACQUIRE rwlock %s [%x,%x] / taken %d / count %d\n",
210__FUNCTION__, this->process->pid, this->trdid, 
211lock_type_str[lock_type], lock_cxy, lock_ptr,
212hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
213#endif
214
215    // release busylock
216    remote_busylock_release( busylock_xp );
217
218}  // end remote_rwlock_wr_acquire()
219
220
221///////////////////////////////////////////////
222void remote_rwlock_rd_release( xptr_t lock_xp )
223{
224    // memory barrier before lock release
225    hal_fence();
226
227    // get cluster and local pointer on remote_rwlock
228    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
229    cxy_t             lock_cxy = GET_CXY( lock_xp );
230
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 );
236
237    // get busylock
238    remote_busylock_acquire( busylock_xp );
239
240        // decrement number of readers
241    hal_remote_atomic_add( count_xp , -1 );
242
243#if DEBUG_RWLOCK_TYPE
244thread_t * this      = CURRENT_THREAD;
245uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
246xptr_t     taken_xp  = XPTR( lock_cxy , &lock_ptr->taken );
247if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
248    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
249    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
250printk("\n[%s] thread[%x,%x] READ RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
251__FUNCTION__, this->process->pid, this->trdid,
252lock_type_str[lock_type], lock_cxy, lock_ptr,
253hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
254#endif
255
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 ); 
264
265        // remove this waiting thread from waiting list
266        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
267
268        // unblock this waiting thread
269        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
270
271#if DEBUG_RWLOCK_TYPE
272if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
273    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
274    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
275{
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 );
282}
283#endif
284
285    }
286
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 ); 
297
298            // remove this waiting thread from waiting list
299            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
300
301            // unblock this waiting thread
302            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
303
304#if DEBUG_RWLOCK_TYPE
305if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
306    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
307    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
308{
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 );
315}
316#endif
317
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
332    // get cluster and local pointer on remote_rwlock
333    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
334    cxy_t             lock_cxy = GET_CXY( lock_xp );
335
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 );
341
342    // get busylock
343    remote_busylock_acquire( busylock_xp );
344
345    // release rwlock
346    hal_remote_s32( taken_xp , 0 );
347
348#if DEBUG_RWLOCK_TYPE
349thread_t * this      = CURRENT_THREAD;
350uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
351xptr_t     count_xp  = XPTR( lock_cxy , &lock_ptr->count );
352if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
353    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
354    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
355printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
356__FUNCTION__, this->process->pid, this->trdid,
357lock_type_str[lock_type], lock_cxy, lock_ptr,
358hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
359#endif
360
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 ); 
368
369        // remove this waiting thread from waiting list
370        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
371
372        // unblock this waiting thread
373        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
374
375#if DEBUG_RWLOCK_TYPE
376if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
377    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
378    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
379{
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 );
386}
387#endif
388
389    }
390
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 ); 
400
401            // remove this waiting thread from waiting list
402            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
403
404            // unblock this waiting thread
405            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
406
407#if DEBUG_RWLOCK_TYPE
408if( (lock_type          == DEBUG_RWLOCK_TYPE) && 
409    ((intptr_t)lock_ptr == DEBUG_RWLOCK_PTR ) && 
410    (lock_cxy           == DEBUG_RWLOCK_CXY ) )
411{
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 );
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.