source: trunk/kernel/libk/remote_mutex.c @ 690

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

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

File size: 12.7 KB
Line 
1/*
2 * remote_mutex.c - POSIX mutex implementation.
3 *
4 * Authors   Alain   Greiner (2016,2017,2018,2019,2020:)
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 <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <hal_remote.h>
27#include <thread.h>
28#include <xlist.h>
29#include <scheduler.h>
30#include <remote_busylock.h>
31#include <remote_mutex.h>
32
33
34/////////////////////////////////////////////////
35xptr_t remote_mutex_from_ident( intptr_t  ident )
36{
37    // get pointer on local process_descriptor
38    process_t * process = CURRENT_THREAD->process;
39
40    // get extended pointer on reference process
41    xptr_t      ref_xp = process->ref_xp;
42
43    // get cluster and local pointer on reference process
44    cxy_t          ref_cxy = GET_CXY( ref_xp );
45    process_t    * ref_ptr = (process_t *)GET_PTR( ref_xp );
46
47    // get extended pointers on mutexes list 
48    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
49    xptr_t lock_xp = XPTR( ref_cxy , &ref_ptr->sync_lock );
50
51    // get lock protecting synchro lists
52    remote_queuelock_acquire( lock_xp );
53 
54    // scan reference process mutex list
55    xptr_t           iter_xp;
56    xptr_t           mutex_xp;
57    cxy_t            mutex_cxy;
58    remote_mutex_t * mutex_ptr;
59    intptr_t         current;
60    bool_t           found = false;
61           
62    XLIST_FOREACH( root_xp , iter_xp )
63    {
64        mutex_xp  = XLIST_ELEMENT( iter_xp , remote_mutex_t , list );
65        mutex_cxy = GET_CXY( mutex_xp );
66        mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
67        current     = (intptr_t)hal_remote_lpt( XPTR( mutex_cxy , &mutex_ptr->ident ) );   
68        if( ident == current )
69        {
70            found = true;
71            break;
72        }
73    }
74
75    // relese lock protecting synchros lists
76    remote_queuelock_release( lock_xp );
77 
78    if( found == false )  return XPTR_NULL;
79    else                  return mutex_xp;
80
81}  // end remote_mutex_from_ident()
82
83/////////////////////////////////////////////
84error_t remote_mutex_create( intptr_t ident )
85{ 
86    remote_mutex_t * mutex_ptr;
87
88    // get pointer on local process descriptor
89    process_t * process = CURRENT_THREAD->process;
90
91    // get extended pointer on reference process
92    xptr_t      ref_xp = process->ref_xp;
93
94    // get reference process cluster and local pointer
95    cxy_t       ref_cxy = GET_CXY( ref_xp );
96    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
97
98    // allocate memory for mutex descriptor in reference cluster
99    mutex_ptr = kmem_remote_alloc( ref_cxy , bits_log2(sizeof(remote_mutex_t)) , AF_ZERO );
100
101    if( mutex_ptr == NULL )
102    {
103       printk("\n[ERROR] in %s : cannot create mutex\n", __FUNCTION__);
104       return -1;
105    }
106
107    // initialise mutex
108    hal_remote_s32 ( XPTR( ref_cxy , &mutex_ptr->taken )   , 0 );
109    hal_remote_spt( XPTR( ref_cxy , &mutex_ptr->ident )   , (void *)ident );
110    xlist_entry_init( XPTR( ref_cxy , &mutex_ptr->list ) );
111    xlist_root_init( XPTR( ref_cxy , &mutex_ptr->root ) );
112    hal_remote_s64( XPTR( ref_cxy , &mutex_ptr->owner ) , XPTR_NULL );
113    remote_busylock_init( XPTR( ref_cxy , &mutex_ptr->lock ), LOCK_MUTEX_STATE );
114
115    // get root of mutexes list in process, and list_entry in mutex
116    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
117    xptr_t xp_list = XPTR( ref_cxy , &mutex_ptr->list );
118
119    // get lock protecting user synchros lists
120    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
121
122    // register mutex in process descriptor
123    xlist_add_first( root_xp , xp_list );
124
125    // release lock protecting user synchros lists
126    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
127
128#if DEBUG_MUTEX
129thread_t * this = CURRENT_THREAD;
130if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
131printk("\n[%s] : thread[%x,%x] created mutex(%x,%x)\n",
132__FUNCTION__, this->process->pid, this->trdid, local_cxy, mutex_ptr );
133#endif
134
135
136    return 0;
137
138}  // end remote_mutex_create()
139
140////////////////////////////////////////////
141void remote_mutex_destroy( xptr_t mutex_xp )
142{
143    // get pointer on local process descriptor
144    process_t * process = CURRENT_THREAD->process;
145
146    // get extended pointer on reference process
147    xptr_t      ref_xp = process->ref_xp;
148
149    // get reference process cluster and local pointer
150    cxy_t       ref_cxy = GET_CXY( ref_xp );
151    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
152
153    // get mutex cluster and local pointer
154    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
155    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
156
157    // get lock protecting user synchros lists
158    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
159
160    // remove mutex from reference process xlist
161    xlist_unlink( XPTR( mutex_cxy , &mutex_ptr->list ) );
162
163    // release lock protecting user synchros lists
164    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
165
166    // release memory allocated for mutex descriptor
167    kmem_remote_free( mutex_cxy , mutex_ptr , bits_log2(sizeof(remote_mutex_t)) );
168
169}  // end remote_mutex_destroy()
170
171/////////////////////////////////////////
172void remote_mutex_lock( xptr_t mutex_xp )
173{ 
174    // get cluster and pointers on calling thread
175    cxy_t            caller_cxy = local_cxy;
176    thread_t       * caller_ptr = CURRENT_THREAD;
177    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
178
179    // check calling thread can yield
180    thread_assert_can_yield( caller_ptr , __FUNCTION__ );
181
182    // get cluster and local pointer on mutex
183    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
184    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
185
186    // get extended pointers on mutex fields
187    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
188    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
189    xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
190    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
191
192    while( 1 )
193    {
194        // get busylock protecting mutex state
195        remote_busylock_acquire( lock_xp );
196
197        // test mutex state
198        if( hal_remote_l32( taken_xp ) == 0 )                 // success
199        {
200            // register calling thread as mutex owner
201            hal_remote_s64( owner_xp , caller_xp );
202
203            // update mutex state
204            hal_remote_s32( taken_xp , 1 );
205
206#if DEBUG_MUTEX
207thread_t * this = CURRENT_THREAD;
208if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
209printk("\n[%s] thread[%x,%x] SUCCESS on mutex(%x,%x)\n",
210__FUNCTION__, this->process->pid, this->trdid, mutex_cxy, mutex_ptr );
211#endif
212
213            // release busylock protecting mutex state
214            remote_busylock_release( lock_xp ); 
215
216             return;
217        }
218        else                                                 //  already taken
219        {
220            // block the calling thread   
221            thread_block( caller_xp , THREAD_BLOCKED_USERSYNC );
222
223            // register calling thread in mutex waiting queue
224            xptr_t entry_xp = XPTR( caller_cxy , &caller_ptr->wait_xlist );
225            xlist_add_last( root_xp , entry_xp );
226
227#if DEBUG_MUTEX
228thread_t * this = CURRENT_THREAD;
229if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
230printk("\n[%s] thread[%x,%x] BLOCKED on mutex(%x,%x)\n",
231__FUNCTION__, this->process->pid, this->trdid, mutex_cxy, mutex_ptr );
232#endif
233
234            // release busylock protecting mutex state
235            remote_busylock_release( lock_xp ); 
236
237            // deschedule calling thread
238            sched_yield("blocked on mutex");
239        }
240    } 
241}  // end remote_mutex_lock()
242
243//////////////////////////////////////////////
244error_t remote_mutex_unlock( xptr_t mutex_xp )
245{
246    // memory barrier before mutex release
247    hal_fence();
248
249    // get cluster and local pointer on mutex
250    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
251    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
252
253    // get cluster and pointers on calling thread
254    cxy_t            caller_cxy = local_cxy;
255    thread_t       * caller_ptr = CURRENT_THREAD;
256    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
257
258    // get extended pointers on mutex fields
259    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
260    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
261    xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
262    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
263
264    // get busylock protecting mutex state
265    remote_busylock_acquire( lock_xp );
266   
267    // check calling thread is mutex owner
268    if( hal_remote_l64( owner_xp ) != caller_xp )
269    {
270        // release busylock protecting mutex state
271        remote_busylock_release( lock_xp );
272
273        return 0xFFFFFFFF;
274    }
275
276#if DEBUG_MUTEX
277thread_t * this = CURRENT_THREAD;
278if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
279printk("\n[%s] thread[%x,%x] EXIT / mutex(%x,%x)\n",
280__FUNCTION__, this->process->pid, this->trdid, mutex_cxy, mutex_ptr );
281#endif
282
283    // update owner field,
284    hal_remote_s64( owner_xp , XPTR_NULL );
285
286    // update taken field
287    hal_remote_s32( taken_xp , 0 );
288
289    // unblock first waiting thread if waiting list non empty
290    if( xlist_is_empty( root_xp ) == false )
291    {
292        // get extended pointer on first waiting thread
293        xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_xlist );
294        thread_t * thread_ptr = GET_PTR( thread_xp );
295        cxy_t      thread_cxy = GET_CXY( thread_xp );
296
297#if DEBUG_MUTEX
298if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
299{
300trdid_t     trdid   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
301process_t * process = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
302pid_t       pid     = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
303printk("\n[%s] thread[%x,%x] UNBLOCK thread %x in process %d / mutex(%x,%x)\n",
304__FUNCTION__, this->process->pid, this->trdid, trdid, pid, mutex_cxy, mutex_ptr );
305}
306#endif
307
308        // remove this thread from waiting queue
309        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
310
311        // unblock first waiting thread
312        thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC ); 
313    }
314   
315    // release busylock protecting mutex state
316    remote_busylock_release( lock_xp );
317
318    return 0;
319
320}  // end remote_mutex_unlock()
321
322///////////////////////////////////////////////
323error_t remote_mutex_trylock( xptr_t mutex_xp )
324{
325    // get cluster and local pointer on mutex
326    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
327    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
328
329    // get cluster and pointers on calling thread
330    cxy_t            caller_cxy = local_cxy;
331    thread_t       * caller_ptr = CURRENT_THREAD;
332    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
333
334    // get extended pointers on mutex fields
335    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
336    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
337    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
338
339    // get busylock protecting mutex state
340    remote_busylock_acquire( lock_xp );
341
342    // test mutex state
343    if( hal_remote_l32( taken_xp ) == 0 )                 // success
344    {
345        // register calling thread as mutex owner
346        hal_remote_s64( owner_xp , caller_xp );
347
348        // update mutex state
349        hal_remote_s32( taken_xp , 1 );
350
351#if DEBUG_MUTEX
352thread_t * this = CURRENT_THREAD;
353if( (uint32_t)hal_get_cycles() > DEBUG_QUEUELOCK )
354printk("\n[%s] SUCCESS for thread[%x,%x] / mutex(%x,%x)\n",
355__FUNCTION__, this->process->pid, this->trdid, mutex_cxy, mutex_ptr );
356#endif
357        // release busylock protecting mutex state
358        remote_busylock_release( lock_xp ); 
359
360        return 0;
361    }
362    else                                                 //  already taken
363    {
364
365#if DEBUG_MUTEX
366thread_t * this = CURRENT_THREAD;
367if( (uint32_t)hal_get_cycles() > DEBUG_QUEUELOCK )
368printk("\n[%s] FAILURE for thread[%x,%x] / mutex(%x,%x)\n",
369__FUNCTION__, this->process->pid, this->trdid, mutex_cxy, mutex_ptr );
370#endif
371        // release busylock protecting mutex state
372        remote_busylock_release( lock_xp ); 
373
374        return 0xFFFFFFFF;
375    }
376}  // end remote_mutex_trylock()
Note: See TracBrowser for help on using the repository browser.