| [439] | 1 | /* | 
|---|
| [457] | 2 | * pthread.c - User level <pthread> library implementation. | 
|---|
| [439] | 3 | * | 
|---|
| [440] | 4 | * Author     Alain Greiner (2016,2017,2018) | 
|---|
| [439] | 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> | 
|---|
| [457] | 25 | #include <hal_shared_types.h> | 
|---|
| [439] | 26 | #include <stdio.h> | 
|---|
|  | 27 | #include <stdlib.h> | 
|---|
|  | 28 | #include <pthread.h> | 
|---|
| [457] | 29 | #include <shared_pthread.h> | 
|---|
| [445] | 30 | #include <almosmkh.h> | 
|---|
| [444] | 31 | #include <syscalls_numbers.h> | 
|---|
| [439] | 32 |  | 
|---|
|  | 33 |  | 
|---|
|  | 34 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 35 | //                  Threads | 
|---|
|  | 36 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 37 |  | 
|---|
|  | 38 | ///////////////////////////////////////////////// | 
|---|
|  | 39 | int 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 | ///////////////////////////////////// | 
|---|
|  | 52 | int pthread_join( pthread_t    trdid, | 
|---|
|  | 53 | void      ** exit_value ) | 
|---|
|  | 54 | { | 
|---|
|  | 55 | return hal_user_syscall( SYS_THREAD_JOIN, | 
|---|
| [473] | 56 | (reg_t)trdid, | 
|---|
|  | 57 | (reg_t)exit_value, 0, 0 ); | 
|---|
| [439] | 58 | } | 
|---|
|  | 59 |  | 
|---|
|  | 60 | /////////////////////////////////////// | 
|---|
|  | 61 | int pthread_detach( pthread_t   trdid ) | 
|---|
|  | 62 | { | 
|---|
|  | 63 | return hal_user_syscall( SYS_THREAD_DETACH, | 
|---|
|  | 64 | (reg_t)trdid, 0, 0, 0 ); | 
|---|
|  | 65 | } | 
|---|
|  | 66 |  | 
|---|
|  | 67 | ///////////////////////////////////// | 
|---|
|  | 68 | int pthread_exit( void * exit_value ) | 
|---|
|  | 69 | { | 
|---|
|  | 70 | return hal_user_syscall( SYS_THREAD_EXIT, | 
|---|
|  | 71 | (reg_t)exit_value, 0, 0, 0 ); | 
|---|
|  | 72 | } | 
|---|
|  | 73 |  | 
|---|
| [581] | 74 | ///////////////////////// | 
|---|
| [477] | 75 | int pthread_yield( void ) | 
|---|
| [439] | 76 | { | 
|---|
|  | 77 | return hal_user_syscall( SYS_THREAD_YIELD, 0, 0, 0, 0 ); | 
|---|
|  | 78 | } | 
|---|
|  | 79 |  | 
|---|
|  | 80 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [581] | 81 | //                               Mutexes | 
|---|
|  | 82 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 83 |  | 
|---|
|  | 84 | ////////////////////////////////////////////////////////// | 
|---|
|  | 85 | int 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 | //////////////////////////////////////////////////// | 
|---|
|  | 101 | int 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 | ///////////////////////////////////////////////// | 
|---|
|  | 110 | int 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 | //////////////////////////////////////////////////// | 
|---|
|  | 119 | int 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 | /////////////////////////////////////////////////// | 
|---|
|  | 128 | int 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 | /////////////////////////////////////////////// | 
|---|
|  | 141 | int 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 | ///////////////////////////////////////////////// | 
|---|
|  | 157 | int 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 | ////////////////////////////////////////////// | 
|---|
|  | 166 | int 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 | //////////////////////////////////////////////// | 
|---|
|  | 177 | int 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 | /////////////////////////////////////////////////// | 
|---|
|  | 186 | int 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 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [439] | 196 | //                            Barriers | 
|---|
|  | 197 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 198 |  | 
|---|
| [581] | 199 | //////////////////////////////////////////////////////////////// | 
|---|
|  | 200 | int 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 | 0 ); | 
|---|
|  | 209 | } | 
|---|
|  | 210 |  | 
|---|
|  | 211 | ////////////////////////////////////////////////////////// | 
|---|
|  | 212 | int 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 | /////////////////////////////////////////////////////// | 
|---|
|  | 221 | int 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 |  | 
|---|
| [439] | 231 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [581] | 232 | // The following functions define another implementation for the POSX barrier | 
|---|
|  | 233 | // based on a distributed quadtree implemented in user space, and relying | 
|---|
|  | 234 | // on a busy waiting policy. | 
|---|
|  | 235 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 236 |  | 
|---|
|  | 237 |  | 
|---|
|  | 238 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [439] | 239 | // This recursive function initializes the SQT nodes | 
|---|
|  | 240 | // traversing the SQT from root to bottom | 
|---|
|  | 241 | //////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 242 | static void sqt_barrier_build( pthread_barrier_t  * barrier, | 
|---|
|  | 243 | unsigned int         x, | 
|---|
|  | 244 | unsigned int         y, | 
|---|
|  | 245 | unsigned int         level, | 
|---|
|  | 246 | sqt_node_t         * parent, | 
|---|
|  | 247 | unsigned int         x_size, | 
|---|
|  | 248 | unsigned int         y_size, | 
|---|
|  | 249 | unsigned int         nthreads ) | 
|---|
|  | 250 | { | 
|---|
|  | 251 | // get target node address | 
|---|
|  | 252 | sqt_node_t * node = barrier->node[x][y][level]; | 
|---|
|  | 253 |  | 
|---|
|  | 254 | if (level == 0 )        // terminal case | 
|---|
|  | 255 | { | 
|---|
|  | 256 | // initializes target node | 
|---|
|  | 257 | node->arity    = nthreads; | 
|---|
|  | 258 | node->count    = nthreads; | 
|---|
|  | 259 | node->sense    = 0; | 
|---|
|  | 260 | node->level    = 0; | 
|---|
|  | 261 | node->parent   = parent; | 
|---|
|  | 262 | node->child[0] = NULL; | 
|---|
|  | 263 | node->child[1] = NULL; | 
|---|
|  | 264 | node->child[2] = NULL; | 
|---|
|  | 265 | node->child[3] = NULL; | 
|---|
|  | 266 |  | 
|---|
|  | 267 | #if PTHREAD_BARRIER_DEBUG | 
|---|
| [440] | 268 | printf("\n[BARRIER] %s : sqt_node[%d][%d][%d] / arity %d / desc %x\n" | 
|---|
|  | 269 | "parent %x / child0 %x / child1 %x / child2 %x / child3 %x\n", | 
|---|
|  | 270 | __FUNCTION__, x, y, level, node->arity, node, node->parent, | 
|---|
| [439] | 271 | node->child[0], node->child[1], node->child[2], node->child[3] ); | 
|---|
|  | 272 | #endif | 
|---|
|  | 273 |  | 
|---|
|  | 274 | } | 
|---|
|  | 275 | else                   // non terminal case | 
|---|
|  | 276 | { | 
|---|
|  | 277 | unsigned int cx[4];   // x coordinate for children | 
|---|
|  | 278 | unsigned int cy[4];   // y coordinate for children | 
|---|
|  | 279 | unsigned int arity = 0; | 
|---|
|  | 280 | unsigned int i; | 
|---|
|  | 281 |  | 
|---|
|  | 282 | // the child0 coordinates are equal to the parent coordinates | 
|---|
|  | 283 | // other children coordinates are incremented depending on the level value | 
|---|
|  | 284 | cx[0] = x; | 
|---|
|  | 285 | cy[0] = y; | 
|---|
|  | 286 |  | 
|---|
|  | 287 | cx[1] = x; | 
|---|
|  | 288 | cy[1] = y + (1 << (level-1)); | 
|---|
|  | 289 |  | 
|---|
|  | 290 | cx[2] = x + (1 << (level-1)); | 
|---|
|  | 291 | cy[2] = y; | 
|---|
|  | 292 |  | 
|---|
|  | 293 | cx[3] = x + (1 << (level-1)); | 
|---|
|  | 294 | cy[3] = y + (1 << (level-1)); | 
|---|
|  | 295 |  | 
|---|
|  | 296 | // initializes parent node taken into account the actual number of childs | 
|---|
|  | 297 | // child pointer is NULL if coordinates outside the mesh | 
|---|
|  | 298 | for ( i = 0 ; i < 4 ; i++ ) | 
|---|
|  | 299 | { | 
|---|
|  | 300 | if ( (cx[i] < x_size) && (cy[i] < y_size) ) | 
|---|
|  | 301 | { | 
|---|
|  | 302 | node->child[i] = barrier->node[cx[i]][cy[i]][level-1]; | 
|---|
|  | 303 | arity++; | 
|---|
|  | 304 | } | 
|---|
|  | 305 | else  node->child[i] = NULL; | 
|---|
|  | 306 | } | 
|---|
|  | 307 | node->arity    = arity; | 
|---|
|  | 308 | node->count    = arity; | 
|---|
|  | 309 | node->sense    = 0; | 
|---|
|  | 310 | node->level    = level; | 
|---|
|  | 311 | node->parent   = parent; | 
|---|
|  | 312 |  | 
|---|
|  | 313 | #if PTHREAD_BARRIER_DEBUG | 
|---|
| [440] | 314 | printf("\n[BARRIER] %s : sqt_node[%d][%d][%d] / arity %d / desc %x\n" | 
|---|
|  | 315 | "parent %x / child0 %x / child1 %x / child2 %x / child3 %x\n", | 
|---|
|  | 316 | __FUNCTION__, x, y, level, node->arity, node, node->parent, | 
|---|
| [439] | 317 | node->child[0], node->child[1], node->child[2], node->child[3] ); | 
|---|
|  | 318 | #endif | 
|---|
|  | 319 |  | 
|---|
|  | 320 | // recursive calls for children nodes | 
|---|
|  | 321 | for ( i = 0 ; i < 4 ; i++ ) | 
|---|
|  | 322 | { | 
|---|
|  | 323 | if ( (cx[i] < x_size) && (cy[i] < y_size) ) | 
|---|
|  | 324 | sqt_barrier_build( barrier, | 
|---|
|  | 325 | cx[i], | 
|---|
|  | 326 | cy[i], | 
|---|
|  | 327 | level-1, | 
|---|
|  | 328 | node, | 
|---|
|  | 329 | x_size, | 
|---|
|  | 330 | y_size, | 
|---|
|  | 331 | nthreads ); | 
|---|
|  | 332 | } | 
|---|
|  | 333 | } | 
|---|
|  | 334 | }  // end sqt_barrier_build() | 
|---|
|  | 335 |  | 
|---|
|  | 336 | //////////////////////////////////////////////////////////////// | 
|---|
|  | 337 | int pthread_barrier_init( pthread_barrier_t           * barrier, | 
|---|
|  | 338 | const pthread_barrierattr_t * attr, | 
|---|
|  | 339 | unsigned int                  count ) | 
|---|
|  | 340 | { | 
|---|
|  | 341 | unsigned int x_size; | 
|---|
|  | 342 | unsigned int y_size; | 
|---|
|  | 343 | unsigned int nthreads; | 
|---|
|  | 344 |  | 
|---|
|  | 345 | if( attr != NULL ) | 
|---|
|  | 346 | { | 
|---|
|  | 347 | x_size   = attr->x_size; | 
|---|
|  | 348 | y_size   = attr->y_size; | 
|---|
|  | 349 | nthreads = attr->nthreads; | 
|---|
|  | 350 | } | 
|---|
|  | 351 | else | 
|---|
|  | 352 | { | 
|---|
|  | 353 | x_size   = 1; | 
|---|
|  | 354 | y_size   = 1; | 
|---|
|  | 355 | nthreads = count; | 
|---|
|  | 356 | } | 
|---|
|  | 357 |  | 
|---|
|  | 358 | // check attributes | 
|---|
| [445] | 359 | if( (x_size * y_size * nthreads) != count ) | 
|---|
|  | 360 | { | 
|---|
|  | 361 | printf("\[ERROR] in %s : count != x_size * y_size * nthreads/n", __FUNCTION__); | 
|---|
|  | 362 | exit( EXIT_FAILURE ); | 
|---|
|  | 363 | } | 
|---|
| [439] | 364 |  | 
|---|
|  | 365 | // compute SQT levels | 
|---|
|  | 366 | unsigned int levels; | 
|---|
|  | 367 | unsigned int z = (x_size > y_size) ? x_size : y_size; | 
|---|
|  | 368 | levels = (z < 2) ? 1 : (z < 3) ? 2 : (z < 5) ? 3 : (z < 9) ? 4 : 5; | 
|---|
|  | 369 |  | 
|---|
|  | 370 | #if PTHREAD_BARRIER_DEBUG | 
|---|
|  | 371 | unsigned int side = (z < 2) ? 1 : (z < 3) ? 2 : (z < 5) ? 4 : (z < 9) ? 8 : 16; | 
|---|
|  | 372 | printf("\n[BARRIER] %s : x_size = %d / y_size = %d / levels = %d / side = %d\n", | 
|---|
|  | 373 | __FUNCTION__ , x_size , y_size , levels , side ); | 
|---|
|  | 374 | #endif | 
|---|
|  | 375 |  | 
|---|
|  | 376 | // allocates memory for the SQT nodes and initializes SQT nodes pointers array | 
|---|
|  | 377 | // the actual number of SQT nodes in a cluster(x,y) depends on (x,y): | 
|---|
|  | 378 | // At least 1 node / at most 5 nodes | 
|---|
|  | 379 | unsigned int x;          // x coordinate for one SQT node | 
|---|
|  | 380 | unsigned int y;          // y coordinate for one SQT node | 
|---|
|  | 381 | unsigned int l;          // level for one SQT node | 
|---|
|  | 382 | for ( x = 0 ; x < x_size ; x++ ) | 
|---|
|  | 383 | { | 
|---|
|  | 384 | for ( y = 0 ; y < y_size ; y++ ) | 
|---|
|  | 385 | { | 
|---|
|  | 386 | unsigned int cxy = (x<<QDT_YWIDTH) + y; | 
|---|
|  | 387 |  | 
|---|
|  | 388 | for ( l = 0 ; l < levels ; l++ ) | 
|---|
|  | 389 | { | 
|---|
|  | 390 | if ( ( (l == 0) && ((x&0x00) == 0) && ((y&0x00) == 0) ) || | 
|---|
|  | 391 | ( (l == 1) && ((x&0x01) == 0) && ((y&0x01) == 0) ) || | 
|---|
|  | 392 | ( (l == 2) && ((x&0x03) == 0) && ((y&0x03) == 0) ) || | 
|---|
|  | 393 | ( (l == 3) && ((x&0x07) == 0) && ((y&0x07) == 0) ) || | 
|---|
|  | 394 | ( (l == 4) && ((x&0x0F) == 0) && ((y&0x0F) == 0) ) ) | 
|---|
|  | 395 | { | 
|---|
|  | 396 | sqt_node_t * node = remote_malloc( sizeof(sqt_node_t) , cxy ); | 
|---|
|  | 397 |  | 
|---|
|  | 398 | if( node == NULL ) | 
|---|
|  | 399 | { | 
|---|
|  | 400 | printf("\n[ERROR] in %s : cannot allocate sqt_node in cluster %x\n", | 
|---|
|  | 401 | __FUNCTION__ , cxy ); | 
|---|
|  | 402 | return -1; | 
|---|
|  | 403 | } | 
|---|
|  | 404 |  | 
|---|
|  | 405 | barrier->node[x][y][l] = node; | 
|---|
|  | 406 |  | 
|---|
|  | 407 | } | 
|---|
|  | 408 | } | 
|---|
|  | 409 | } | 
|---|
|  | 410 | } | 
|---|
|  | 411 |  | 
|---|
|  | 412 | // recursively initialize all SQT nodes from root to bottom | 
|---|
|  | 413 | sqt_barrier_build( barrier, | 
|---|
|  | 414 | 0, | 
|---|
|  | 415 | 0, | 
|---|
|  | 416 | levels-1, | 
|---|
|  | 417 | NULL, | 
|---|
|  | 418 | x_size, | 
|---|
|  | 419 | y_size, | 
|---|
|  | 420 | nthreads ); | 
|---|
|  | 421 |  | 
|---|
|  | 422 | hal_user_fence(); | 
|---|
|  | 423 |  | 
|---|
|  | 424 | return 0; | 
|---|
|  | 425 |  | 
|---|
|  | 426 | }  // end pthread_barrier_init | 
|---|
|  | 427 |  | 
|---|
|  | 428 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 429 | // This recursive function decrements the distributed "count" variables, | 
|---|
|  | 430 | // traversing the SQT from bottom to root. | 
|---|
|  | 431 | // The last arrived thread reset the local node before returning. | 
|---|
|  | 432 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 433 | static void sqt_barrier_decrement( sqt_node_t * node ) | 
|---|
|  | 434 | { | 
|---|
|  | 435 |  | 
|---|
|  | 436 | #if PTHREAD_BARRIER_DEBUG | 
|---|
|  | 437 | unsigned int    cxy; | 
|---|
|  | 438 | unsigned int    lid; | 
|---|
|  | 439 | get_core( &cxy , &lid ); | 
|---|
|  | 440 | printf("\n[BARRIER] %s : core[%x,%d] decrement SQT barrier node %x :\n" | 
|---|
|  | 441 | " level = %d / parent = %x / arity = %d / sense = %d / count = %d\n", | 
|---|
|  | 442 | __FUNCTION__ , cxy , lid , (unsigned int)node , | 
|---|
|  | 443 | node->level , node->parent, node->arity , node->sense , node->count ); | 
|---|
|  | 444 | #endif | 
|---|
|  | 445 |  | 
|---|
|  | 446 | unsigned int expected; | 
|---|
|  | 447 |  | 
|---|
|  | 448 | // compute expected sense value | 
|---|
|  | 449 | if ( node->sense == 0) expected = 1; | 
|---|
|  | 450 | else                   expected = 0; | 
|---|
|  | 451 |  | 
|---|
|  | 452 | // atomically decrement count | 
|---|
|  | 453 | int count = hal_user_atomic_add( (int *)&node->count , -1 ); | 
|---|
|  | 454 |  | 
|---|
|  | 455 | // last arrived thread makes the recursive call | 
|---|
|  | 456 | if ( count == 1 )                                     // last thread | 
|---|
|  | 457 | { | 
|---|
|  | 458 | // decrement the parent node if the current node is not the root | 
|---|
|  | 459 | if ( node->parent != NULL )  sqt_barrier_decrement( node->parent ); | 
|---|
|  | 460 |  | 
|---|
|  | 461 | #if PTHREAD_BARRIER_DEBUG | 
|---|
|  | 462 | printf("\n[BARRIER] %s : core[%x,%d] reset SQT barrier node %x :\n" | 
|---|
|  | 463 | " level = %d / arity = %d / sense = %d / count = %d\n", | 
|---|
|  | 464 | __FUNCTION__ , cxy , lid , (unsigned int)node , | 
|---|
|  | 465 | node->level , node->arity , node->sense , node->count ); | 
|---|
|  | 466 | #endif | 
|---|
| [573] | 467 | // reset the current node | 
|---|
|  | 468 | node->sense = expected; | 
|---|
|  | 469 | node->count = node->arity; | 
|---|
|  | 470 |  | 
|---|
| [439] | 471 | return; | 
|---|
|  | 472 | } | 
|---|
|  | 473 | else                                               // not the last thread | 
|---|
|  | 474 | { | 
|---|
|  | 475 | while( 1 ) | 
|---|
|  | 476 | { | 
|---|
| [445] | 477 | // poll sense | 
|---|
| [439] | 478 | if( node->sense == expected ) break; | 
|---|
| [445] | 479 |  | 
|---|
|  | 480 | // deschedule | 
|---|
|  | 481 | pthread_yield(); | 
|---|
| [439] | 482 | } | 
|---|
|  | 483 |  | 
|---|
|  | 484 | return; | 
|---|
|  | 485 | } | 
|---|
|  | 486 | } // end sqt_barrier_decrement() | 
|---|
|  | 487 |  | 
|---|
|  | 488 | /////////////////////////////////////////////////////// | 
|---|
|  | 489 | int pthread_barrier_wait( pthread_barrier_t * barrier ) | 
|---|
|  | 490 | { | 
|---|
|  | 491 | // get calling core cluster | 
|---|
|  | 492 | unsigned int    cxy; | 
|---|
|  | 493 | unsigned int    lid; | 
|---|
|  | 494 | get_core( &cxy , &lid ); | 
|---|
|  | 495 |  | 
|---|
|  | 496 | // get calling core coordinate | 
|---|
|  | 497 | unsigned int    x = cxy >> QDT_YWIDTH; | 
|---|
|  | 498 | unsigned int    y = cxy &  QDT_YMASK; | 
|---|
|  | 499 |  | 
|---|
|  | 500 | #if PTHREAD_BARRIER_DEBUG | 
|---|
| [473] | 501 | printf("\n[BARRIER] %s : core[%x,%d] enter / barrier = %x / node = %x\n", | 
|---|
| [439] | 502 | __FUNCTION__ , cxy , lid , barrier, barrier->node[x][y][0] ); | 
|---|
|  | 503 | #endif | 
|---|
|  | 504 |  | 
|---|
|  | 505 | // recursively decrement count from bottom to root | 
|---|
|  | 506 | sqt_barrier_decrement( barrier->node[x][y][0] ); | 
|---|
|  | 507 |  | 
|---|
|  | 508 | hal_user_fence(); | 
|---|
|  | 509 |  | 
|---|
|  | 510 | return 0; | 
|---|
|  | 511 |  | 
|---|
|  | 512 | }  // end pthread_barrier_wait() | 
|---|
|  | 513 |  | 
|---|
| [581] | 514 | */ | 
|---|
| [439] | 515 |  | 
|---|
|  | 516 |  | 
|---|
|  | 517 |  | 
|---|
|  | 518 | // Local Variables: | 
|---|
|  | 519 | // tab-width: 4 | 
|---|
|  | 520 | // c-basic-offset: 4 | 
|---|
|  | 521 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) | 
|---|
|  | 522 | // indent-tabs-mode: nil | 
|---|
|  | 523 | // End: | 
|---|
|  | 524 | // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 | 
|---|
|  | 525 |  | 
|---|