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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 14.4 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
253printk("\n@@@ in %s : release first waiting writer[%x,%x]\n",
254__FUNCTION__, thread_cxy, thread_ptr );
255
256        // remove this waiting thread from waiting list
257        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
258
259        // unblock this waiting thread
260        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
261
262#if DEBUG_RWLOCK_TYPE
263if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
264{
265    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
266    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
267    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
268    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
269    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
270    lock_type_str[lock_type], lock_cxy, lock_ptr );
271}
272#endif
273
274    }
275
276    // release all readers in waiting queue if writers waiting queue empty
277    // and readers waiting queue non empty
278    else if( xlist_is_empty( wr_root_xp ) && (xlist_is_empty( rd_root_xp ) == false) )
279    {
280        while( xlist_is_empty( rd_root_xp ) == false )
281        {
282            // get first writer thread
283            xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
284            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
285            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
286
287            // remove this waiting thread from waiting list
288            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
289
290            // unblock this waiting thread
291            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
292
293#if DEBUG_RWLOCK_TYPE
294if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
295{
296    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
297    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
298    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
299    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
300    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
301    lock_type_str[lock_type], lock_cxy, lock_ptr );
302}
303#endif
304
305        }
306    }
307
308    // release busylock
309    remote_busylock_release( busylock_xp );
310
311}  // end remote_rwlock_rd_release()
312
313///////////////////////////////////////////////
314void remote_rwlock_wr_release( xptr_t lock_xp )
315{ 
316    // memory barrier before lock release
317    hal_fence();
318
319    // get cluster and local pointer on remote_rwlock
320    remote_rwlock_t * lock_ptr = GET_PTR( lock_xp );
321    cxy_t             lock_cxy = GET_CXY( lock_xp );
322
323    // build useful extended pointers
324    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
325    xptr_t taken_xp    = XPTR( lock_cxy , &lock_ptr->taken );
326    xptr_t rd_root_xp  = XPTR( lock_cxy , &lock_ptr->rd_xroot );
327    xptr_t wr_root_xp  = XPTR( lock_cxy , &lock_ptr->wr_xroot );
328
329    // get busylock
330    remote_busylock_acquire( busylock_xp );
331
332    // release rwlock
333    hal_remote_s32( taken_xp , 0 );
334
335#if DEBUG_RWLOCK_TYPE
336thread_t * this      = CURRENT_THREAD;
337uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
338xptr_t     count_xp  = XPTR( lock_cxy , &lock_ptr->count );
339if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
340printk("\n[%s] thread[%x,%x] WRITE RELEASE rwlock %s [%x,%x] / taken %d / count %d\n",
341__FUNCTION__, this->process->pid, this->trdid,
342lock_type_str[lock_type], lock_cxy, lock_ptr,
343hal_remote_l32( taken_xp ), hal_remote_l32( count_xp ) );
344#endif
345
346    // unblock first waiting writer thread if writers waiting queue non empty
347    if( xlist_is_empty( wr_root_xp ) == false )
348    {
349        // get first writer thread
350        xptr_t      thread_xp  = XLIST_FIRST( wr_root_xp , thread_t, wait_xlist );
351        cxy_t       thread_cxy = GET_CXY( thread_xp ); 
352        thread_t *  thread_ptr = GET_PTR( thread_xp ); 
353
354        // remove this waiting thread from waiting list
355        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
356
357        // unblock this waiting thread
358        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
359
360#if DEBUG_RWLOCK_TYPE
361if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
362{
363    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
364    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
365    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
366    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
367    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
368    lock_type_str[lock_type], lock_cxy, lock_ptr );
369}
370#endif
371
372    }
373
374    // check readers waiting queue and unblock all if writers waiting queue empty
375    else 
376    {
377        while( xlist_is_empty( rd_root_xp ) == false )
378        {
379            // get first writer thread
380            xptr_t      thread_xp  = XLIST_FIRST( rd_root_xp , thread_t, wait_xlist );
381            cxy_t       thread_cxy = GET_CXY( thread_xp ); 
382            thread_t *  thread_ptr = GET_PTR( thread_xp ); 
383
384            // remove this waiting thread from waiting list
385            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
386
387            // unblock this waiting thread
388            thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
389
390#if DEBUG_RWLOCK_TYPE
391if( (DEBUG_RWLOCK_TYPE == lock_type) || (DEBUG_RWLOCK_TYPE == 1000) )
392{
393    trdid_t     trdid     = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
394    process_t * process   = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
395    uint32_t    pid       = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
396    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / rwlock %s [%x,%x]\n",
397    __FUNCTION__, this->process->pid, this->trdid, pid, trdid, 
398    lock_type_str[lock_type], lock_cxy, lock_ptr );
399}
400#endif
401
402        }
403    }
404
405    // release busylock
406    remote_busylock_release( busylock_xp );
407
408}  // end remote_rwlock_wr_release()
409
410
411
Note: See TracBrowser for help on using the repository browser.