source: trunk/kernel/libk/remote_sem.c

Last change on this file was 683, checked in by alain, 4 years ago

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

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