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

Last change on this file since 577 was 573, checked in by alain, 5 years ago

Cosmetic.

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