source: trunk/kernel/libk/remote_sem.c @ 633

Last change on this file since 633 was 563, checked in by alain, 6 years ago

Complete restructuration of kernel spinlocks.

File size: 11.2 KB
RevLine 
[1]1/*
[563]2 * remote_sem.c - POSIX unnamed semaphore implementation.
[1]3 *
[563]4 * Author   Alain Greiner  (2016,2017,2018)
[1]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
[457]24#include <hal_kernel_types.h>
[23]25#include <hal_remote.h>
[1]26#include <thread.h>
27#include <kmem.h>
28#include <printk.h>
29#include <process.h>
30#include <vmm.h>
31#include <remote_sem.h>
32
33
34///////////////////////////////////////////////
[563]35xptr_t remote_sem_from_ident( intptr_t  ident )
[1]36{
37    // get pointer on local process_descriptor
[23]38    process_t * process = CURRENT_THREAD->process;
[1]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 );
[469]45    process_t    * ref_ptr = GET_PTR( ref_xp );
[1]46
[563]47    // get extended pointer on semaphores list
[1]48    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->sem_root );
[563]49    xptr_t lock_xp = XPTR( ref_cxy , &ref_ptr->sync_lock );
[1]50   
[563]51    // get lock protecting synchro lists
52    remote_queuelock_acquire( lock_xp );
53 
[1]54    // scan reference process semaphores list
55    xptr_t         iter_xp;
56    xptr_t         sem_xp;
57    cxy_t          sem_cxy;
58    remote_sem_t * sem_ptr;
[563]59    intptr_t       current;
[1]60    bool_t         found = false;
61           
62    XLIST_FOREACH( root_xp , iter_xp )
63    {
[23]64        sem_xp  = XLIST_ELEMENT( iter_xp , remote_sem_t , list );
[1]65        sem_cxy = GET_CXY( sem_xp );
[469]66        sem_ptr = GET_PTR( sem_xp );
[563]67        current = (intptr_t)hal_remote_lpt( XPTR( sem_cxy , &sem_ptr->ident ) );   
[469]68
[563]69        if( current == ident )
[1]70        {
71            found = true;
72            break;
73        }
74    }
75
[563]76    // relese lock protecting synchros lists
77    remote_queuelock_release( lock_xp );
78 
[1]79    if( found == false )  return XPTR_NULL;
80    else                  return sem_xp;
81
[563]82}  // end remote_sem_from_ident()
[1]83
[23]84///////////////////////////////////////////
[457]85error_t remote_sem_create( intptr_t   vaddr,
[563]86                           uint32_t   value )
[1]87{
[457]88    remote_sem_t * sem_ptr;
[1]89    xptr_t         sem_xp;
90
91    // get pointer on local process descriptor
[23]92    process_t * process = CURRENT_THREAD->process;
[1]93
94    // get extended pointer on reference process
95    xptr_t      ref_xp = process->ref_xp;
96
[23]97    // get reference process cluster and local pointer
[1]98    cxy_t       ref_cxy = GET_CXY( ref_xp );
99    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
100
101    // allocate memory for new semaphore in reference cluster
102    if( ref_cxy == local_cxy )  // local cluster is the reference
103    {
104        kmem_req_t req;   
105        req.type  = KMEM_SEM;
106        req.flags = AF_ZERO;
107        sem_ptr   = kmem_alloc( &req );
108        sem_xp    = XPTR( local_cxy , sem_ptr );
109    }
110    else                         // reference is remote
111    {
[23]112        rpc_kcm_alloc_client( ref_cxy , KMEM_SEM , &sem_xp );
[457]113        sem_ptr = GET_PTR( sem_xp );
[1]114    }
115
[563]116    if( sem_xp == XPTR_NULL ) return 0xFFFFFFFF;
[1]117
[23]118    // initialise semaphore
[563]119    hal_remote_s32 ( XPTR( ref_cxy , &sem_ptr->count ) , value );
[1]120        hal_remote_spt( XPTR( ref_cxy , &sem_ptr->ident ) , (void *)vaddr );
[23]121        xlist_root_init( XPTR( ref_cxy , &sem_ptr->root ) );
122        xlist_entry_init( XPTR( ref_cxy , &sem_ptr->list ) );
[563]123    remote_busylock_init( XPTR( ref_cxy , &sem_ptr->lock ), LOCK_SEM_STATE );
[1]124
125    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->sem_root );
[563]126    xptr_t list_xp = XPTR( ref_cxy , &sem_ptr->list );
[1]127
[563]128    // get lock protecting user synchro lists
129    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[457]130
[563]131    // register semaphore in reference process list of semaphores
132    xlist_add_first( root_xp , list_xp );
133
134    // release lock protecting user synchro lists
135    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
136
137#if DEBUG_SEM
138thread_t * this = CURRENT_THREAD;
139if( (uint32_t)hal_get_cycles() > DEBUG_SEM )
140printk("\n[DBG] %s : thread %x in process %x INITIALIZE sem(%x,%x) / value %d\n",
141__FUNCTION__, this->trdid, this->process->pid, local_cxy, sem_ptr, value );
142#endif
143
[1]144    return 0;
145
[563]146}  // end remote_sem_create()
[1]147 
[23]148////////////////////////////////////////
149void remote_sem_destroy( xptr_t sem_xp )
150{
151    // get pointer on local process descriptor
152    process_t * process = CURRENT_THREAD->process;
153
154    // get extended pointer on reference process
155    xptr_t      ref_xp = process->ref_xp;
156
157    // get reference process cluster and local pointer
158    cxy_t       ref_cxy = GET_CXY( ref_xp );
[457]159    process_t * ref_ptr = GET_PTR( ref_xp );
[23]160
161    // get semaphore cluster and local pointer
162    cxy_t          sem_cxy = GET_CXY( sem_xp );
[563]163    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
[23]164
[457]165    // get remote pointer on waiting queue root
166    xptr_t root_xp = XPTR( sem_cxy , &sem_ptr->root );
[23]167 
168    if( !xlist_is_empty( root_xp ) )   // user error
169    {
170        printk("WARNING in %s for thread %x in process %x : "
171               "destroy semaphore, but  waiting threads queue not empty\n", 
172               __FUNCTION__ , CURRENT_THREAD->trdid , CURRENT_THREAD->process->pid );
173    }
174
175    // remove semaphore from reference process xlist
[563]176    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]177    xlist_unlink( XPTR( sem_cxy , &sem_ptr->list ) );
[563]178    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]179
180    // release memory allocated for semaphore descriptor
181    if( sem_cxy == local_cxy )                            // reference is local
182    {
183        kmem_req_t  req;
184        req.type = KMEM_SEM;
185        req.ptr  = sem_ptr;
186        kmem_free( &req );
187    }
188    else                                                  // reference is remote
189    {
190        rpc_kcm_free_client( sem_cxy , sem_ptr , KMEM_SEM );
191    }
192
193}  // end remote_sem_destroy()
194
[457]195/////////////////////////////////////
[1]196void remote_sem_wait( xptr_t sem_xp )
197{ 
[563]198    thread_t * this = CURRENT_THREAD;
199
200// check calling thread can yield
201assert( (this->busylocks == 0),
202"cannot yield : busylocks = %d\n", this->busylocks );
203
204
[1]205    // get semaphore cluster and local pointer
206    cxy_t          sem_cxy = GET_CXY( sem_xp );
[457]207    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
[1]208
[563]209    // get extended pointers on sem fields
210    xptr_t           count_xp = XPTR( sem_cxy , &sem_ptr->count );
211    xptr_t           root_xp  = XPTR( sem_cxy , &sem_ptr->root );
212    xptr_t           lock_xp  = XPTR( sem_cxy , &sem_ptr->lock );
213
214    while( 1 )
215    {
216        // get busylock protecting semaphore     
217            remote_busylock_acquire( lock_xp );
[1]218 
[563]219        // get semaphore current value
220        uint32_t count = hal_remote_l32( count_xp );
[1]221
[563]222            if( count > 0 )                     // success
223            {
224            // decrement semaphore value
225            hal_remote_s32( count_xp , count - 1 );
[1]226
[563]227#if DEBUG_SEM
228if( (uint32_t)hal_get_cycles() > DEBUG_SEM )
229printk("\n[DBG] %s : thread %x in process %x DECREMENT sem(%x,%x) / value %d\n",
230__FUNCTION__, this->trdid, this->process->pid, sem_cxy, sem_ptr, count-1 );
231#endif
232            // release busylock protecting semaphore
233                remote_busylock_release( XPTR( sem_cxy , &sem_ptr->lock ) );
[1]234
[563]235            return;
236        }
237            else                               // failure
238            {
239            // get cluster and pointers on calling thread
240            cxy_t            caller_cxy = local_cxy;
241            thread_t       * caller_ptr = CURRENT_THREAD;
242            xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
[1]243
[563]244            // block the calling thread
245            thread_block( caller_xp , THREAD_BLOCKED_SEM ); 
[1]246
[563]247            // register calling thread in waiting queue
248            xptr_t entry_xp = XPTR( caller_cxy , &caller_ptr->wait_xlist );
249                    xlist_add_last( root_xp , entry_xp );
250
251#if DEBUG_SEM
252if( (uint32_t)hal_get_cycles() > DEBUG_SEM )
253printk("\n[DBG] %s : thread %x in process %x BLOCK on sem(%x,%x) / value %d\n",
254__FUNCTION__, this->trdid, this->process->pid, sem_cxy, sem_ptr, count );
255#endif
256            // release busylock protecting semaphore
257                remote_busylock_release( XPTR( sem_cxy , &sem_ptr->lock ) );
258
259            // deschedule calling thread
260            sched_yield("blocked on semaphore");
261        }
[1]262        }
263}  // end remote_sem_wait()
264
265/////////////////////////////////////
266void remote_sem_post( xptr_t sem_xp )
267{
[563]268    // memory barrier before sem release
269    hal_fence();
270
[1]271    // get semaphore cluster and local pointer
272    cxy_t          sem_cxy = GET_CXY( sem_xp );
[457]273    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
[1]274
[563]275    // get extended pointers on sem fields
276    xptr_t           count_xp = XPTR( sem_cxy , &sem_ptr->count );
277    xptr_t           root_xp  = XPTR( sem_cxy , &sem_ptr->root );
278    xptr_t           lock_xp  = XPTR( sem_cxy , &sem_ptr->lock );
279
280    // get busylock protecting semaphore
281        remote_busylock_acquire( lock_xp );
[1]282 
[563]283    // increment semaphore value
284    hal_remote_atomic_add( count_xp , 1 );
[457]285
[563]286#if DEBUG_SEM
287uint32_t count = hal_remote_l32( count_xp );
288thread_t * this = CURRENT_THREAD;
289if( (uint32_t)hal_get_cycles() > DEBUG_SEM )
290printk("\n[DBG] %s : thread %x in process %x INCREMENT sem(%x,%x) / value %d\n",
291__FUNCTION__, this->trdid, this->process->pid, sem_cxy, sem_ptr, count );
292#endif
293
294    // scan waiting queue to unblock all waiting threads
295        while( xlist_is_empty( root_xp ) == false )   // waiting queue non empty
[1]296    {
297        // get first waiting thread from queue
[563]298        xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_xlist );
[1]299        cxy_t      thread_cxy = GET_CXY( thread_xp );
[457]300        thread_t * thread_ptr = GET_PTR( thread_xp );
[1]301
[563]302        // remove this thread from the waiting queue
303        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
304
305        // unblock this waiting thread
[1]306                thread_unblock( thread_xp , THREAD_BLOCKED_SEM );
[563]307
308#if DEBUG_SEM
309if( (uint32_t)hal_get_cycles() > DEBUG_SEM )
310{
311trdid_t     trdid   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
312process_t * process = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
313pid_t       pid     = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
314printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %x / sem(%x,%x)\n",
315__FUNCTION__, this->trdid, this->process->pid, trdid, pid, sem_cxy, sem_ptr );
316}
317#endif
318
[1]319    }
320
[563]321    // release busylock protecting the semaphore
322        remote_busylock_release( XPTR( sem_cxy , &sem_ptr->lock ) );
[1]323
324}  // end remote_sem_post()
325
326
327//////////////////////////////////////////////
328void remote_sem_get_value( xptr_t      sem_xp,
329                           uint32_t  * data )
330{
331    // get semaphore cluster and local pointer
332    cxy_t          sem_cxy = GET_CXY( sem_xp );
[457]333    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
[1]334
[563]335    *data = hal_remote_l32( XPTR( sem_cxy , &sem_ptr->count ) );
[1]336
337}  // end remote_sem_get_value()
338
339
Note: See TracBrowser for help on using the repository browser.