PAPI  5.1.0.2
threads.c
Go to the documentation of this file.
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 #else
00221     ( void ) tid;
00222 #endif
00223 }
00224 
00225 static int
00226 remove_thread( ThreadInfo_t * entry )
00227 {
00228     ThreadInfo_t *tmp = NULL, *prev = NULL;
00229 
00230     _papi_hwi_lock( THREADS_LOCK );
00231 
00232     THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n",
00233             _papi_hwi_thread_head->tid, _papi_hwi_thread_head );
00234 
00235     /* Find the preceding element and the matched element,
00236        short circuit if we've seen the head twice */
00237 
00238     for ( tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head;
00239           ( entry != tmp ) || ( prev == NULL ); tmp = tmp->next ) {
00240         prev = tmp;
00241     }
00242 
00243     if ( tmp != entry ) {
00244         THRDBG( "Thread %ld at %p was not found in the thread list!\n",
00245                 entry->tid, entry );
00246         return ( PAPI_EBUG );
00247     }
00248 
00249     /* Only 1 element in list */
00250 
00251     if ( prev == tmp ) {
00252         _papi_hwi_thread_head = NULL;
00253         tmp->next = NULL;
00254         THRDBG( "_papi_hwi_thread_head now NULL\n" );
00255     } else {
00256         prev->next = tmp->next;
00257         /* If we're removing the head, better advance it! */
00258         if ( _papi_hwi_thread_head == tmp ) {
00259             _papi_hwi_thread_head = tmp->next;
00260             THRDBG( "_papi_hwi_thread_head now thread %ld at %p\n",
00261                     _papi_hwi_thread_head->tid, _papi_hwi_thread_head );
00262         }
00263         THRDBG( "Removed thread %p from list\n", tmp );
00264     }
00265 
00266     _papi_hwi_unlock( THREADS_LOCK );
00267 
00268 #if defined(HAVE_THREAD_LOCAL_STORAGE)
00269     _papi_hwi_my_thread = NULL;
00270     THRDBG( "TLS for thread %ld is now %p\n", entry->tid,
00271             _papi_hwi_my_thread );
00272 #endif
00273 
00274     return PAPI_OK;
00275 }
00276 
00277 int
00278 _papi_hwi_initialize_thread( ThreadInfo_t ** dest, int tid )
00279 {
00280     int retval;
00281     ThreadInfo_t *thread;
00282     int i;
00283 
00284     if ( ( thread = allocate_thread( tid  ) ) == NULL ) {
00285         *dest = NULL;
00286         return PAPI_ENOMEM;
00287     }
00288 
00289     /* Call the component to fill in anything special. */
00290 
00291     for ( i = 0; i < papi_num_components; i++ ) {
00292         if (_papi_hwd[i]->cmp_info.disabled) continue;
00293         retval = _papi_hwd[i]->init_thread( thread->context[i] );
00294         if ( retval ) {
00295            free_thread( &thread );
00296            *dest = NULL;
00297            return retval;
00298         }
00299     }
00300 
00301     insert_thread( thread, tid );
00302 
00303     *dest = thread;
00304     return PAPI_OK;
00305 }
00306 
00307 #if defined(ANY_THREAD_GETS_SIGNAL)
00308 
00309 /* This is ONLY defined for systems that enable ANY_THREAD_GETS_SIGNAL
00310    since we must forward signals sent to non-PAPI threads.
00311 
00312    This is NOT compatible with thread local storage, since to broadcast
00313    the signal, we need a list of threads. */
00314 
00315 int
00316 _papi_hwi_broadcast_signal( unsigned int mytid )
00317 {
00318     int i, retval, didsomething = 0;
00319     volatile ThreadInfo_t *foo = NULL;
00320 
00321     _papi_hwi_lock( THREADS_LOCK );
00322 
00323     for ( foo = _papi_hwi_thread_head; foo != NULL; foo = foo->next ) {
00324         /* xxxx Should this be hardcoded to index 0 or walk the list or what? */
00325         for ( i = 0; i < papi_num_components; i++ ) {
00326             if ( ( foo->tid != mytid ) && ( foo->running_eventset[i] ) &&
00327                  ( foo->running_eventset[i]->
00328                    state & ( PAPI_OVERFLOWING | PAPI_MULTIPLEXING ) ) ) {
00329                 /* xxxx mpx_info inside _papi_mdi_t _papi_hwi_system_info is commented out.
00330                    See papi_internal.h for details. The multiplex_timer_sig value is now part of that structure */
00331               THRDBG("Thread %ld sending signal %d to thread %ld\n",mytid,foo->tid,
00332                   (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig));
00333               retval = (*_papi_hwi_thread_kill_fn)(foo->tid, 
00334                   (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig));
00335               if (retval != 0)
00336                 return(PAPI_EMISC);
00337             }
00338         }
00339         if ( foo->next == _papi_hwi_thread_head )
00340           break;
00341     }
00342     _papi_hwi_unlock( THREADS_LOCK );
00343 
00344     return ( PAPI_OK );
00345 }
00346 #endif
00347 
00348 /* This is undefined for systems that enable ANY_THREAD_GETS_SIGNAL
00349    since we always must enable threads for safety. */
00350 
00351 int
00352 _papi_hwi_set_thread_id_fn( unsigned long ( *id_fn ) ( void ) )
00353 {
00354 #if !defined(ANY_THREAD_GETS_SIGNAL)
00355     /* Check for multiple threads still in the list, if so, we can't change it */
00356 
00357     if ( _papi_hwi_thread_head->next != _papi_hwi_thread_head )
00358         return ( PAPI_EINVAL );
00359 
00360     /* We can't change the thread id function from one to another, 
00361        only NULL to non-NULL and vice versa. */
00362 
00363     if ( ( id_fn != NULL ) && ( _papi_hwi_thread_id_fn != NULL ) )
00364         return ( PAPI_EINVAL );
00365 
00366     _papi_hwi_thread_id_fn = id_fn;
00367 
00368     THRDBG( "Set new thread id function to %p\n", id_fn );
00369 
00370     if ( id_fn )
00371         _papi_hwi_thread_head->tid = ( *_papi_hwi_thread_id_fn ) (  );
00372     else
00373         _papi_hwi_thread_head->tid = ( unsigned long ) getpid(  );
00374 
00375     THRDBG( "New master tid is %ld\n", _papi_hwi_thread_head->tid );
00376 #else
00377     THRDBG( "Skipping set of thread id function\n" );
00378 #endif
00379 
00380     return PAPI_OK;
00381 }
00382 
00383 
00384 static int _papi_hwi_thread_free_eventsets(long tid) {
00385 
00386    EventSetInfo_t *ESI;
00387    ThreadInfo_t *master;
00388    DynamicArray_t *map = &_papi_hwi_system_info.global_eventset_map;
00389    int i;
00390 
00391    master = _papi_hwi_lookup_thread( tid );
00392 
00393    _papi_hwi_lock( INTERNAL_LOCK );
00394 
00395    for( i = 0; i < map->totalSlots; i++ ) {
00396       ESI = map->dataSlotArray[i];
00397       if ( ( ESI ) && (ESI->master!=NULL) ) {
00398 
00399      if ( ESI->master == master ) {
00400         THRDBG("Attempting to remove %d from tid %ld\n",ESI->EventSetIndex,tid);
00401 
00402         /* Code copied from _papi_hwi_remove_EventSet(ESI);      */
00403         _papi_hwi_free_EventSet( ESI );
00404         map->dataSlotArray[i] = NULL;
00405         map->availSlots++;
00406         map->fullSlots--;
00407      } 
00408       }
00409    }
00410 
00411    _papi_hwi_unlock( INTERNAL_LOCK );
00412 
00413    return PAPI_OK;
00414 }
00415 
00416 
00417 
00418 
00419 int
00420 _papi_hwi_shutdown_thread( ThreadInfo_t * thread )
00421 {
00422     int retval = PAPI_OK;
00423     unsigned long tid;
00424     int i, failure = 0;
00425 
00426     if ( _papi_hwi_thread_id_fn )
00427         tid = ( *_papi_hwi_thread_id_fn ) (  );
00428     else
00429         tid = ( unsigned long ) getpid(  );
00430 
00431         THRDBG("Want to shutdown thread %ld, alloc %ld, our_tid: %ld\n",
00432            thread->tid,
00433            thread->allocator_tid,
00434            tid);
00435 
00436     if ((thread->tid==tid) || ( thread->allocator_tid == tid )) {
00437 
00438                 _papi_hwi_thread_free_eventsets(tid);
00439 
00440         remove_thread( thread );
00441         THRDBG( "Shutting down thread %ld at %p\n", thread->tid, thread );
00442         for( i = 0; i < papi_num_components; i++ ) {
00443            if (_papi_hwd[i]->cmp_info.disabled) continue;
00444            retval = _papi_hwd[i]->shutdown_thread( thread->context[i]);
00445            if ( retval != PAPI_OK ) failure = retval;
00446         }
00447         free_thread( &thread );
00448         return ( failure );
00449     }
00450 
00451     THRDBG( "Skipping shutdown thread %ld at %p, thread %ld not allocator!\n",
00452             thread->tid, thread, tid );
00453     return PAPI_EBUG;
00454 }
00455 
00456 /* THESE MUST BE CALLED WITH A GLOBAL LOCK */
00457 
00458 int
00459 _papi_hwi_shutdown_global_threads( void )
00460 {
00461         int err,num_threads,i;
00462     ThreadInfo_t *tmp,*next;
00463     unsigned long our_tid;
00464 
00465     tmp = _papi_hwi_lookup_thread( 0 );
00466 
00467     if ( tmp == NULL ) {
00468        THRDBG( "Did not find my thread for shutdown!\n" );
00469        err = PAPI_EBUG;
00470     }
00471     else {
00472        our_tid=tmp->tid;
00473 
00474        THRDBG("Shutting down %ld\n",our_tid);
00475 
00476        err = _papi_hwi_shutdown_thread( tmp );
00477 
00478 
00479        /* count threads */
00480        tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head;
00481        num_threads=0;
00482        while(tmp!=NULL) {
00483           num_threads++;
00484           if (tmp->next==_papi_hwi_thread_head) break;
00485           tmp=tmp->next;
00486        }
00487 
00488        /* Shut down all threads allocated by this thread */
00489        /* Urgh it's a circular list where we removed in the loop  */
00490        /* so the only sane way to do it is get a count in advance */
00491        tmp = ( ThreadInfo_t * ) _papi_hwi_thread_head;
00492 
00493        for(i=0;i<num_threads;i++) {
00494 
00495           next=tmp->next;
00496 
00497           THRDBG("looking at #%d %ld our_tid: %ld alloc_tid: %ld\n",
00498              i,tmp->tid,our_tid,tmp->allocator_tid);
00499         
00500           if (tmp->allocator_tid==our_tid) {
00501          THRDBG("Also removing thread %ld\n",tmp->tid);
00502              err = _papi_hwi_shutdown_thread( tmp );
00503           }
00504   
00505           tmp=next;
00506 
00507        }
00508     }
00509 
00510 
00511 #ifdef DEBUG
00512     if ( ISLEVEL( DEBUG_THREADS ) ) {
00513         if ( _papi_hwi_thread_head ) {
00514             THRDBG( "Thread head %p still exists!\n", _papi_hwi_thread_head );
00515         }
00516     }
00517 #endif
00518 
00519 #if defined(HAVE_THREAD_LOCAL_STORAGE)
00520     _papi_hwi_my_thread = NULL;
00521 #endif
00522     _papi_hwi_thread_head = NULL;
00523     _papi_hwi_thread_id_fn = NULL;
00524 #if defined(ANY_THREAD_GETS_SIGNAL)
00525     _papi_hwi_thread_kill_fn = NULL;
00526 #endif
00527 
00528     return err;
00529 }
00530 
00531 int
00532 _papi_hwi_init_global_threads( void )
00533 {
00534     int retval;
00535     ThreadInfo_t *tmp;
00536 
00537     _papi_hwi_lock( GLOBAL_LOCK );
00538 
00539 #if defined(HAVE_THREAD_LOCAL_STORAGE)
00540     _papi_hwi_my_thread = NULL;
00541 #endif
00542     _papi_hwi_thread_head = NULL;
00543     _papi_hwi_thread_id_fn = NULL;
00544 #if defined(ANY_THREAD_GETS_SIGNAL)
00545     _papi_hwi_thread_kill_fn = NULL;
00546 #endif
00547 
00548     retval = _papi_hwi_initialize_thread( &tmp , 0);
00549     if ( retval == PAPI_OK ) {
00550        retval = lookup_and_set_thread_symbols(  );
00551     }
00552 
00553     _papi_hwi_unlock( GLOBAL_LOCK );
00554 
00555     return ( retval );
00556 }
00557 
00558 int
00559 _papi_hwi_gather_all_thrspec_data( int tag, PAPI_all_thr_spec_t * where )
00560 {
00561     int didsomething = 0;
00562     ThreadInfo_t *foo = NULL;
00563 
00564     _papi_hwi_lock( THREADS_LOCK );
00565 
00566     for ( foo = ( ThreadInfo_t * ) _papi_hwi_thread_head; foo != NULL;
00567           foo = foo->next ) {
00568         /* If we want thread ID's */
00569         if ( where->id )
00570             memcpy( &where->id[didsomething], &foo->tid,
00571                     sizeof ( where->id[didsomething] ) );
00572 
00573         /* If we want data pointers */
00574         if ( where->data )
00575             where->data[didsomething] = foo->thread_storage[tag];
00576 
00577         didsomething++;
00578 
00579         if ( ( where->id ) || ( where->data ) ) {
00580             if ( didsomething >= where->num )
00581                 break;
00582         }
00583 
00584         if ( foo->next == _papi_hwi_thread_head )
00585             break;
00586     }
00587 
00588     where->num = didsomething;
00589     _papi_hwi_unlock( THREADS_LOCK );
00590 
00591     return ( PAPI_OK );
00592 
00593 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines