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

Last change on this file since 500 was 469, checked in by alain, 6 years ago

1) Introduce the libsemaphore library.
2) Introduce a small libmath library, required by the "fft" application..
3) Introduce the multithreaded "fft" application.
4) Fix a bad synchronisation bug in the Copy-On-Write mechanism.

File size: 9.0 KB
Line 
1/*
2 * remote_sem.c - Kernel function implementing the semaphore related syscalls.
3 *
4 * Author   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_kernel_types.h>
25#include <hal_remote.h>
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///////////////////////////////////////////////
35xptr_t remote_sem_from_vaddr( intptr_t  vaddr )
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 = GET_PTR( ref_xp );
46
47    // get extended pointer on root of semaphores list
48    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->sem_root );
49   
50    // scan reference process semaphores list
51    xptr_t         iter_xp;
52    xptr_t         sem_xp;
53    cxy_t          sem_cxy;
54    remote_sem_t * sem_ptr;
55    intptr_t       ident;
56    bool_t         found = false;
57           
58    XLIST_FOREACH( root_xp , iter_xp )
59    {
60        sem_xp  = XLIST_ELEMENT( iter_xp , remote_sem_t , list );
61        sem_cxy = GET_CXY( sem_xp );
62        sem_ptr = GET_PTR( sem_xp );
63        ident   = (intptr_t)hal_remote_lpt( XPTR( sem_cxy , &sem_ptr->ident ) );   
64
65        if( ident == vaddr )
66        {
67            found = true;
68            break;
69        }
70    }
71
72    if( found == false )  return XPTR_NULL;
73    else                  return sem_xp;
74
75}  // end remote_sem_from_vaddr()
76
77///////////////////////////////////////////
78error_t remote_sem_create( intptr_t   vaddr,
79                           uint32_t   value,
80                           xptr_t     sem_xp_xp )
81{
82    remote_sem_t * sem_ptr;
83    xptr_t         sem_xp;
84
85    // get pointer on local process descriptor
86    process_t * process = CURRENT_THREAD->process;
87
88    // get extended pointer on reference process
89    xptr_t      ref_xp = process->ref_xp;
90
91    // get reference process cluster and local pointer
92    cxy_t       ref_cxy = GET_CXY( ref_xp );
93    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
94
95    // allocate memory for new semaphore in reference cluster
96    if( ref_cxy == local_cxy )  // local cluster is the reference
97    {
98        kmem_req_t req;   
99        req.type  = KMEM_SEM;
100        req.flags = AF_ZERO;
101        sem_ptr   = kmem_alloc( &req );
102        sem_xp    = XPTR( local_cxy , sem_ptr );
103    }
104    else                         // reference is remote
105    {
106        rpc_kcm_alloc_client( ref_cxy , KMEM_SEM , &sem_xp );
107        sem_ptr = GET_PTR( sem_xp );
108    }
109
110    if( sem_xp == XPTR_NULL ) return -1;
111
112    // initialise semaphore
113    hal_remote_sw ( XPTR( ref_cxy , &sem_ptr->count ) , value );
114        hal_remote_spt( XPTR( ref_cxy , &sem_ptr->ident ) , (void *)vaddr );
115    remote_spinlock_init( XPTR( ref_cxy , &sem_ptr->lock ) );
116        xlist_root_init( XPTR( ref_cxy , &sem_ptr->root ) );
117        xlist_entry_init( XPTR( ref_cxy , &sem_ptr->list ) );
118
119    // register semaphore in reference process xlist
120    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->sem_root );
121    xptr_t xp_list = XPTR( ref_cxy , &sem_ptr->list );
122    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
123    xlist_add_first( root_xp , xp_list );
124    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
125
126    // write extended pointer on semaphore in calling thread buffer
127    hal_remote_swd( sem_xp_xp , sem_xp );
128
129    return 0;
130
131}  // en remote_sem_create()
132 
133////////////////////////////////////////
134void remote_sem_destroy( xptr_t sem_xp )
135{
136    // get pointer on local process descriptor
137    process_t * process = CURRENT_THREAD->process;
138
139    // get extended pointer on reference process
140    xptr_t      ref_xp = process->ref_xp;
141
142    // get reference process cluster and local pointer
143    cxy_t       ref_cxy = GET_CXY( ref_xp );
144    process_t * ref_ptr = GET_PTR( ref_xp );
145
146    // get semaphore cluster and local pointer
147    cxy_t          sem_cxy = GET_CXY( sem_xp );
148    remote_sem_t * sem_ptr = (remote_sem_t *)GET_PTR( sem_xp );
149
150    // get lock protecting semaphore
151    remote_spinlock_lock( XPTR( sem_cxy , &sem_ptr->lock ) );
152 
153    // get remote pointer on waiting queue root
154    xptr_t root_xp = XPTR( sem_cxy , &sem_ptr->root );
155 
156    if( !xlist_is_empty( root_xp ) )   // user error
157    {
158        printk("WARNING in %s for thread %x in process %x : "
159               "destroy semaphore, but  waiting threads queue not empty\n", 
160               __FUNCTION__ , CURRENT_THREAD->trdid , CURRENT_THREAD->process->pid );
161    }
162
163    // reset semaphore count
164    hal_remote_sw( XPTR( sem_cxy , &sem_ptr->count ) , 0 );
165
166    // remove semaphore from reference process xlist
167    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
168    xlist_unlink( XPTR( sem_cxy , &sem_ptr->list ) );
169    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
170
171    // release lock
172    remote_spinlock_unlock( XPTR( sem_cxy , &sem_ptr->lock ) );
173
174    // release memory allocated for semaphore descriptor
175    if( sem_cxy == local_cxy )                            // reference is local
176    {
177        kmem_req_t  req;
178        req.type = KMEM_SEM;
179        req.ptr  = sem_ptr;
180        kmem_free( &req );
181    }
182    else                                                  // reference is remote
183    {
184        rpc_kcm_free_client( sem_cxy , sem_ptr , KMEM_SEM );
185    }
186
187}  // end remote_sem_destroy()
188
189/////////////////////////////////////
190void remote_sem_wait( xptr_t sem_xp )
191{ 
192    // get semaphore cluster and local pointer
193    cxy_t          sem_cxy = GET_CXY( sem_xp );
194    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
195
196    // get lock protecting semaphore     
197        remote_spinlock_lock( XPTR( sem_cxy , &sem_ptr->lock ) );
198 
199    // get semaphore current value
200    uint32_t count = hal_remote_lw( XPTR( sem_cxy , &sem_ptr->count ) );
201
202        if( count > 0 )       // success
203        {
204        // decrement semaphore value
205        hal_remote_sw( XPTR( sem_cxy , &sem_ptr->count ) , count - 1 );
206
207        // release lock
208            remote_spinlock_unlock( XPTR( sem_cxy , &sem_ptr->lock ) );
209        }
210        else                 // failure
211        {
212        thread_t * this = CURRENT_THREAD;
213
214        // register thread in waiting queue
215        xptr_t root_xp = XPTR( sem_cxy   , &sem_ptr->root );
216        xptr_t list_xp = XPTR( local_cxy , &this->wait_list );
217                xlist_add_last( root_xp , list_xp );
218
219        // release lock
220            remote_spinlock_unlock( XPTR( sem_cxy , &sem_ptr->lock ) );
221
222        // block and deschedule
223        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_SEM ); 
224        sched_yield("blocked on semaphore");
225        }
226}  // end remote_sem_wait()
227
228/////////////////////////////////////
229void remote_sem_post( xptr_t sem_xp )
230{
231    // get semaphore cluster and local pointer
232    cxy_t          sem_cxy = GET_CXY( sem_xp );
233    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
234
235    // get lock protecting semaphore
236        remote_spinlock_lock( XPTR( sem_cxy , &sem_ptr->lock ) );
237 
238    // get semaphore current value
239    uint32_t count = hal_remote_lw( XPTR( sem_cxy , &sem_ptr->count ) );
240
241    // get remote pointer on waiting queue root
242    xptr_t root_xp = XPTR( sem_cxy , &sem_ptr->root );
243 
244        if( xlist_is_empty( root_xp ) )   // no waiting thread
245    {
246        // increment semaphore value
247        hal_remote_sw( XPTR( sem_cxy , &sem_ptr->count ) , count + 1 );
248    }
249    else
250    {
251        // get first waiting thread from queue
252        xptr_t thread_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
253
254        // get thread cluster and local poiner
255        cxy_t      thread_cxy = GET_CXY( thread_xp );
256        thread_t * thread_ptr = GET_PTR( thread_xp );
257
258        // remove this thread from the waiting queue, and unblock it
259        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_list ) );
260                thread_unblock( thread_xp , THREAD_BLOCKED_SEM );
261    }
262
263    // release lock
264        remote_spinlock_unlock( XPTR( sem_cxy , &sem_ptr->lock ) );
265
266}  // end remote_sem_post()
267
268
269//////////////////////////////////////////////
270void remote_sem_get_value( xptr_t      sem_xp,
271                           uint32_t  * data )
272{
273    // get semaphore cluster and local pointer
274    cxy_t          sem_cxy = GET_CXY( sem_xp );
275    remote_sem_t * sem_ptr = GET_PTR( sem_xp );
276
277    *data = hal_remote_lw( XPTR( sem_cxy , &sem_ptr->count ) );
278
279}  // end remote_sem_get_value()
280
281
Note: See TracBrowser for help on using the repository browser.