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

Last change on this file since 590 was 581, checked in by alain, 6 years ago

1) Improve the busylock debug infrastructure.
2) introduce a non-distributed, but portable implementation for the pthread_barrier.

File size: 10.5 KB
RevLine 
[1]1/*
[563]2 * remote_barrier.c -  POSIX barrier implementation.
[104]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>
[1]25#include <hal_remote.h>
[23]26#include <hal_irqmask.h>
[563]27#include <remote_busylock.h>
[23]28#include <thread.h>
29#include <kmem.h>
30#include <printk.h>
31#include <process.h>
32#include <vmm.h>
[1]33#include <remote_barrier.h>
34
35
[23]36///////////////////////////////////////////////////
37xptr_t remote_barrier_from_ident( intptr_t  ident )
38{
39    // get pointer on local process_descriptor
40    process_t * process = CURRENT_THREAD->process;
[1]41
[23]42    // get extended pointer on reference process
43    xptr_t      ref_xp = process->ref_xp;
44
[104]45    // get cluster and local pointer on reference process
[23]46    cxy_t          ref_cxy = GET_CXY( ref_xp );
47    process_t    * ref_ptr = (process_t *)GET_PTR( ref_xp );
48
[104]49    // get extended pointer on root of barriers list
[23]50    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->barrier_root );
[104]51
[23]52    // scan reference process barriers list
53    xptr_t             iter_xp;
54    xptr_t             barrier_xp;
55    cxy_t              barrier_cxy;
56    remote_barrier_t * barrier_ptr;
57    intptr_t           current;
58    bool_t             found = false;
[104]59
[23]60    XLIST_FOREACH( root_xp , iter_xp )
61    {
62        barrier_xp  = XLIST_ELEMENT( iter_xp , remote_barrier_t , list );
63        barrier_cxy = GET_CXY( barrier_xp );
64        barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
[104]65        current     = (intptr_t)hal_remote_lpt( XPTR( barrier_cxy , &barrier_ptr->ident ) );
[23]66        if( ident == current )
67        {
68            found = true;
69            break;
70        }
71    }
72
73    if( found == false )  return XPTR_NULL;
74    else                  return barrier_xp;
[104]75}
[23]76
77//////////////////////////////////////////////
78error_t remote_barrier_create( intptr_t ident,
79                               uint32_t count )
80{
81    xptr_t             barrier_xp;
82    remote_barrier_t * barrier_ptr;
83
84    // get pointer on local process descriptor
[581]85    thread_t  * this    = CURRENT_THREAD;
86    process_t * process = this->process;
[23]87
[581]88#if DEBUG_BARRIER
89uint32_t cycle = (uint32_t)hal_get_cycles();
90if( cycle > DEBUG_BARRIER )
91printk("\n[DBG] %s : thread %x in process %x enter / count %d / cycle %d\n",
92__FUNCTION__, this->trdid, process->pid, count, cycle );
93#endif
94
[23]95    // get extended pointer on reference process
96    xptr_t      ref_xp = process->ref_xp;
97
98    // get reference process cluster and local pointer
99    cxy_t       ref_cxy = GET_CXY( ref_xp );
[563]100    process_t * ref_ptr = GET_PTR( ref_xp );
[23]101
102    // allocate memory for barrier descriptor
[104]103    if( ref_cxy == local_cxy )                  // local cluster is the reference
[23]104    {
[104]105        kmem_req_t req;
[23]106        req.type      = KMEM_BARRIER;
107        req.flags     = AF_ZERO;
108        barrier_ptr   = kmem_alloc( &req );
109        barrier_xp    = XPTR( local_cxy , barrier_ptr );
110    }
111    else                                       // reference is remote
112    {
113        rpc_kcm_alloc_client( ref_cxy , KMEM_BARRIER , &barrier_xp );
114        barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
115    }
116
117    if( barrier_ptr == NULL ) return ENOMEM;
118
[104]119    // initialise barrier
[581]120    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->nb_threads ) , count );
121    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->current    ) , 0 );
122    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->sense      ) , 0 );
[23]123    hal_remote_spt( XPTR( ref_cxy , &barrier_ptr->ident      ) , (void*)ident );
124
[581]125    xlist_root_init( XPTR( ref_cxy , &barrier_ptr->root ) );
[23]126
127    // register  barrier in reference process xlist
128    xptr_t root_xp  = XPTR( ref_cxy , &ref_ptr->barrier_root );
129    xptr_t entry_xp = XPTR( ref_cxy , &barrier_ptr->list );
130
[563]131    remote_busylock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]132    xlist_add_first( root_xp , entry_xp );
[563]133    remote_busylock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]134
[581]135#if DEBUG_BARRIER
136cycle = (uint32_t)hal_get_cycles();
137if( cycle > DEBUG_BARRIER )
138printk("\n[DBG] %s : thread %x in process %x exit / barrier %x in cluster %x / cycle %d\n",
139__FUNCTION__, this->trdid, process->pid, barrier_ptr, ref_cxy, cycle );
140#endif
141
[23]142    return 0;
143
[581]144}  // end remote_barrier_create()
145
[23]146////////////////////////////////////////////////
147void remote_barrier_destroy( xptr_t barrier_xp )
148{
149    // get pointer on local process descriptor
150    process_t * process = CURRENT_THREAD->process;
151
152    // get extended pointer on reference process
153    xptr_t      ref_xp = process->ref_xp;
154
155    // get reference process cluster and local pointer
156    cxy_t       ref_cxy = GET_CXY( ref_xp );
157    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
158
159    // get barrier cluster and local pointer
160    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
161    remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
162
163    // remove barrier from reference process xlist
[563]164    remote_busylock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]165    xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
[563]166    remote_busylock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]167
168    // release memory allocated for barrier descriptor
169    if( barrier_cxy == local_cxy )                        // reference is local
170    {
171        kmem_req_t  req;
172        req.type = KMEM_BARRIER;
173        req.ptr  = barrier_ptr;
174        kmem_free( &req );
175    }
176    else                                                  // reference is remote
177    {
178        rpc_kcm_free_client( barrier_cxy , barrier_ptr , KMEM_BARRIER );
179    }
[581]180}  // end remote_barrier_destroy()
[23]181
182/////////////////////////////////////////////
183void remote_barrier_wait( xptr_t barrier_xp )
184{
185    uint32_t  expected;
[581]186    uint32_t  sense;
[23]187    uint32_t  current;
[581]188    uint32_t  nb_threads;
[23]189    xptr_t    root_xp;
[581]190    xptr_t    lock_xp;
191    xptr_t    current_xp;
192    xptr_t    sense_xp;
193    xptr_t    nb_threads_xp;
[23]194
[581]195    // get pointer on calling thread
196    thread_t * this = CURRENT_THREAD;
[23]197
[581]198    // check calling thread can yield
199    thread_assert_can_yield( this , __FUNCTION__ );
[563]200
[23]201    // get cluster and local pointer on remote barrier
[581]202    remote_barrier_t * barrier_ptr = GET_PTR( barrier_xp );
[23]203    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
204
[581]205#if DEBUG_BARRIER
206uint32_t cycle = (uint32_t)hal_get_cycles();
207if( cycle > DEBUG_BARRIER )
208printk("\n[DBG] %s : thread %x in process %x enter / barrier %x in cluster %x / cycle %d\n",
209__FUNCTION__, this->trdid, this->process->pid, barrier_ptr, barrier_cxy, cycle );
210#endif
[23]211
[581]212    // compute extended pointers on various barrier fields
213    lock_xp       = XPTR( barrier_cxy , &barrier_ptr->lock );
214    root_xp       = XPTR( barrier_cxy , &barrier_ptr->root );
215    current_xp    = XPTR( barrier_cxy , &barrier_ptr->current );
216    sense_xp      = XPTR( barrier_cxy , &barrier_ptr->sense );
217    nb_threads_xp = XPTR( barrier_cxy , &barrier_ptr->nb_threads );
[23]218
[581]219    // take busylock protecting the remote_barrier
220    remote_busylock_acquire( lock_xp );
221
222#if (DEBUG_BARRIER & 1)
223cycle = (uint32_t)hal_get_cycles();
224if( cycle > DEBUG_BARRIER )
225printk("\n[DBG] %s : thread %x in process %x get lock / cycle %d\n",
226__FUNCTION__, this->trdid, this->process->pid, cycle );
227#endif
228
229    // get sense and nb_threads values from barrier descriptor
230    sense      = hal_remote_l32( sense_xp );
231    nb_threads = hal_remote_l32( nb_threads_xp );
232
[104]233    // compute expected value
[23]234    if ( sense == 0 ) expected = 1;
235    else              expected = 0;
236
[581]237#if (DEBUG_BARRIER & 1)
238cycle = (uint32_t)hal_get_cycles();
239if( cycle > DEBUG_BARRIER )
240printk("\n[DBG] %s : thread %x in process %x / count %d / sense %d / cycle %d\n",
241__FUNCTION__, this->trdid, this->process->pid, nb_threads, sense, cycle );
242#endif
[23]243
[581]244    // atomically increment current, and get value before increment
245    current = hal_remote_atomic_add( current_xp , 1 );
246
[23]247    // last thread reset current, toggle sense, and activate all waiting threads
[104]248    // other threads block, register in queue, and deschedule
[23]249
[581]250    if( current == (nb_threads-1) )                       // last thread
[23]251    {
[581]252        hal_remote_s32( current_xp , 0 );
253        hal_remote_s32( sense_xp , expected );
[23]254
[581]255        // unblock all waiting threads
256        while( xlist_is_empty( root_xp ) == false )
[23]257        {
[581]258            // get pointers on first waiting thread
259            xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_list );
260            cxy_t      thread_cxy = GET_CXY( thread_xp );
261            thread_t * thread_ptr = GET_PTR( thread_xp );
[104]262
[581]263#if (DEBUG_BARRIER & 1)
264cycle = (uint32_t)hal_get_cycles();
265if( cycle > DEBUG_BARRIER )
266printk("\n[DBG] %s : thread %x in process %x / unblock thread %x / cycle %d\n",
267__FUNCTION__, this->trdid, this->process->pid, thread_ptr, cycle );
268#endif
[104]269
[581]270            // remove waiting thread from queue
271            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_list ) );
[23]272
[581]273            // unblock waiting thread
274            thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
275        }
[23]276
[581]277        // release busylock protecting the remote_barrier
278        remote_busylock_release( lock_xp );
[23]279    }
[104]280    else                                             // not the last thread
[23]281    {
[104]282
[581]283#if (DEBUG_BARRIER & 1)
284cycle = (uint32_t)hal_get_cycles();
285if( cycle > DEBUG_BARRIER )
286printk("\n[DBG] %s : thread %x in process %x / blocked / cycle %d\n",
287__FUNCTION__, this->trdid, this->process->pid, cycle );
288#endif
289
[23]290        // register calling thread in barrier waiting queue
[581]291        xlist_add_last( root_xp , XPTR( local_cxy , &this->wait_list ) );
[23]292
[581]293        // block calling thread
294        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_USERSYNC );
[23]295
[581]296        // release busylock protecting the remote_barrier
297        remote_busylock_release( lock_xp );
298
299        // deschedule
[408]300        sched_yield("blocked on barrier");
[581]301    }
[23]302
[581]303#if DEBUG_BARRIER
304cycle = (uint32_t)hal_get_cycles();
305if( cycle > DEBUG_BARRIER )
306printk("\n[DBG] %s : thread %x in process %x exit / barrier %x in cluster %x / cycle %d\n",
307__FUNCTION__, this->trdid, this->process->pid, barrier_ptr, barrier_cxy, cycle );
308#endif
309
310}  // end remote_barrier_wait()
Note: See TracBrowser for help on using the repository browser.