source: trunk/kernel/kern/remote_sem.c @ 9

Last change on this file since 9 was 5, checked in by alain, 7 years ago

Introduce the chdev_t structure in place of the device_t structure.

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