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

Last change on this file since 635 was 635, checked in by alain, 15 months ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File size: 8.3 KB
Line 
1/*
2 * remote_condvar.c - remote kernel condition variable implementation.
3 *
4 * Authors     Alain Greiner (2016,2017,2018,2019)
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 <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <thread.h>
27#include <scheduler.h>
28#include <xlist.h>
29#include <remote_mutex.h>
30#include <remote_busylock.h>
31#include <remote_condvar.h>
32
33
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 );
45    process_t    * ref_ptr = GET_PTR( ref_xp );
46
47    // get extended pointer on condvars list
48    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->condvar_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 condvar list
55    xptr_t             iter_xp;
56    xptr_t             condvar_xp;
57    cxy_t              condvar_cxy;
58    remote_condvar_t * condvar_ptr;
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 );
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 )
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 condvar_xp;
81
82}  // end remote_condvar_from_ident()
83
84/////////////////////////////////////////////////
85error_t remote_condvar_create( intptr_t   ident )
86{
87    remote_condvar_t * condvar_ptr;
88    kmem_req_t         req;   
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    req.type    = KMEM_KCM;
101    req.order   = bits_log2( sizeof(remote_condvar_t) );
102    req.flags   = AF_ZERO | AF_KERNEL;
103    condvar_ptr = kmem_alloc( &req );
104
105    if( condvar_ptr == NULL )
106    {
107        printk("\n[ERROR] in %s : cannot create condvar\n", __FUNCTION__ );
108        return -1;
109    }
110
111    // initialise condvar
112        hal_remote_spt( XPTR( ref_cxy , &condvar_ptr->ident ) , (void *)ident );
113        xlist_root_init( XPTR( ref_cxy , &condvar_ptr->root ) );
114        xlist_entry_init( XPTR( ref_cxy , &condvar_ptr->list ) );
115    remote_busylock_init( XPTR( ref_cxy , &condvar_ptr->lock ), LOCK_CONDVAR_STATE );
116
117    // register condvar in reference process xlist
118    xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->condvar_root );
119    xptr_t list_xp = XPTR( ref_cxy , &condvar_ptr->list );
120
121    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
122    xlist_add_first( root_xp , list_xp );
123    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
124
125    return 0;
126
127}  // end remote_condvar_create()
128
129////////////////////////////////////////////////
130void remote_condvar_destroy( xptr_t condvar_xp )
131{
132    kmem_req_t  req;
133
134    // get pointer on local process descriptor
135    process_t * process = CURRENT_THREAD->process;
136
137    // get extended pointer on reference process
138    xptr_t      ref_xp = process->ref_xp;
139
140    // get reference process cluster and local pointer
141    cxy_t       ref_cxy = GET_CXY( ref_xp );
142    process_t * ref_ptr = GET_PTR( ref_xp );
143
144    // get condvar cluster and local pointer
145    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
146    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
147
148    // get remote pointer on waiting queue root
149    xptr_t root_xp = XPTR( condvar_cxy , &condvar_ptr->root );
150 
151    if( !xlist_is_empty( root_xp ) )   // user error
152    {
153        printk("WARNING in %s for thread %x in process %x : "
154               "destroy condvar, but  waiting threads queue not empty\n", 
155               __FUNCTION__ , CURRENT_THREAD->trdid , CURRENT_THREAD->process->pid );
156    }
157
158    // remove condvar from reference process xlist
159    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
160    xlist_unlink( XPTR( condvar_cxy , &condvar_ptr->list ) );
161    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
162
163    // release memory allocated for condvar descriptor
164    req.type = KMEM_KCM;
165    req.ptr  = condvar_ptr;
166    kmem_remote_free( ref_cxy , &req );
167
168}  // end remote_convar_destroy()
169
170////////////////////////////////////////////
171void remote_condvar_wait( xptr_t condvar_xp,
172                          xptr_t mutex_xp )
173{
174    thread_t * this = CURRENT_THREAD;
175
176    // check calling thread can yield
177    thread_assert_can_yield( this , __FUNCTION__ );
178
179    // get condvar cluster and local pointer
180    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
181    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
182
183    // register the calling thread in condvar waiting queue
184    xlist_add_last( XPTR( condvar_cxy , &condvar_ptr->root ),
185                    XPTR( local_cxy   , &this->wait_xlist ) );
186
187    // block the calling thread
188    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_USERSYNC );
189
190    // release the mutex
191    remote_mutex_unlock( mutex_xp );
192
193    // deschedule
194    sched_yield("blocked on condvar");
195
196    // re-acquire the mutex
197    remote_mutex_lock( mutex_xp );
198
199}  // end remote_condvar_wait()
200
201///////////////////////////////////////////////
202void remote_condvar_signal( xptr_t condvar_xp )
203{
204    // get condvar cluster and local pointer
205    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
206    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
207
208    // does nothing if waiting queue empty
209    if( xlist_is_empty( XPTR( condvar_cxy, &condvar_ptr->root ) ) == false )
210    {
211         // get first waiting thread
212         xptr_t thread_xp = XLIST_FIRST( XPTR( condvar_cxy , &condvar_ptr->root ),
213                                         thread_t , wait_xlist );
214
215         // remove this waiting thread from queue
216         thread_t * thread_ptr = GET_PTR( thread_xp );
217         cxy_t      thread_cxy = GET_CXY( thread_xp );
218         xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
219
220         // unblock this waiting thread
221         thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
222    }
223
224}  // end remote_condvar_signal()
225
226//////////////////////////////////////////////////
227void remote_condvar_broadcast( xptr_t condvar_xp )
228{
229    // get condvar cluster and local pointer
230    remote_condvar_t * condvar_ptr = GET_PTR( condvar_xp );
231    cxy_t              condvar_cxy = GET_CXY( condvar_xp );
232
233    // does nothing if waiting queue empty
234    while( xlist_is_empty( XPTR( condvar_cxy , &condvar_ptr->root ) ) == false )
235    {
236         // get first waiting thread
237         xptr_t thread_xp = XLIST_FIRST( XPTR( condvar_cxy , &condvar_ptr->root ),
238                                         thread_t , wait_xlist );
239
240         // remove this waiting thread from queue
241         thread_t * thread_ptr = GET_PTR( thread_xp );
242         cxy_t      thread_cxy = GET_CXY( thread_xp );
243         xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
244
245         // unblock this waiting thread
246         thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
247    }
248}  // end remote_condvar_broadcast()
249
Note: See TracBrowser for help on using the repository browser.