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

Last change on this file since 576 was 563, checked in by alain, 6 years ago

Complete restructuration of kernel spinlocks.

File size: 8.8 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
85    process_t * process = CURRENT_THREAD->process;
86
87    // get extended pointer on reference process
88    xptr_t      ref_xp = process->ref_xp;
89
90    // get reference process cluster and local pointer
91    cxy_t       ref_cxy = GET_CXY( ref_xp );
[563]92    process_t * ref_ptr = GET_PTR( ref_xp );
[23]93
94    // allocate memory for barrier descriptor
[104]95    if( ref_cxy == local_cxy )                  // local cluster is the reference
[23]96    {
[104]97        kmem_req_t req;
[23]98        req.type      = KMEM_BARRIER;
99        req.flags     = AF_ZERO;
100        barrier_ptr   = kmem_alloc( &req );
101        barrier_xp    = XPTR( local_cxy , barrier_ptr );
102    }
103    else                                       // reference is remote
104    {
105        rpc_kcm_alloc_client( ref_cxy , KMEM_BARRIER , &barrier_xp );
106        barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
107    }
108
109    if( barrier_ptr == NULL ) return ENOMEM;
110
[104]111    // initialise barrier
[563]112    hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->nb_threads ) , count );
113    hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->current    ) , 0 );
114    hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->sense      ) , 0 );
[23]115    hal_remote_spt( XPTR( ref_cxy , &barrier_ptr->ident      ) , (void*)ident );
116
117    xlist_entry_init( XPTR( ref_cxy , &barrier_ptr->list ) );
118
119    // register  barrier in reference process xlist
120    xptr_t root_xp  = XPTR( ref_cxy , &ref_ptr->barrier_root );
121    xptr_t entry_xp = XPTR( ref_cxy , &barrier_ptr->list );
122
[563]123    remote_busylock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]124    xlist_add_first( root_xp , entry_xp );
[563]125    remote_busylock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]126
127    return 0;
[104]128}
[23]129
130////////////////////////////////////////////////
131void remote_barrier_destroy( xptr_t barrier_xp )
132{
133    // get pointer on local process descriptor
134    process_t * process = CURRENT_THREAD->process;
135
136    // get extended pointer on reference process
137    xptr_t      ref_xp = process->ref_xp;
138
139    // get reference process cluster and local pointer
140    cxy_t       ref_cxy = GET_CXY( ref_xp );
141    process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
142
143    // get barrier cluster and local pointer
144    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
145    remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
146
147    // remove barrier from reference process xlist
[563]148    remote_busylock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]149    xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
[563]150    remote_busylock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]151
152    // release memory allocated for barrier descriptor
153    if( barrier_cxy == local_cxy )                        // reference is local
154    {
155        kmem_req_t  req;
156        req.type = KMEM_BARRIER;
157        req.ptr  = barrier_ptr;
158        kmem_free( &req );
159    }
160    else                                                  // reference is remote
161    {
162        rpc_kcm_free_client( barrier_cxy , barrier_ptr , KMEM_BARRIER );
163    }
[104]164}
[23]165
166/////////////////////////////////////////////
167void remote_barrier_wait( xptr_t barrier_xp )
168{
169    uint32_t  expected;
170    uint32_t  current;
171    uint32_t  count;
172    uint32_t  sense;
[60]173    reg_t     irq_state;
[23]174    xptr_t    root_xp;
175
176    // get cluster and local pointer on calling thread
177    cxy_t              thread_cxy = local_cxy;
178    thread_t         * thread_ptr = CURRENT_THREAD;
179
[563]180// check calling thread can yield
181assert( (thread_ptr->busylocks == 0),
182"cannot yield : busylocks = %d\n", thread_ptr->busylocks );
183
[23]184    // get cluster and local pointer on remote barrier
185    remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
186    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
187
188    // get count and root fields from barrier descriptor
[563]189    count   = hal_remote_l32 ( XPTR( barrier_cxy , &barrier_ptr->nb_threads ) );
190    root_xp = hal_remote_l64( XPTR( barrier_cxy , &barrier_ptr->root ) );
[23]191
192    // get barrier sense value
[563]193    sense = hal_remote_l32( XPTR( barrier_cxy , &barrier_ptr->sense ) );
[23]194
[104]195    // compute expected value
[23]196    if ( sense == 0 ) expected = 1;
197    else              expected = 0;
198
[104]199    // atomically increment current
[23]200    current = hal_remote_atomic_add( XPTR( barrier_cxy , &barrier_ptr->current ) , 1 );
201
202    // last thread reset current, toggle sense, and activate all waiting threads
[104]203    // other threads block, register in queue, and deschedule
[23]204
205    if( current == (count-1) )                       // last thread
206    {
[563]207        hal_remote_s32( XPTR( barrier_cxy , &barrier_ptr->current) , 0 );
208        hal_remote_s32( XPTR( barrier_cxy , &barrier_ptr->sense  ) , expected );
[23]209
210        // activate waiting threads if required
[104]211        if( xlist_is_empty( root_xp ) == false )
[23]212        {
213            // disable interrupts
[104]214            hal_disable_irq( &irq_state );
215
[23]216            xptr_t  iter_xp;
217            xptr_t  thread_xp;
218            XLIST_FOREACH( root_xp , iter_xp )
219            {
220                // get extended pointer on waiting thread
221                thread_xp = XLIST_ELEMENT( iter_xp , thread_t , wait_list );
[104]222
[23]223                // remove waiting thread from queue
[563]224                remote_busylock_acquire( XPTR( barrier_cxy , &barrier_ptr->lock ) );
[23]225                xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
[563]226                remote_busylock_release( XPTR( barrier_cxy , &barrier_ptr->lock ) );
[23]227
228                // unblock waiting thread
[104]229                thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
[23]230            }
231
232            // restore interrupts
233            hal_restore_irq( irq_state );
234        }
235    }
[104]236    else                                             // not the last thread
[23]237    {
238        // disable interrupts
[104]239        hal_disable_irq( &irq_state );
240
[23]241        // register calling thread in barrier waiting queue
242        xptr_t entry_xp = XPTR( thread_cxy , &thread_ptr->wait_list );
243
[563]244        remote_busylock_acquire( XPTR( barrier_cxy , &barrier_ptr->lock ) );
[23]245        xlist_add_last( root_xp , entry_xp );
[563]246        remote_busylock_release( XPTR( barrier_cxy , &barrier_ptr->lock ) );
[23]247
[104]248        // block & deschedule the calling thread
[436]249        thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_USERSYNC );
[408]250        sched_yield("blocked on barrier");
[23]251
252        // restore interrupts
253        hal_restore_irq( irq_state );
254    }
[104]255}
Note: See TracBrowser for help on using the repository browser.