|
PAPI
5.0.1.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00005 /* 00006 * File: threads.c 00007 * Author: Philip Mucci 00008 * mucci@cs.utk.edu 00009 * Mods: Kevin London 00010 * london@cs.utk.edu 00011 */ 00012 00013 /* This file contains thread allocation and bookkeeping functions */ 00014 00015 #include "papi.h" 00016 #include "papi_internal.h" 00017 #include "papi_vector.h" 00018 #include "papi_memory.h" 00019 #include <string.h> 00020 #include <unistd.h> 00021 00022 /*****************/ 00023 /* BEGIN GLOBALS */ 00024 /*****************/ 00025 00026 /* The following globals get initialized and cleared by: 00027 extern int _papi_hwi_init_global_threads(void); 00028 extern int _papi_hwi_shutdown_thread(ThreadInfo_t *thread); */ 00029 00030 /* list of threads, gets initialized to master process with TID of getpid() */ 00031 00032 volatile ThreadInfo_t *_papi_hwi_thread_head; 00033 00034 /* If we have TLS, this variable ALWAYS points to our thread descriptor. It's like magic! */ 00035 00036 #if defined(HAVE_THREAD_LOCAL_STORAGE) 00037 THREAD_LOCAL_STORAGE_KEYWORD ThreadInfo_t *_papi_hwi_my_thread; 00038 #endif 00039 00040 /* Function that returns and unsigned long thread identifier */ 00041 00042 unsigned long ( *_papi_hwi_thread_id_fn ) ( void ); 00043 00044 /* Function that sends a signal to other threads */ 00045 00046 #ifdef ANY_THREAD_GETS_SIGNAL 00047 int ( *_papi_hwi_thread_kill_fn ) ( int, int ); 00048 #endif 00049 00050 /*****************/ 00051 /* END GLOBALS */ 00052 /*****************/ 00053 00054 static int 00055 lookup_and_set_thread_symbols( void ) 00056 { 00057 #if defined(ANY_THREAD_GETS_SIGNAL) 00058 int retval; 00059 char *error_ptc = NULL, *error_ptk = NULL; 00060 void *symbol_ptc = NULL, *symbol_ptk = NULL, *handle = NULL; 00061 00062 handle = dlopen( NULL, RTLD_LAZY ); 00063 if ( handle == NULL ) { 00064 PAPIERROR( "Error from dlopen(NULL, RTLD_LAZY): %d %s", errno, 00065 dlerror( ) ); 00066 return ( PAPI_ESYS ); 00067 } 00068 00069 symbol_ptc = dlsym( handle, "pthread_self" ); 00070 if ( symbol_ptc == NULL ) { 00071 error_ptc = dlerror( ); 00072 THRDBG( "dlsym(%p,pthread_self) returned NULL: %s\n", 00073 ( error_ptc ? error_ptc : "No error, NULL symbol!" ) ); 00074 } 00075 00076 symbol_ptk = dlsym( handle, "pthread_kill" ); 00077 if ( symbol_ptk == NULL ) { 00078 error_ptk = dlerror( ); 00079 THRDBG( "dlsym(%p,pthread_kill) returned NULL: %s\n", 00080 ( error_ptk ? error_ptk : "No error, NULL symbol!" ) ); 00081 } 00082 00083 dlclose( handle ); 00084 00085 if ( !( ( _papi_hwi_thread_kill_fn && _papi_hwi_thread_id_fn ) || 00086 ( !_papi_hwi_thread_kill_fn && !_papi_hwi_thread_id_fn ) ) ) 00087 return ( PAPI_EMISC ); 00088 00089 _papi_hwi_thread_kill_fn = ( int ( * )( int, int ) ) symbol_ptk; 00090 _papi_hwi_thread_id_fn = ( unsigned long ( * )( void ) ) symbol_ptc; 00091 #endif 00092 return ( PAPI_OK ); 00093 } 00094 00095 static ThreadInfo_t * 00096 allocate_thread( int tid ) 00097 { 00098 ThreadInfo_t *thread; 00099 int i; 00100 00101 /* The Thread EventSet is special. It is not in the EventSet list, but is pointed 00102 to by each EventSet of that particular thread. */ 00103 00104 thread = ( ThreadInfo_t * ) papi_malloc( sizeof ( ThreadInfo_t ) ); 00105 if ( thread == NULL ) 00106 return ( NULL ); 00107 memset( thread, 0x00, sizeof ( ThreadInfo_t ) ); 00108 00109 thread->context = 00110 ( hwd_context_t ** ) papi_malloc( sizeof ( hwd_context_t * ) * 00111 ( size_t ) papi_num_components ); 00112 if ( !thread->context ) { 00113 papi_free( thread ); 00114 return ( NULL ); 00115 } 00116 00117 thread->running_eventset = 00118 ( EventSetInfo_t ** ) papi_malloc( sizeof ( EventSetInfo_t * ) * 00119 ( size_t ) papi_num_components ); 00120 if ( !thread->running_eventset ) { 00121 papi_free( thread->context ); 00122 papi_free( thread ); 00123 return ( NULL ); 00124 } 00125 00126 for ( i = 0; i < papi_num_components; i++ ) { 00127 thread->context[i] = 00128 ( void * ) papi_malloc( ( size_t ) _papi_hwd[i]->size.context ); 00129 thread->running_eventset[i] = NULL; 00130 if ( thread->context[i] == NULL ) { 00131 for ( i--; i >= 0; i-- ) 00132 papi_free( thread->context[i] ); 00133 papi_free( thread->context ); 00134 papi_free( thread ); 00135 return ( NULL ); 00136 } 00137 memset( thread->context[i], 0x00, 00138 ( size_t ) _papi_hwd[i]->size.context ); 00139 } 00140 00141 if ( _papi_hwi_thread_id_fn ) { 00142 thread->tid = ( *_papi_hwi_thread_id_fn ) ( ); 00143 } 00144 else { 00145 thread->tid = ( unsigned long ) getpid( ); 00146 } 00147 00148 thread->allocator_tid=thread->tid; 00149 00150 if (tid == 0 ) { 00151 } 00152 else { 00153 thread->tid=tid; 00154 } 00155 00156 THRDBG( "Allocated thread %ld at %p, allocator: %ld\n", thread->tid, 00157 thread, 00158 thread->allocator_tid ); 00159 00160 return thread; 00161 } 00162 00163 static void 00164 free_thread( ThreadInfo_t ** thread ) 00165 { 00166 int i; 00167 THRDBG( "Freeing thread %ld at %p\n", ( *thread )->tid, *thread ); 00168 00169 for ( i = 0; i < papi_num_components; i++ ) { 00170 if ( ( *thread )->context[i] ) 00171 papi_free( ( *thread )->context[i] ); 00172 } 00173 00174 if ( ( *thread )->context ) 00175 papi_free( ( *thread )->context ); 00176 00177 if ( ( *thread )->running_eventset ) 00178 papi_free( ( *thread )->running_eventset ); 00179 00180 memset( *thread, 0x00, sizeof ( ThreadInfo_t ) ); 00181 papi_free( *thread ); 00182 *thread = NULL; 00183 } 00184 00185 static void 00186 insert_thread( ThreadInfo_t * entry, int tid ) 00187 { 00188 _papi_hwi_lock( THREADS_LOCK ); 00189 00190 if ( _papi_hwi_thread_head == NULL ) { /* 0 elements */ 00191 THRDBG( "_papi_hwi_thread_head is NULL\n" ); 00192 entry->next = entry; 00193 } else if ( _papi_hwi_thread_head->next == _papi_hwi_thread_head ) { /* 1 elements */ 00194 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n", 00195 _papi_hwi_thread_head->tid, _papi_hwi_thread_head ); 00196 _papi_hwi_thread_head->next = entry; 00197 entry->next = ( ThreadInfo_t * ) _papi_hwi_thread_head; 00198 } else { /* 2+ elements */ 00199 00200 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n", 00201 _papi_hwi_thread_head->tid, _papi_hwi_thread_head ); 00202 entry->next = _papi_hwi_thread_head->next; 00203 _papi_hwi_thread_head->next = entry; 00204 } 00205 00206 _papi_hwi_thread_head = entry; 00207 00208 THRDBG( "_papi_hwi_thread_head now thread %ld at %p\n", 00209 _papi_hwi_thread_head->tid, _papi_hwi_thread_head ); 00210 00211 _papi_hwi_unlock( THREADS_LOCK ); 00212 00213 #if defined(HAVE_THREAD_LOCAL_STORAGE) 00214 /* Don't set the current local thread if we are a fake attach thread */ 00215 if (tid==0) { 00216 _papi_hwi_my_thread = entry; 00217 THRDBG( "TLS for thread %ld is now %p\n", entry->tid, 00218 _papi_hwi_my_thread ); 00219 } 00220 #endif 00221 } 00222 00223 static int 00224 remove_thread( ThreadInfo_t * entry ) 00225 { 00226 ThreadInfo_t *tmp = NULL, *prev = NULL; 00227 00228 _papi_hwi_lock( THREADS_LOCK ); 00229 00230 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n", 00231 _papi_hwi_thread_head->tid, _papi_hwi_thread_head ); 00232 00233 /* Find the preceding element and the matched element, 00234 short circuit if we've seen the head twice */ 00235 00236 for ( tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head; 00237 ( entry != tmp ) || ( prev == NULL ); tmp = tmp->next ) { 00238 prev = tmp; 00239 } 00240 00241 if ( tmp != entry ) { 00242 THRDBG( "Thread %ld at %p was not found in the thread list!\n", 00243 entry->tid, entry ); 00244 return ( PAPI_EBUG ); 00245 } 00246 00247 /* Only 1 element in list */ 00248 00249 if ( prev == tmp ) { 00250 _papi_hwi_thread_head = NULL; 00251 tmp->next = NULL; 00252 THRDBG( "_papi_hwi_thread_head now NULL\n" ); 00253 } else { 00254 prev->next = tmp->next; 00255 /* If we're removing the head, better advance it! */ 00256 if ( _papi_hwi_thread_head == tmp ) { 00257 _papi_hwi_thread_head = tmp->next; 00258 THRDBG( "_papi_hwi_thread_head now thread %ld at %p\n", 00259 _papi_hwi_thread_head->tid, _papi_hwi_thread_head ); 00260 } 00261 THRDBG( "Removed thread %p from list\n", tmp ); 00262 } 00263 00264 _papi_hwi_unlock( THREADS_LOCK ); 00265 00266 #if defined(HAVE_THREAD_LOCAL_STORAGE) 00267 _papi_hwi_my_thread = NULL; 00268 THRDBG( "TLS for thread %ld is now %p\n", entry->tid, 00269 _papi_hwi_my_thread ); 00270 #endif 00271 00272 return PAPI_OK; 00273 } 00274 00275 int 00276 _papi_hwi_initialize_thread( ThreadInfo_t ** dest, int tid ) 00277 { 00278 int retval; 00279 ThreadInfo_t *thread; 00280 int i; 00281 00282 if ( ( thread = allocate_thread( tid ) ) == NULL ) { 00283 *dest = NULL; 00284 return PAPI_ENOMEM; 00285 } 00286 00287 /* Call the component to fill in anything special. */ 00288 00289 for ( i = 0; i < papi_num_components; i++ ) { 00290 if (_papi_hwd[i]->cmp_info.disabled) continue; 00291 retval = _papi_hwd[i]->init_thread( thread->context[i] ); 00292 if ( retval ) { 00293 free_thread( &thread ); 00294 *dest = NULL; 00295 return retval; 00296 } 00297 } 00298 00299 insert_thread( thread, tid ); 00300 00301 *dest = thread; 00302 return PAPI_OK; 00303 } 00304 00305 #if defined(ANY_THREAD_GETS_SIGNAL) 00306 00307 /* This is ONLY defined for systems that enable ANY_THREAD_GETS_SIGNAL 00308 since we must forward signals sent to non-PAPI threads. 00309 00310 This is NOT compatible with thread local storage, since to broadcast 00311 the signal, we need a list of threads. */ 00312 00313 int 00314 _papi_hwi_broadcast_signal( unsigned int mytid ) 00315 { 00316 int i, retval, didsomething = 0; 00317 volatile ThreadInfo_t *foo = NULL; 00318 00319 _papi_hwi_lock( THREADS_LOCK ); 00320 00321 for ( foo = _papi_hwi_thread_head; foo != NULL; foo = foo->next ) { 00322 /* xxxx Should this be hardcoded to index 0 or walk the list or what? */ 00323 for ( i = 0; i < papi_num_components; i++ ) { 00324 if ( ( foo->tid != mytid ) && ( foo->running_eventset[i] ) && 00325 ( foo->running_eventset[i]-> 00326 state & ( PAPI_OVERFLOWING | PAPI_MULTIPLEXING ) ) ) { 00327 /* xxxx mpx_info inside _papi_mdi_t _papi_hwi_system_info is commented out. 00328 See papi_internal.h for details. The multiplex_timer_sig value is now part of that structure */ 00329 THRDBG("Thread %ld sending signal %d to thread %ld\n",mytid,foo->tid, 00330 (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig)); 00331 retval = (*_papi_hwi_thread_kill_fn)(foo->tid, 00332 (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig)); 00333 if (retval != 0) 00334 return(PAPI_EMISC); 00335 } 00336 } 00337 if ( foo->next == _papi_hwi_thread_head ) 00338 break; 00339 } 00340 _papi_hwi_unlock( THREADS_LOCK ); 00341 00342 return ( PAPI_OK ); 00343 } 00344 #endif 00345 00346 /* This is undefined for systems that enable ANY_THREAD_GETS_SIGNAL 00347 since we always must enable threads for safety. */ 00348 00349 int 00350 _papi_hwi_set_thread_id_fn( unsigned long ( *id_fn ) ( void ) ) 00351 { 00352 #if !defined(ANY_THREAD_GETS_SIGNAL) 00353 /* Check for multiple threads still in the list, if so, we can't change it */ 00354 00355 if ( _papi_hwi_thread_head->next != _papi_hwi_thread_head ) 00356 return ( PAPI_EINVAL ); 00357 00358 /* We can't change the thread id function from one to another, 00359 only NULL to non-NULL and vice versa. */ 00360 00361 if ( ( id_fn != NULL ) && ( _papi_hwi_thread_id_fn != NULL ) ) 00362 return ( PAPI_EINVAL ); 00363 00364 _papi_hwi_thread_id_fn = id_fn; 00365 00366 THRDBG( "Set new thread id function to %p\n", id_fn ); 00367 00368 if ( id_fn ) 00369 _papi_hwi_thread_head->tid = ( *_papi_hwi_thread_id_fn ) ( ); 00370 else 00371 _papi_hwi_thread_head->tid = ( unsigned long ) getpid( ); 00372 00373 THRDBG( "New master tid is %ld\n", _papi_hwi_thread_head->tid ); 00374 #else 00375 THRDBG( "Skipping set of thread id function\n" ); 00376 #endif 00377 00378 return PAPI_OK; 00379 } 00380 00381 00382 static int _papi_hwi_thread_free_eventsets(long tid) { 00383 00384 EventSetInfo_t *ESI; 00385 ThreadInfo_t *master; 00386 DynamicArray_t *map = &_papi_hwi_system_info.global_eventset_map; 00387 int i; 00388 00389 master = _papi_hwi_lookup_thread( tid ); 00390 00391 _papi_hwi_lock( INTERNAL_LOCK ); 00392 00393 for( i = 0; i < map->totalSlots; i++ ) { 00394 ESI = map->dataSlotArray[i]; 00395 if ( ( ESI ) && (ESI->master!=NULL) ) { 00396 00397 if ( ESI->master == master ) { 00398 THRDBG("Attempting to remove %d from tid %ld\n",ESI->EventSetIndex,tid); 00399 00400 /* Code copied from _papi_hwi_remove_EventSet(ESI); */ 00401 _papi_hwi_free_EventSet( ESI ); 00402 map->dataSlotArray[i] = NULL; 00403 map->availSlots++; 00404 map->fullSlots--; 00405 } 00406 } 00407 } 00408 00409 _papi_hwi_unlock( INTERNAL_LOCK ); 00410 00411 return PAPI_OK; 00412 } 00413 00414 00415 00416 00417 int 00418 _papi_hwi_shutdown_thread( ThreadInfo_t * thread ) 00419 { 00420 int retval = PAPI_OK; 00421 unsigned long tid; 00422 int i, failure = 0; 00423 00424 if ( _papi_hwi_thread_id_fn ) 00425 tid = ( *_papi_hwi_thread_id_fn ) ( ); 00426 else 00427 tid = ( unsigned long ) getpid( ); 00428 00429 THRDBG("Want to shutdown thread %ld, alloc %ld, our_tid: %ld\n", 00430 thread->tid, 00431 thread->allocator_tid, 00432 tid); 00433 00434 if ((thread->tid==tid) || ( thread->allocator_tid == tid )) { 00435 00436 _papi_hwi_thread_free_eventsets(tid); 00437 00438 remove_thread( thread ); 00439 THRDBG( "Shutting down thread %ld at %p\n", thread->tid, thread ); 00440 for( i = 0; i < papi_num_components; i++ ) { 00441 if (_papi_hwd[i]->cmp_info.disabled) continue; 00442 retval = _papi_hwd[i]->shutdown_thread( thread->context[i]); 00443 if ( retval != PAPI_OK ) failure = retval; 00444 } 00445 free_thread( &thread ); 00446 return ( failure ); 00447 } 00448 00449 THRDBG( "Skipping shutdown thread %ld at %p, thread %ld not allocator!\n", 00450 thread->tid, thread, tid ); 00451 return PAPI_EBUG; 00452 } 00453 00454 /* THESE MUST BE CALLED WITH A GLOBAL LOCK */ 00455 00456 int 00457 _papi_hwi_shutdown_global_threads( void ) 00458 { 00459 int err,num_threads,i; 00460 ThreadInfo_t *tmp,*next; 00461 unsigned long our_tid; 00462 00463 tmp = _papi_hwi_lookup_thread( 0 ); 00464 00465 if ( tmp == NULL ) { 00466 THRDBG( "Did not find my thread for shutdown!\n" ); 00467 err = PAPI_EBUG; 00468 } 00469 else { 00470 our_tid=tmp->tid; 00471 00472 THRDBG("Shutting down %ld\n",our_tid); 00473 00474 err = _papi_hwi_shutdown_thread( tmp ); 00475 00476 00477 /* count threads */ 00478 tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head; 00479 num_threads=0; 00480 while(tmp!=NULL) { 00481 num_threads++; 00482 if (tmp->next==_papi_hwi_thread_head) break; 00483 tmp=tmp->next; 00484 } 00485 00486 /* Shut down all threads allocated by this thread */ 00487 /* Urgh it's a circular list where we removed in the loop */ 00488 /* so the only sane way to do it is get a count in advance */ 00489 tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head; 00490 00491 for(i=0;i<num_threads;i++) { 00492 00493 next=tmp->next; 00494 00495 THRDBG("looking at #%d %ld our_tid: %ld alloc_tid: %ld\n", 00496 i,tmp->tid,our_tid,tmp->allocator_tid); 00497 00498 if (tmp->allocator_tid==our_tid) { 00499 THRDBG("Also removing thread %ld\n",tmp->tid); 00500 err = _papi_hwi_shutdown_thread( tmp ); 00501 } 00502 00503 tmp=next; 00504 00505 } 00506 } 00507 00508 00509 #ifdef DEBUG 00510 if ( ISLEVEL( DEBUG_THREADS ) ) { 00511 if ( _papi_hwi_thread_head ) { 00512 THRDBG( "Thread head %p still exists!\n", _papi_hwi_thread_head ); 00513 } 00514 } 00515 #endif 00516 00517 #if defined(HAVE_THREAD_LOCAL_STORAGE) 00518 _papi_hwi_my_thread = NULL; 00519 #endif 00520 _papi_hwi_thread_head = NULL; 00521 _papi_hwi_thread_id_fn = NULL; 00522 #if defined(ANY_THREAD_GETS_SIGNAL) 00523 _papi_hwi_thread_kill_fn = NULL; 00524 #endif 00525 00526 return err; 00527 } 00528 00529 int 00530 _papi_hwi_init_global_threads( void ) 00531 { 00532 int retval; 00533 ThreadInfo_t *tmp; 00534 00535 _papi_hwi_lock( GLOBAL_LOCK ); 00536 00537 #if defined(HAVE_THREAD_LOCAL_STORAGE) 00538 _papi_hwi_my_thread = NULL; 00539 #endif 00540 _papi_hwi_thread_head = NULL; 00541 _papi_hwi_thread_id_fn = NULL; 00542 #if defined(ANY_THREAD_GETS_SIGNAL) 00543 _papi_hwi_thread_kill_fn = NULL; 00544 #endif 00545 00546 retval = _papi_hwi_initialize_thread( &tmp , 0); 00547 if ( retval == PAPI_OK ) { 00548 retval = lookup_and_set_thread_symbols( ); 00549 } 00550 00551 _papi_hwi_unlock( GLOBAL_LOCK ); 00552 00553 return ( retval ); 00554 } 00555 00556 int 00557 _papi_hwi_gather_all_thrspec_data( int tag, PAPI_all_thr_spec_t * where ) 00558 { 00559 int didsomething = 0; 00560 ThreadInfo_t *foo = NULL; 00561 00562 _papi_hwi_lock( THREADS_LOCK ); 00563 00564 for ( foo = ( ThreadInfo_t * ) _papi_hwi_thread_head; foo != NULL; 00565 foo = foo->next ) { 00566 /* If we want thread ID's */ 00567 if ( where->id ) 00568 memcpy( &where->id[didsomething], &foo->tid, 00569 sizeof ( where->id[didsomething] ) ); 00570 00571 /* If we want data pointers */ 00572 if ( where->data ) 00573 where->data[didsomething] = foo->thread_storage[tag]; 00574 00575 didsomething++; 00576 00577 if ( ( where->id ) || ( where->data ) ) { 00578 if ( didsomething >= where->num ) 00579 break; 00580 } 00581 00582 if ( foo->next == _papi_hwi_thread_head ) 00583 break; 00584 } 00585 00586 where->num = didsomething; 00587 _papi_hwi_unlock( THREADS_LOCK ); 00588 00589 return ( PAPI_OK ); 00590 00591 }