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

Last change on this file since 370 was 296, checked in by alain, 7 years ago

Several modifs in the generic scheduler and in the hal_context to
fix the context switch mechanism.

File size: 9.1 KB
Line 
1/*
2 * remote_mutex.c - Access a POSIX mutex.
3 *
4 * Authors   Alain   Greiner (2016)
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_types.h>
25#include <hal_remote.h>
26#include <hal_special.h>
27#include <hal_irqmask.h>
28#include <thread.h>
29#include <cluster.h>
30#include <scheduler.h>
31#include <remote_mutex.h>
32
33/////////////////////////////////////////////////
34xptr_t remote_mutex_from_ident( intptr_t  ident )
35{
36    // get pointer on local process_descriptor
37    process_t * process = CURRENT_THREAD->process;
38
39    // get extended pointer on reference process
40    xptr_t      ref_xp = process->ref_xp;
41
42    // get cluster and local pointer on reference process
43    cxy_t          ref_cxy = GET_CXY( ref_xp );
44    process_t    * ref_ptr = (process_t *)GET_PTR( ref_xp );
45
46    // get extended pointer on root of mutex list
47    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
48   
49    // scan reference process mutex list
50    xptr_t           iter_xp;
51    xptr_t           mutex_xp;
52    cxy_t            mutex_cxy;
53    remote_mutex_t * mutex_ptr;
54    intptr_t         current;
55    bool_t           found = false;
56           
57    XLIST_FOREACH( root_xp , iter_xp )
58    {
59        mutex_xp  = XLIST_ELEMENT( iter_xp , remote_mutex_t , list );
60        mutex_cxy = GET_CXY( mutex_xp );
61        mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
62        current     = (intptr_t)hal_remote_lpt( XPTR( mutex_cxy , &mutex_ptr->ident ) );   
63        if( ident == current )
64        {
65            found = true;
66            break;
67        }
68    }
69
70    if( found == false )  return XPTR_NULL;
71    else                  return mutex_xp;
72
73}  // end remote_mutex_from_ident()
74
75/////////////////////////////////////////////
76error_t remote_mutex_create( intptr_t ident )
77{ 
78    xptr_t           mutex_xp;
79    remote_mutex_t * mutex_ptr;
80
81    // get pointer on local process descriptor
82    process_t * process = CURRENT_THREAD->process;
83
84    // get extended pointer on reference process
85    xptr_t      ref_xp = process->ref_xp;
86
87    // get reference process cluster and local pointer
88    cxy_t       ref_cxy = GET_CXY( ref_xp );
89    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
90
91    // allocate memory for barrier descriptor
92    if( ref_cxy == local_cxy )                  // local cluster is the reference
93    {
94        kmem_req_t req;   
95        req.type    = KMEM_MUTEX;
96        req.flags   = AF_ZERO;
97        mutex_ptr   = kmem_alloc( &req );
98        mutex_xp    = XPTR( local_cxy , mutex_ptr );
99    }
100    else                                       // reference is remote
101    {
102        rpc_kcm_alloc_client( ref_cxy , KMEM_MUTEX , &mutex_xp );
103        mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
104    }
105
106    if( mutex_ptr == NULL ) return ENOMEM;
107
108    // initialise mutex
109    hal_remote_sw ( XPTR( ref_cxy , &mutex_ptr->value )   , 0 );
110    hal_remote_spt( XPTR( ref_cxy , &mutex_ptr->ident )   , (void *)ident );
111    hal_remote_swd( XPTR( ref_cxy , &mutex_ptr->owner )   , XPTR_NULL );
112
113    xlist_entry_init( XPTR( ref_cxy , &mutex_ptr->list ) );
114    xlist_root_init( XPTR( ref_cxy , &mutex_ptr->root ) );
115    remote_spinlock_init( XPTR( ref_cxy , &mutex_ptr->lock ) );
116
117    // register mutex in reference process xlist
118    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
119    xptr_t xp_list = XPTR( ref_cxy , &mutex_ptr->list );
120
121    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
122    xlist_add_first( root_xp , xp_list );
123    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
124
125    return 0;
126
127}  // end remote_mutex_create()
128
129////////////////////////////////////////////
130void remote_mutex_destroy( xptr_t mutex_xp )
131{
132    // get pointer on local process descriptor
133    process_t * process = CURRENT_THREAD->process;
134
135    // get extended pointer on reference process
136    xptr_t      ref_xp = process->ref_xp;
137
138    // get reference process cluster and local pointer
139    cxy_t       ref_cxy = GET_CXY( ref_xp );
140    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
141
142    // get mutex cluster and local pointer
143    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
144    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
145
146    // remove mutex from reference process xlist
147    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
148    xlist_unlink( XPTR( mutex_cxy , &mutex_ptr->list ) );
149    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
150
151    // release memory allocated for mutexaphore descriptor
152    if( mutex_cxy == local_cxy )                            // reference is local
153    {
154        kmem_req_t  req;
155        req.type = KMEM_MUTEX;
156        req.ptr  = mutex_ptr;
157        kmem_free( &req );
158    }
159    else                                                  // reference is remote
160    {
161        rpc_kcm_free_client( mutex_cxy , mutex_ptr , KMEM_BARRIER );
162    }
163
164}  // end remote_mutex_destroy()
165
166/////////////////////////////////////////
167void remote_mutex_lock( xptr_t mutex_xp )
168{ 
169    bool_t    success;
170    reg_t     irq_state;
171
172    // get cluster and local pointer on remote mutex
173    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
174    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
175
176    // get cluster and local pointer on calling thread
177    cxy_t            thread_cxy = local_cxy;
178    thread_t       * thread_ptr = CURRENT_THREAD;
179
180    // get extended pointers on mutex value
181    xptr_t           value_xp = XPTR( mutex_cxy , &mutex_ptr->value );
182
183    // Try to take the mutex
184    success = hal_remote_atomic_cas( value_xp , 0 , 1 );
185
186    if( success )  // take the lock
187    {
188        // register calling thread as mutex owner
189        xptr_t owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
190        hal_remote_swd( owner_xp , XPTR( thread_cxy , thread_ptr ) );
191
192        // increment calling thread remote_locks
193        hal_remote_atomic_add( XPTR( thread_cxy , &thread_ptr->remote_locks ) , 1 );
194    }
195    else           // deschedule and register calling thread in queue
196    {
197        // disable interrupts
198            hal_disable_irq( &irq_state );
199 
200        // register calling thread in mutex waiting queue
201        xptr_t root_xp  = XPTR( mutex_cxy  , &mutex_ptr->root );
202        xptr_t entry_xp = XPTR( thread_cxy , &thread_ptr->wait_list );
203
204        remote_spinlock_lock( XPTR( mutex_cxy , &mutex_ptr->lock ) ); 
205        xlist_add_last( root_xp , entry_xp );
206        remote_spinlock_unlock( XPTR( mutex_cxy , &mutex_ptr->lock ) ); 
207
208        // block & deschedule the calling thread   
209        thread_block( thread_ptr , THREAD_BLOCKED_USERSYNC );
210        sched_yield( NULL );
211
212        // restore interrupts
213        hal_restore_irq( irq_state );
214    } 
215
216    hal_fence();
217
218}  // end remote_mutex_lock()
219
220///////////////////////////////////////////
221void remote_mutex_unlock( xptr_t mutex_xp )
222{
223        reg_t               irq_state;
224
225    // get cluster and local pointer on remote mutex
226    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
227    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
228
229    // get cluster and local pointer on calling thread
230    cxy_t            thread_cxy = local_cxy;
231    thread_t       * thread_ptr = CURRENT_THREAD;
232
233    // get extended pointers on mutex value, root, lock & owner fields
234    xptr_t           value_xp = XPTR( mutex_cxy , &mutex_ptr->value );
235    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
236    xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
237   
238    // disable interrupts
239        hal_disable_irq( &irq_state );
240 
241    // unregister owner thread,
242    hal_remote_swd( owner_xp , XPTR_NULL );
243
244    // decrement calling thread remote_locks
245        hal_remote_atomic_add( XPTR( thread_cxy , &thread_ptr->remote_locks ) , -1 );
246
247    // activate first waiting thread if required
248    if( xlist_is_empty( root_xp ) == false )        // one waiiting thread
249    {
250        // get extended pointer on first waiting thread
251        xptr_t thread_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
252
253        // remove first waiting thread from queue
254        remote_spinlock_lock( XPTR( mutex_cxy , &mutex_ptr->lock ) );
255        xlist_unlink( XPTR( mutex_cxy , &mutex_ptr->list ) );
256        remote_spinlock_unlock( XPTR( mutex_cxy , &mutex_ptr->lock ) );
257
258        // unblock first waiting thread
259        thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC ); 
260    }
261    else                                            // no waiting thread
262    {
263        // release mutex
264        hal_remote_sw( value_xp , 0 );
265    }
266
267    // restore interrupts
268        hal_restore_irq( irq_state );
269
270}  // end remote_mutex_unlock()
271
Note: See TracBrowser for help on using the repository browser.