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

Last change on this file since 473 was 473, checked in by alain, 3 years ago

Fix several GCC warning related to the -Wextra compilation option.

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