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

Last change on this file since 623 was 623, checked in by alain, 5 years ago

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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