source: trunk/libs/libpthread/pthread.c@ 650

Last change on this file since 650 was 650, checked in by alain, 7 years ago

Simplify the pthread_parallel_create() syscall.

File size: 17.0 KB
Line 
1/*
2 * pthread.c - User level <pthread> library implementation.
3 *
4 * Author 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 <hal_user.h>
25#include <hal_shared_types.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <pthread.h>
29#include <shared_pthread.h>
30#include <almosmkh.h>
31#include <syscalls_numbers.h>
32
33
34////////////////////////////////////////////////////////////////////////////////////////////
35// Threads
36////////////////////////////////////////////////////////////////////////////////////////////
37
38/////////////////////////////////////////////////
39int pthread_create( pthread_t * trdid,
40 const pthread_attr_t * attr,
41 void * start_func,
42 void * start_args )
43{
44 return hal_user_syscall( SYS_THREAD_CREATE,
45 (reg_t)trdid,
46 (reg_t)attr,
47 (reg_t)start_func,
48 (reg_t)start_args );
49}
50
51/////////////////////////////////////
52int pthread_join( pthread_t trdid,
53 void ** exit_status )
54{
55 return hal_user_syscall( SYS_THREAD_JOIN,
56 (reg_t)trdid,
57 (reg_t)exit_status, 0, 0 );
58}
59
60///////////////////////////////////////
61int pthread_detach( pthread_t trdid )
62{
63 return hal_user_syscall( SYS_THREAD_DETACH,
64 (reg_t)trdid, 0, 0, 0 );
65}
66
67//////////////////////////////////////
68int pthread_exit( void * exit_status )
69{
70 return hal_user_syscall( SYS_THREAD_EXIT,
71 (reg_t)exit_status, 0, 0, 0 );
72}
73
74/////////////////////////
75int pthread_yield( void )
76{
77 return hal_user_syscall( SYS_THREAD_YIELD, 0, 0, 0, 0 );
78}
79
80////////////////////////////////////////////////////////////////////////////////////////////
81// Mutexes
82////////////////////////////////////////////////////////////////////////////////////////////
83
84//////////////////////////////////////////////////////////
85int pthread_mutex_init( pthread_mutex_t * mutex,
86 const pthread_mutexattr_t * attr )
87{
88 if( attr != NULL )
89 {
90 printf("\n[ERROR] in %s : <attr> argument not supported\n", __FUNCTION__);
91 return -1;
92 }
93
94 return hal_user_syscall( SYS_MUTEX,
95 (reg_t)mutex,
96 MUTEX_INIT,
97 0, 0 );
98}
99
100////////////////////////////////////////////////////
101int pthread_mutex_destroy( pthread_mutex_t * mutex )
102{
103 return hal_user_syscall( SYS_MUTEX,
104 (reg_t)mutex,
105 MUTEX_DESTROY,
106 0, 0 );
107}
108
109/////////////////////////////////////////////////
110int pthread_mutex_lock( pthread_mutex_t * mutex )
111{
112 return hal_user_syscall( SYS_MUTEX,
113 (reg_t)mutex,
114 MUTEX_LOCK,
115 0, 0 );
116}
117
118////////////////////////////////////////////////////
119int pthread_mutex_trylock( pthread_mutex_t * mutex )
120{
121 return hal_user_syscall( SYS_MUTEX,
122 (reg_t)mutex,
123 MUTEX_TRYLOCK,
124 0, 0 );
125}
126
127///////////////////////////////////////////////////
128int pthread_mutex_unlock( pthread_mutex_t * mutex )
129{
130 return hal_user_syscall( SYS_MUTEX,
131 (reg_t)mutex,
132 MUTEX_UNLOCK,
133 0, 0 );
134}
135
136////////////////////////////////////////////////////////////////////////////////////////////
137// Condvars
138////////////////////////////////////////////////////////////////////////////////////////////
139
140///////////////////////////////////////////////
141int pthread_cond_init( pthread_cond_t * cond,
142 pthread_condattr_t * attr )
143{
144 if( attr )
145 {
146 printf("[ERROR] in %s ; <attr> argument must be NULL\n", __FUNCTION__ );
147 return -1;
148 }
149
150 return hal_user_syscall( SYS_CONDVAR,
151 (reg_t)cond,
152 CONDVAR_INIT,
153 0, 0 );
154}
155
156/////////////////////////////////////////////////
157int pthread_cond_destroy( pthread_cond_t * cond )
158{
159 return hal_user_syscall( SYS_CONDVAR,
160 (reg_t)cond,
161 CONDVAR_DESTROY,
162 0, 0 );
163}
164
165//////////////////////////////////////////////
166int pthread_cond_wait( pthread_cond_t * cond,
167 pthread_mutex_t * mutex )
168{
169 return hal_user_syscall( SYS_CONDVAR,
170 (reg_t)cond,
171 CONDVAR_WAIT,
172 (reg_t)mutex,
173 0 );
174}
175
176////////////////////////////////////////////////
177int pthread_cond_signal( pthread_cond_t * cond )
178{
179 return hal_user_syscall( SYS_CONDVAR,
180 (reg_t)cond,
181 CONDVAR_SIGNAL,
182 0, 0 );
183}
184
185///////////////////////////////////////////////////
186int pthread_cond_broadcast( pthread_cond_t * cond )
187{
188 return hal_user_syscall( SYS_CONDVAR,
189 (reg_t)cond,
190 CONDVAR_BROADCAST,
191 0, 0 );
192}
193
194
195////////////////////////////////////////////////////////////////////////////////////////////
196// Barriers
197////////////////////////////////////////////////////////////////////////////////////////////
198
199////////////////////////////////////////////////////////////////
200int pthread_barrier_init( pthread_barrier_t * barrier,
201 const pthread_barrierattr_t * attr,
202 unsigned int count )
203{
204 return hal_user_syscall( SYS_BARRIER,
205 (reg_t)barrier,
206 BARRIER_INIT,
207 (reg_t)count,
208 (reg_t)attr );
209}
210
211//////////////////////////////////////////////////////////
212int pthread_barrier_destroy( pthread_barrier_t * barrier )
213{
214 return hal_user_syscall( SYS_BARRIER,
215 (reg_t)barrier,
216 BARRIER_DESTROY,
217 0, 0 );
218}
219
220///////////////////////////////////////////////////////
221int pthread_barrier_wait( pthread_barrier_t * barrier )
222{
223 return hal_user_syscall( SYS_BARRIER,
224 (reg_t)barrier,
225 BARRIER_WAIT,
226 0, 0 );
227}
228
229/*
230
231////////////////////////////////////////////////////////////////////////////////////////////
232// The following functions define another implementation for the POSX barrier, based on
233// a distributed quad tree implemented in user space, but using a busy waiting policy.
234////////////////////////////////////////////////////////////////////////////////////////////
235
236
237////////////////////////////////////////////////////////////////////////////////////////////
238// This recursive function initializes the DQT nodes traversing the SQT from root to bottom
239////////////////////////////////////////////////////////////////////////////////////////////
240static void dqt_barrier_build( pthread_barrier_t * barrier,
241 unsigned int x,
242 unsigned int y,
243 unsigned int level,
244 dqt_node_t * parent,
245 unsigned int x_size,
246 unsigned int y_size,
247 unsigned int nthreads )
248{
249 // get target node address
250 dqt_node_t * node = barrier->node[x][y][level];
251
252 if (level == 0 ) // terminal case
253 {
254 // initializes target node
255 node->arity = nthreads;
256 node->count = nthreads;
257 node->sense = 0;
258 node->level = 0;
259 node->parent = parent;
260 node->child[0] = NULL;
261 node->child[1] = NULL;
262 node->child[2] = NULL;
263 node->child[3] = NULL;
264
265#if PTHREAD_BARRIER_DEBUG
266printf("\n[BARRIER] %s : dqt_node[%d][%d][%d] / arity %d / desc %x\n"
267"parent %x / child0 %x / child1 %x / child2 %x / child3 %x\n",
268__FUNCTION__, x, y, level, node->arity, node, node->parent,
269node->child[0], node->child[1], node->child[2], node->child[3] );
270#endif
271
272 }
273 else // non terminal case
274 {
275 unsigned int cx[4]; // x coordinate for children
276 unsigned int cy[4]; // y coordinate for children
277 unsigned int arity = 0;
278 unsigned int i;
279
280 // the child0 coordinates are equal to the parent coordinates
281 // other children coordinates are incremented depending on the level value
282 cx[0] = x;
283 cy[0] = y;
284
285 cx[1] = x;
286 cy[1] = y + (1 << (level-1));
287
288 cx[2] = x + (1 << (level-1));
289 cy[2] = y;
290
291 cx[3] = x + (1 << (level-1));
292 cy[3] = y + (1 << (level-1));
293
294 // initializes parent node taken into account the actual number of childs
295 // child pointer is NULL if coordinates outside the mesh
296 for ( i = 0 ; i < 4 ; i++ )
297 {
298 if ( (cx[i] < x_size) && (cy[i] < y_size) )
299 {
300 node->child[i] = barrier->node[cx[i]][cy[i]][level-1];
301 arity++;
302 }
303 else node->child[i] = NULL;
304 }
305 node->arity = arity;
306 node->count = arity;
307 node->sense = 0;
308 node->level = level;
309 node->parent = parent;
310
311#if PTHREAD_BARRIER_DEBUG
312printf("\n[BARRIER] %s : dqt_node[%d][%d][%d] / arity %d / desc %x\n"
313"parent %x / child0 %x / child1 %x / child2 %x / child3 %x\n",
314__FUNCTION__, x, y, level, node->arity, node, node->parent,
315node->child[0], node->child[1], node->child[2], node->child[3] );
316#endif
317
318 // recursive calls for children nodes
319 for ( i = 0 ; i < 4 ; i++ )
320 {
321 if ( (cx[i] < x_size) && (cy[i] < y_size) )
322 dqt_barrier_build( barrier,
323 cx[i],
324 cy[i],
325 level-1,
326 node,
327 x_size,
328 y_size,
329 nthreads );
330 }
331 }
332} // end dqt_barrier_build()
333
334////////////////////////////////////////////////////////////////
335int pthread_barrier_init( pthread_barrier_t * barrier,
336 const pthread_barrierattr_t * attr,
337 unsigned int count )
338{
339 unsigned int x_size;
340 unsigned int y_size;
341 unsigned int nthreads;
342
343 if( attr != NULL )
344 {
345 x_size = attr->x_size;
346 y_size = attr->y_size;
347 nthreads = attr->nthreads;
348 }
349 else
350 {
351 x_size = 1;
352 y_size = 1;
353 nthreads = count;
354 }
355
356 // check attributes / count
357 if( (x_size * y_size * nthreads) != count )
358 {
359 printf("\[ERROR] in %s : count != x_size * y_size * nthreads/n", __FUNCTION__);
360 exit( EXIT_FAILURE );
361 }
362
363 // compute SQT levels
364 unsigned int levels;
365 unsigned int z = (x_size > y_size) ? x_size : y_size;
366 levels = (z < 2) ? 1 : (z < 3) ? 2 : (z < 5) ? 3 : (z < 9) ? 4 : 5;
367
368#if PTHREAD_BARRIER_DEBUG
369unsigned int side = (z < 2) ? 1 : (z < 3) ? 2 : (z < 5) ? 4 : (z < 9) ? 8 : 16;
370printf("\n[BARRIER] %s : x_size = %d / y_size = %d / levels = %d / side = %d\n",
371__FUNCTION__ , x_size , y_size , levels , side );
372#endif
373
374 // allocates memory for the SQT nodes and initializes SQT nodes pointers array
375 // the actual number of SQT nodes in a cluster(x,y) depends on (x,y):
376 // At least 1 node / at most 5 nodes
377 unsigned int x; // x coordinate for one SQT node
378 unsigned int y; // y coordinate for one SQT node
379 unsigned int l; // level for one SQT node
380 for ( x = 0 ; x < x_size ; x++ )
381 {
382 for ( y = 0 ; y < y_size ; y++ )
383 {
384 unsigned int cxy = (x<<QDT_YWIDTH) + y;
385
386 for ( l = 0 ; l < levels ; l++ )
387 {
388 if ( ( (l == 0) && ((x&0x00) == 0) && ((y&0x00) == 0) ) ||
389 ( (l == 1) && ((x&0x01) == 0) && ((y&0x01) == 0) ) ||
390 ( (l == 2) && ((x&0x03) == 0) && ((y&0x03) == 0) ) ||
391 ( (l == 3) && ((x&0x07) == 0) && ((y&0x07) == 0) ) ||
392 ( (l == 4) && ((x&0x0F) == 0) && ((y&0x0F) == 0) ) )
393 {
394 dqt_node_t * node = remote_malloc( sizeof(dqt_node_t) , cxy );
395
396 if( node == NULL )
397 {
398 printf("\n[ERROR] in %s : cannot allocate dqt_node in cluster %x\n",
399 __FUNCTION__ , cxy );
400 return -1;
401 }
402
403 barrier->node[x][y][l] = node;
404
405 }
406 }
407 }
408 }
409
410 // recursively initialize all SQT nodes from root to bottom
411 dqt_barrier_build( barrier,
412 0,
413 0,
414 levels-1,
415 NULL,
416 x_size,
417 y_size,
418 nthreads );
419
420 hal_user_fence();
421
422 return 0;
423
424} // end pthread_barrier_init
425
426//////////////////////////////////////////////////////////////////////////////////////////
427// This recursive function decrements the distributed "count" variables,
428// traversing the DQT from bottom to root.
429// The last arrived thread reset the local node before returning.
430//////////////////////////////////////////////////////////////////////////////////////////
431static void dqt_barrier_decrement( dqt_node_t * node )
432{
433
434#if PTHREAD_BARRIER_DEBUG
435unsigned int cxy;
436unsigned int lid;
437get_core( &cxy , &lid );
438printf("\n[BARRIER] %s : core[%x,%d] decrement SQT barrier node %x :\n"
439" level = %d / parent = %x / arity = %d / sense = %d / count = %d\n",
440__FUNCTION__ , cxy , lid , (unsigned int)node ,
441node->level , node->parent, node->arity , node->sense , node->count );
442#endif
443
444 unsigned int expected;
445
446 // compute expected sense value
447 if ( node->sense == 0) expected = 1;
448 else expected = 0;
449
450 // atomically decrement count
451 int count = hal_user_atomic_add( (int *)&node->count , -1 );
452
453 // last arrived thread makes the recursive call
454 if ( count == 1 ) // last thread
455 {
456 // decrement the parent node if the current node is not the root
457 if ( node->parent != NULL ) dqt_barrier_decrement( node->parent );
458
459#if PTHREAD_BARRIER_DEBUG
460printf("\n[BARRIER] %s : core[%x,%d] reset SQT barrier node %x :\n"
461" level = %d / arity = %d / sense = %d / count = %d\n",
462__FUNCTION__ , cxy , lid , (unsigned int)node ,
463node->level , node->arity , node->sense , node->count );
464#endif
465 // reset the current node
466 node->sense = expected;
467 node->count = node->arity;
468
469 return;
470 }
471 else // not the last thread
472 {
473 while( 1 )
474 {
475 // poll sense
476 if( node->sense == expected ) break;
477
478 // deschedule
479 pthread_yield();
480 }
481
482 return;
483 }
484} // end dqt_barrier_decrement()
485
486///////////////////////////////////////////////////////
487int pthread_barrier_wait( pthread_barrier_t * barrier )
488{
489 // get calling core cluster
490 unsigned int cxy;
491 unsigned int lid;
492 get_core( &cxy , &lid );
493
494 // get calling core coordinate
495 unsigned int x = cxy >> QDT_YWIDTH;
496 unsigned int y = cxy & QDT_YMASK;
497
498#if PTHREAD_BARRIER_DEBUG
499printf("\n[BARRIER] %s : core[%x,%d] enter / barrier = %x / node = %x\n",
500__FUNCTION__ , cxy , lid , barrier, barrier->node[x][y][0] );
501#endif
502
503 // recursively decrement count from bottom to root
504 dqt_barrier_decrement( barrier->node[x][y][0] );
505
506 hal_user_fence();
507
508 return 0;
509
510} // end pthread_barrier_wait()
511
512*/
513
514
515
516// Local Variables:
517// tab-width: 4
518// c-basic-offset: 4
519// c-file-offsets:((innamespace . 0)(inline-open . 0))
520// indent-tabs-mode: nil
521// End:
522// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
523
Note: See TracBrowser for help on using the repository browser.