source: trunk/kernel/libk/remote_condvar.c @ 593

Last change on this file since 593 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: 8.9 KB
RevLine 
[23]1/*
[563]2 * remote_condvar.c - remote kernel condition variable implementation.
[23]3 *
[563]4 * Authors     Alain Greiner (2016,2017,2018)
5 *
[23]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
[563]24#include <kernel_config.h>
[457]25#include <hal_kernel_types.h>
[23]26#include <thread.h>
[563]27#include <scheduler.h>
[23]28#include <xlist.h>
29#include <remote_mutex.h>
[563]30#include <remote_busylock.h>
[23]31#include <remote_condvar.h>
32
[563]33
[23]34///////////////////////////////////////////////////
35xptr_t remote_condvar_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 );
[563]45    process_t    * ref_ptr = GET_PTR( ref_xp );
[23]46
[563]47    // get extended pointer on condvars list
[23]48    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->condvar_root );
[563]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 condvar list
[23]55    xptr_t             iter_xp;
56    xptr_t             condvar_xp;
57    cxy_t              condvar_cxy;
[563]58    remote_condvar_t * condvar_ptr;
[23]59    intptr_t           current;
60    bool_t             found = false;
61           
62    XLIST_FOREACH( root_xp , iter_xp )
63    {
64        condvar_xp  = XLIST_ELEMENT( iter_xp , remote_condvar_t , list );
65        condvar_cxy = GET_CXY( condvar_xp );
[563]66        condvar_ptr = GET_PTR( condvar_xp );
67        current = (intptr_t)hal_remote_lpt( XPTR( condvar_cxy , &condvar_ptr->ident ) );   
68
69        if( current == ident )
[23]70        {
71            found = true;
72            break;
73        }
74    }
75
[563]76    // relese lock protecting synchros lists
77    remote_queuelock_release( lock_xp );
78 
[23]79    if( found == false )  return XPTR_NULL;
80    else                  return condvar_xp;
81
82}  // end remote_condvar_from_ident()
83
[563]84/////////////////////////////////////////////////
85error_t remote_condvar_create( intptr_t   ident )
[23]86{
[563]87    remote_condvar_t * condvar_ptr;
[23]88    xptr_t             condvar_xp;
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
[563]100    // allocate memory for new condvar in reference cluster
101    if( ref_cxy == local_cxy )                              // local cluster is the reference
[23]102    {
103        kmem_req_t req;   
[563]104        req.type    = KMEM_CONDVAR;
105        req.flags   = AF_ZERO;
106        condvar_ptr = kmem_alloc( &req );
107        condvar_xp  = XPTR( local_cxy , condvar_ptr );
[23]108    }
[563]109    else                                                   // reference cluster is remote
[23]110    {
111        rpc_kcm_alloc_client( ref_cxy , KMEM_CONDVAR , &condvar_xp );
[563]112        condvar_ptr = GET_PTR( condvar_xp );
[23]113    }
114
[563]115    if( condvar_xp == XPTR_NULL ) return 0xFFFFFFFF;
[23]116
117    // initialise condvar
[563]118        hal_remote_spt( XPTR( ref_cxy , &condvar_ptr->ident ) , (void *)ident );
119        xlist_root_init( XPTR( ref_cxy , &condvar_ptr->root ) );
120        xlist_entry_init( XPTR( ref_cxy , &condvar_ptr->list ) );
121    remote_busylock_init( XPTR( ref_cxy , &condvar_ptr->lock ), LOCK_CONDVAR_STATE );
[23]122
[563]123    // register condvar in reference process xlist
[23]124    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->condvar_root );
[563]125    xptr_t list_xp = XPTR( ref_cxy , &condvar_ptr->list );
[23]126
[563]127    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
128    xlist_add_first( root_xp , list_xp );
129    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]130
131    return 0;
132
133}  // end remote_condvar_create()
134
135////////////////////////////////////////////////
136void remote_condvar_destroy( xptr_t condvar_xp )
137{
138    // get pointer on local process descriptor
139    process_t * process = CURRENT_THREAD->process;
140
141    // get extended pointer on reference process
142    xptr_t      ref_xp = process->ref_xp;
143
144    // get reference process cluster and local pointer
145    cxy_t       ref_cxy = GET_CXY( ref_xp );
[563]146    process_t * ref_ptr = GET_PTR( ref_xp );
[23]147
148    // get condvar cluster and local pointer
149    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
[563]150    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
[23]151
[563]152    // get remote pointer on waiting queue root
153    xptr_t root_xp = XPTR( condvar_cxy , &condvar_ptr->root );
154 
155    if( !xlist_is_empty( root_xp ) )   // user error
156    {
157        printk("WARNING in %s for thread %x in process %x : "
158               "destroy condvar, but  waiting threads queue not empty\n", 
159               __FUNCTION__ , CURRENT_THREAD->trdid , CURRENT_THREAD->process->pid );
160    }
161
[23]162    // remove condvar from reference process xlist
[563]163    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]164    xlist_unlink( XPTR( condvar_cxy , &condvar_ptr->list ) );
[563]165    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
[23]166
[563]167    // release memory allocated for condvar descriptor
[23]168    if( condvar_cxy == local_cxy )                            // reference is local
169    {
170        kmem_req_t  req;
[563]171        req.type = KMEM_SEM;
[23]172        req.ptr  = condvar_ptr;
173        kmem_free( &req );
174    }
175    else                                                  // reference is remote
176    {
[563]177        rpc_kcm_free_client( condvar_cxy , condvar_ptr , KMEM_CONDVAR );
[23]178    }
179
[563]180}  // end remote_convar_destroy()
[23]181
182////////////////////////////////////////////
183void remote_condvar_wait( xptr_t condvar_xp,
184                          xptr_t mutex_xp )
185{
[563]186    thread_t * this = CURRENT_THREAD;
[23]187
[581]188    // check calling thread can yield
189    thread_assert_can_yield( this , __FUNCTION__ );
[23]190
[563]191    // get condvar cluster and local pointer
192    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
[23]193    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
194
[563]195    // register the calling thread in condvar waiting queue
196    xlist_add_last( XPTR( condvar_cxy , &condvar_ptr->root ),
197                    XPTR( local_cxy   , &this->wait_xlist ) );
[23]198
[563]199    // block the calling thread
200    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_USERSYNC );
[23]201
[563]202    // release the mutex
203    remote_mutex_unlock( mutex_xp );
[23]204
[563]205    // deschedule
[408]206    sched_yield("blocked on condvar");
[23]207
[563]208    // re-acquire the mutex
209    remote_mutex_lock( mutex_xp );
[23]210
211}  // end remote_condvar_wait()
212
213///////////////////////////////////////////////
214void remote_condvar_signal( xptr_t condvar_xp )
215{
[563]216    // get condvar cluster and local pointer
217    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
[23]218    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
219
[563]220    // does nothing if waiting queue empty
221    if( xlist_is_empty( XPTR( condvar_cxy, &condvar_ptr->root ) ) == false )
222    {
223         // get first waiting thread
224         xptr_t thread_xp = XLIST_FIRST( XPTR( condvar_cxy , &condvar_ptr->root ),
225                                         thread_t , wait_xlist );
[23]226
[563]227         // remove this waiting thread from queue
228         thread_t * thread_ptr = GET_PTR( thread_xp );
229         cxy_t      thread_cxy = GET_CXY( thread_xp );
230         xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[23]231
[563]232         // unblock this waiting thread
233         thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
234    }
[23]235
236}  // end remote_condvar_signal()
237
238//////////////////////////////////////////////////
239void remote_condvar_broadcast( xptr_t condvar_xp )
240{
[563]241    // get condvar cluster and local pointer
242    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
[23]243    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
244
[563]245    // does nothing if waiting queue empty
246    while( xlist_is_empty( XPTR( condvar_cxy , &condvar_ptr->root ) ) == false )
247    {
248         // get first waiting thread
249         xptr_t thread_xp = XLIST_FIRST( XPTR( condvar_cxy , &condvar_ptr->root ),
250                                         thread_t , wait_xlist );
[23]251
[563]252         // remove this waiting thread from queue
253         thread_t * thread_ptr = GET_PTR( thread_xp );
254         cxy_t      thread_cxy = GET_CXY( thread_xp );
255         xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
[23]256
[563]257         // unblock this waiting thread
258         thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
[23]259    }
[563]260}  // end remote_condvar_broadcast()
[23]261
Note: See TracBrowser for help on using the repository browser.