source: trunk/kernel/libk/remote_barrier.c @ 27

Last change on this file since 27 was 23, checked in by alain, 8 years ago

Introduce syscalls.

File size: 9.7 KB
Line 
1/*
2 * remote_barrier.c - Access a POSIX barrier.
3 *
4 * Author   Alain Greiner (2016,2017)
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_irqmask.h>
27#include <remote_spinlock.h>
28#include <thread.h>
29#include <kmem.h>
30#include <printk.h>
31#include <process.h>
32#include <vmm.h>
33#include <remote_barrier.h>
34
35/////////////////////////////////////////////////
36inline void remote_barrier( xptr_t    barrier_xp,
37                            uint32_t  count ) 
38{
39    uint32_t  expected;
40
41    remote_barrier_t * ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
42    cxy_t              cxy = GET_CXY( barrier_xp );
43
44    // get barrier sense value
45    uint32_t sense = hal_remote_lw( XPTR( cxy , &ptr->sense ) );
46
47        // compute expected value
48    if ( sense == 0 ) expected = 1;
49    else              expected = 0;
50
51    // atomically increment current
52    uint32_t current = hal_remote_atomic_add( XPTR( cxy , &ptr->current ) , 1 );
53
54    // last task reset current and toggle sense
55    if( current == (count-1) ) 
56    {
57        hal_remote_sw( XPTR( cxy , &ptr->current) , 0 ); 
58        hal_remote_sw( XPTR( cxy , &ptr->sense  ) , expected ); 
59    }
60    else   // other tasks poll the sense
61    {
62        while( hal_remote_lw( XPTR( cxy , &ptr->sense ) ) != expected ) asm volatile ("nop");
63    }
64}
65
66///////////////////////////////////////////////////
67xptr_t remote_barrier_from_ident( intptr_t  ident )
68{
69    // get pointer on local process_descriptor
70    process_t * process = CURRENT_THREAD->process;
71
72    // get extended pointer on reference process
73    xptr_t      ref_xp = process->ref_xp;
74
75    // get cluster and local pointer on reference process
76    cxy_t          ref_cxy = GET_CXY( ref_xp );
77    process_t    * ref_ptr = (process_t *)GET_PTR( ref_xp );
78
79    // get extended pointer on root of barriers list
80    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->barrier_root );
81   
82    // scan reference process barriers list
83    xptr_t             iter_xp;
84    xptr_t             barrier_xp;
85    cxy_t              barrier_cxy;
86    remote_barrier_t * barrier_ptr;
87    intptr_t           current;
88    bool_t             found = false;
89           
90    XLIST_FOREACH( root_xp , iter_xp )
91    {
92        barrier_xp  = XLIST_ELEMENT( iter_xp , remote_barrier_t , list );
93        barrier_cxy = GET_CXY( barrier_xp );
94        barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
95        current     = (intptr_t)hal_remote_lpt( XPTR( barrier_cxy , &barrier_ptr->ident ) );   
96        if( ident == current )
97        {
98            found = true;
99            break;
100        }
101    }
102
103    if( found == false )  return XPTR_NULL;
104    else                  return barrier_xp;
105
106}  // end remote_barrier_from_ident()
107
108//////////////////////////////////////////////
109error_t remote_barrier_create( intptr_t ident,
110                               uint32_t count )
111{
112    xptr_t             barrier_xp;
113    remote_barrier_t * barrier_ptr;
114
115    // get pointer on local process descriptor
116    process_t * process = CURRENT_THREAD->process;
117
118    // get extended pointer on reference process
119    xptr_t      ref_xp = process->ref_xp;
120
121    // get reference process cluster and local pointer
122    cxy_t       ref_cxy = GET_CXY( ref_xp );
123    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
124
125    // allocate memory for barrier descriptor
126    if( ref_cxy == local_cxy )                  // local cluster is the reference
127    {
128        kmem_req_t req;   
129        req.type      = KMEM_BARRIER;
130        req.flags     = AF_ZERO;
131        barrier_ptr   = kmem_alloc( &req );
132        barrier_xp    = XPTR( local_cxy , barrier_ptr );
133    }
134    else                                       // reference is remote
135    {
136        rpc_kcm_alloc_client( ref_cxy , KMEM_BARRIER , &barrier_xp );
137        barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
138    }
139
140    if( barrier_ptr == NULL ) return ENOMEM;
141
142    // initialise barrier
143    hal_remote_sw ( XPTR( ref_cxy , &barrier_ptr->nb_threads ) , count );
144    hal_remote_sw ( XPTR( ref_cxy , &barrier_ptr->current    ) , 0 );
145    hal_remote_sw ( XPTR( ref_cxy , &barrier_ptr->sense      ) , 0 );
146    hal_remote_spt( XPTR( ref_cxy , &barrier_ptr->ident      ) , (void*)ident );
147
148    xlist_entry_init( XPTR( ref_cxy , &barrier_ptr->list ) );
149
150    // register  barrier in reference process xlist
151    xptr_t root_xp  = XPTR( ref_cxy , &ref_ptr->barrier_root );
152    xptr_t entry_xp = XPTR( ref_cxy , &barrier_ptr->list );
153
154    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
155    xlist_add_first( root_xp , entry_xp );
156    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
157
158    return 0;
159
160}  // end remote_barrier_create()
161
162////////////////////////////////////////////////
163void remote_barrier_destroy( xptr_t barrier_xp )
164{
165    // get pointer on local process descriptor
166    process_t * process = CURRENT_THREAD->process;
167
168    // get extended pointer on reference process
169    xptr_t      ref_xp = process->ref_xp;
170
171    // get reference process cluster and local pointer
172    cxy_t       ref_cxy = GET_CXY( ref_xp );
173    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
174
175    // get barrier cluster and local pointer
176    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
177    remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
178
179    // remove barrier from reference process xlist
180    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
181    xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
182    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
183
184    // release memory allocated for barrier descriptor
185    if( barrier_cxy == local_cxy )                        // reference is local
186    {
187        kmem_req_t  req;
188        req.type = KMEM_BARRIER;
189        req.ptr  = barrier_ptr;
190        kmem_free( &req );
191    }
192    else                                                  // reference is remote
193    {
194        rpc_kcm_free_client( barrier_cxy , barrier_ptr , KMEM_BARRIER );
195    }
196
197}  // end remote_barrier_destroy()
198
199/////////////////////////////////////////////
200void remote_barrier_wait( xptr_t barrier_xp )
201{
202    uint32_t  expected;
203    uint32_t  current;
204    uint32_t  count;
205    uint32_t  sense;
206    uint32_t  irq_state;
207    xptr_t    root_xp;
208
209    // get cluster and local pointer on calling thread
210    cxy_t              thread_cxy = local_cxy;
211    thread_t         * thread_ptr = CURRENT_THREAD;
212
213    // get cluster and local pointer on remote barrier
214    remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
215    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
216
217    // get count and root fields from barrier descriptor
218    count   = hal_remote_lw ( XPTR( barrier_cxy , &barrier_ptr->nb_threads ) );
219    root_xp = hal_remote_lwd( XPTR( barrier_cxy , &barrier_ptr->root ) );
220
221    // get barrier sense value
222    sense = hal_remote_lw( XPTR( barrier_cxy , &barrier_ptr->sense ) );
223
224        // compute expected value
225    if ( sense == 0 ) expected = 1;
226    else              expected = 0;
227
228    // atomically increment current
229    current = hal_remote_atomic_add( XPTR( barrier_cxy , &barrier_ptr->current ) , 1 );
230
231    // last thread reset current, toggle sense, and activate all waiting threads
232    // other threads block, register in queue, and deschedule
233
234    if( current == (count-1) )                       // last thread
235    {
236        hal_remote_sw( XPTR( barrier_cxy , &barrier_ptr->current) , 0 ); 
237        hal_remote_sw( XPTR( barrier_cxy , &barrier_ptr->sense  ) , expected ); 
238
239        // activate waiting threads if required
240        if( xlist_is_empty( root_xp ) == false ) 
241        {
242            // disable interrupts
243                hal_disable_irq( &irq_state );
244 
245            xptr_t  iter_xp;
246            xptr_t  thread_xp;
247            XLIST_FOREACH( root_xp , iter_xp )
248            {
249                // get extended pointer on waiting thread
250                thread_xp = XLIST_ELEMENT( iter_xp , thread_t , wait_list );
251       
252                // remove waiting thread from queue
253                remote_spinlock_lock( XPTR( barrier_cxy , &barrier_ptr->lock ) );
254                xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
255                remote_spinlock_unlock( XPTR( barrier_cxy , &barrier_ptr->lock ) );
256
257                // unblock waiting thread
258                thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC ); 
259            }
260
261            // restore interrupts
262            hal_restore_irq( irq_state );
263        }
264    }
265    else                                             // not the last thread 
266    {
267        // disable interrupts
268            hal_disable_irq( &irq_state );
269 
270        // register calling thread in barrier waiting queue
271        xptr_t entry_xp = XPTR( thread_cxy , &thread_ptr->wait_list );
272
273        remote_spinlock_lock( XPTR( barrier_cxy , &barrier_ptr->lock ) ); 
274        xlist_add_last( root_xp , entry_xp );
275        remote_spinlock_unlock( XPTR( barrier_cxy , &barrier_ptr->lock ) ); 
276
277        // block & deschedule the calling thread   
278        thread_block( thread_ptr , THREAD_BLOCKED_USERSYNC );
279        sched_yield();
280
281        // restore interrupts
282        hal_restore_irq( irq_state );
283    }
284}  // end remote_barrier_wait()
Note: See TracBrowser for help on using the repository browser.