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

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

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

File size: 14.0 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( type == DEBUG_RWLOCK_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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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( lock_type == DEBUG_RWLOCK_TYPE )
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.