PAPI 7.1.0.0
Loading...
Searching...
No Matches
threads.c
Go to the documentation of this file.
1/****************************/
2/* THIS IS OPEN SOURCE CODE */
3/****************************/
4
5/*
6* File: threads.c
7* Author: Philip Mucci
8* mucci@cs.utk.edu
9* Mods: Kevin London
10* london@cs.utk.edu
11*/
12
13/* This file contains thread allocation and bookkeeping functions */
14
15#include "papi.h"
16#include "papi_internal.h"
17#include "papi_vector.h"
18#include "papi_memory.h"
19#include <string.h>
20#include <unistd.h>
21
22/*****************/
23/* BEGIN GLOBALS */
24/*****************/
25
26/* The following globals get initialized and cleared by:
27 extern int _papi_hwi_init_global_threads(void);
28 extern int _papi_hwi_shutdown_thread(ThreadInfo_t *thread); */
29
30/* list of threads, gets initialized to master process with TID of getpid() */
31
33
34/* If we have TLS, this variable ALWAYS points to our thread descriptor. It's like magic! */
35
36#if defined(HAVE_THREAD_LOCAL_STORAGE)
38#endif
39
40/* Function that returns and unsigned long thread identifier */
41
42unsigned long ( *_papi_hwi_thread_id_fn ) ( void );
43
44/* Function that sends a signal to other threads */
45
46#ifdef ANY_THREAD_GETS_SIGNAL
48#endif
49
50/*****************/
51/* END GLOBALS */
52/*****************/
53
54static int
56{
57#if defined(ANY_THREAD_GETS_SIGNAL)
58 int retval;
59 char *error_ptc = NULL, *error_ptk = NULL;
60 void *symbol_ptc = NULL, *symbol_ptk = NULL, *handle = NULL;
61
62 handle = dlopen( NULL, RTLD_LAZY );
63 if ( handle == NULL ) {
64 PAPIERROR( "Error from dlopen(NULL, RTLD_LAZY): %d %s", errno,
65 dlerror( ) );
66 return ( PAPI_ESYS );
67 }
68
69 symbol_ptc = dlsym( handle, "pthread_self" );
70 if ( symbol_ptc == NULL ) {
71 error_ptc = dlerror( );
72 THRDBG( "dlsym(%p,pthread_self) returned NULL: %s\n",
73 ( error_ptc ? error_ptc : "No error, NULL symbol!" ) );
74 }
75
76 symbol_ptk = dlsym( handle, "pthread_kill" );
77 if ( symbol_ptk == NULL ) {
78 error_ptk = dlerror( );
79 THRDBG( "dlsym(%p,pthread_kill) returned NULL: %s\n",
80 ( error_ptk ? error_ptk : "No error, NULL symbol!" ) );
81 }
82
83 dlclose( handle );
84
87 return ( PAPI_EMISC );
88
89 _papi_hwi_thread_kill_fn = ( int ( * )( int, int ) ) symbol_ptk;
90 _papi_hwi_thread_id_fn = ( unsigned long ( * )( void ) ) symbol_ptc;
91#endif
92 return ( PAPI_OK );
93}
94
95static ThreadInfo_t *
97{
99 int i;
100
101 /* The Thread EventSet is special. It is not in the EventSet list, but is pointed
102 to by each EventSet of that particular thread. */
103
104 thread = ( ThreadInfo_t * ) papi_malloc( sizeof ( ThreadInfo_t ) );
105 if ( thread == NULL )
106 return ( NULL );
107 memset( thread, 0x00, sizeof ( ThreadInfo_t ) );
108
109 thread->context =
110 ( hwd_context_t ** ) papi_malloc( sizeof ( hwd_context_t * ) *
112 if ( !thread->context ) {
113 papi_free( thread );
114 return ( NULL );
115 }
116
117 thread->running_eventset =
118 ( EventSetInfo_t ** ) papi_malloc( sizeof ( EventSetInfo_t * ) *
120 if ( !thread->running_eventset ) {
121 papi_free( thread->context );
122 papi_free( thread );
123 return ( NULL );
124 }
125
126 for ( i = 0; i < papi_num_components; i++ ) {
127 thread->context[i] =
128 ( void * ) papi_malloc( ( size_t ) _papi_hwd[i]->size.context );
129 thread->running_eventset[i] = NULL;
130 if ( thread->context[i] == NULL ) {
131 for ( i--; i >= 0; i-- )
132 papi_free( thread->context[i] );
133 papi_free( thread->context );
134 papi_free( thread );
135 return ( NULL );
136 }
137 memset( thread->context[i], 0x00,
138 ( size_t ) _papi_hwd[i]->size.context );
139 }
140
142 thread->tid = ( *_papi_hwi_thread_id_fn ) ( );
143 }
144 else {
145 thread->tid = ( unsigned long ) getpid( );
146 }
147
148 thread->allocator_tid=thread->tid;
149
150 if (tid == 0 ) {
151 }
152 else {
153 thread->tid=tid;
154 }
155
156 THRDBG( "Allocated thread %ld at %p, allocator: %ld\n", thread->tid,
157 thread,
158 thread->allocator_tid );
159
160 return thread;
161}
162
163static void
165{
166 int i;
167 THRDBG( "Freeing thread %ld at %p\n", ( *thread )->tid, *thread );
168
169 for ( i = 0; i < papi_num_components; i++ ) {
170 if ( ( *thread )->context[i] )
171 papi_free( ( *thread )->context[i] );
172 }
173
174 if ( ( *thread )->context )
175 papi_free( ( *thread )->context );
176
177 if ( ( *thread )->running_eventset )
178 papi_free( ( *thread )->running_eventset );
179
180 memset( *thread, 0x00, sizeof ( ThreadInfo_t ) );
181 papi_free( *thread );
182 *thread = NULL;
183}
184
185static void
186insert_thread( ThreadInfo_t * entry, int tid )
187{
189
190 if ( _papi_hwi_thread_head == NULL ) { /* 0 elements */
191 THRDBG( "_papi_hwi_thread_head is NULL\n" );
192 entry->next = entry;
193 } else if ( _papi_hwi_thread_head->next == _papi_hwi_thread_head ) { /* 1 elements */
194 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n",
198 } else { /* 2+ elements */
199
200 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n",
204 }
205
206 _papi_hwi_thread_head = entry;
207
208 THRDBG( "_papi_hwi_thread_head now thread %ld at %p\n",
210
212
213#if defined(HAVE_THREAD_LOCAL_STORAGE)
214 /* Don't set the current local thread if we are a fake attach thread */
215 if (tid==0) {
216 _papi_hwi_my_thread = entry;
217 THRDBG( "TLS for thread %ld is now %p\n", entry->tid,
219 }
220#else
221 ( void ) tid;
222#endif
223}
224
225static int
227{
228 ThreadInfo_t *tmp = NULL, *prev = NULL;
229
231
232 THRDBG( "_papi_hwi_thread_head was thread %ld at %p\n",
234
235 /* Find the preceding element and the matched element,
236 short circuit if we've seen the head twice */
237
239 ( entry != tmp ) || ( prev == NULL ); tmp = tmp->next ) {
240 prev = tmp;
241 }
242
243 if ( tmp != entry ) {
244 THRDBG( "Thread %ld at %p was not found in the thread list!\n",
245 entry->tid, entry );
246 return ( PAPI_EBUG );
247 }
248
249 /* Only 1 element in list */
250
251 if ( prev == tmp ) {
253 tmp->next = NULL;
254 THRDBG( "_papi_hwi_thread_head now NULL\n" );
255 } else {
256 prev->next = tmp->next;
257 /* If we're removing the head, better advance it! */
258 if ( _papi_hwi_thread_head == tmp ) {
260 THRDBG( "_papi_hwi_thread_head now thread %ld at %p\n",
262 }
263 THRDBG( "Removed thread %p from list\n", tmp );
264 }
265
267
268#if defined(HAVE_THREAD_LOCAL_STORAGE)
269 _papi_hwi_my_thread = NULL;
270 THRDBG( "TLS for thread %ld is now %p\n", entry->tid,
272#endif
273
274 return PAPI_OK;
275}
276
277int
279{
280 int retval;
282 int i;
283
284 if ( ( thread = allocate_thread( tid ) ) == NULL ) {
285 *dest = NULL;
286 return PAPI_ENOMEM;
287 }
288
289 /* init event memory variables, used by papi_internal.c */
290 thread->tls_papi_event_code = -1;
291 thread->tls_papi_event_code_changed = -1;
292
293 /* Call the component to fill in anything special. */
294
295 for ( i = 0; i < papi_num_components; i++ ) {
296 if (_papi_hwd[i]->cmp_info.disabled &&
297 _papi_hwd[i]->cmp_info.disabled != PAPI_EDELAY_INIT)
298 continue;
299 retval = _papi_hwd[i]->init_thread( thread->context[i] );
300 if ( retval ) {
302 *dest = NULL;
303 return retval;
304 }
305 }
306
307 insert_thread( thread, tid );
308
309 *dest = thread;
310 return PAPI_OK;
311}
312
313#if defined(ANY_THREAD_GETS_SIGNAL)
314
315/* This is ONLY defined for systems that enable ANY_THREAD_GETS_SIGNAL
316 since we must forward signals sent to non-PAPI threads.
317
318 This is NOT compatible with thread local storage, since to broadcast
319 the signal, we need a list of threads. */
320
321int
322_papi_hwi_broadcast_signal( unsigned int mytid )
323{
324 int i, retval, didsomething = 0;
325 volatile ThreadInfo_t *foo = NULL;
326
328
329 for ( foo = _papi_hwi_thread_head; foo != NULL; foo = foo->next ) {
330 /* xxxx Should this be hardcoded to index 0 or walk the list or what? */
331 for ( i = 0; i < papi_num_components; i++ ) {
332 if ( ( foo->tid != mytid ) && ( foo->running_eventset[i] ) &&
333 ( foo->running_eventset[i]->
335 /* xxxx mpx_info inside _papi_mdi_t _papi_hwi_system_info is commented out.
336 See papi_internal.h for details. The multiplex_timer_sig value is now part of that structure */
337 THRDBG("Thread %ld sending signal %d to thread %ld\n",mytid,foo->tid,
338 (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig));
339 retval = (*_papi_hwi_thread_kill_fn)(foo->tid,
340 (foo->running_eventset[i]->state & PAPI_OVERFLOWING ? _papi_hwd[i]->cmp_info.hardware_intr_sig : _papi_os_info.itimer_sig));
341 if (retval != 0)
342 return(PAPI_EMISC);
343 }
344 }
345 if ( foo->next == _papi_hwi_thread_head )
346 break;
347 }
349
350 return ( PAPI_OK );
351}
352#endif
353
354/* This is undefined for systems that enable ANY_THREAD_GETS_SIGNAL
355 since we always must enable threads for safety. */
356
357int
358_papi_hwi_set_thread_id_fn( unsigned long ( *id_fn ) ( void ) )
359{
360#if !defined(ANY_THREAD_GETS_SIGNAL)
361 /* Check for multiple threads still in the list, if so, we can't change it */
362
364 return ( PAPI_EINVAL );
365
366 /* We can't change the thread id function from one to another,
367 only NULL to non-NULL and vice versa. */
368
369 if ( ( id_fn != NULL ) && ( _papi_hwi_thread_id_fn != NULL ) )
370 return ( PAPI_EINVAL );
371
373
374 THRDBG( "Set new thread id function to %p\n", id_fn );
375
376 if ( id_fn )
377 _papi_hwi_thread_head->tid = ( *_papi_hwi_thread_id_fn ) ( );
378 else
379 _papi_hwi_thread_head->tid = ( unsigned long ) getpid( );
380
381 THRDBG( "New master tid is %ld\n", _papi_hwi_thread_head->tid );
382#else
383 THRDBG( "Skipping set of thread id function\n" );
384#endif
385
386 return PAPI_OK;
387}
388
389
391
392 EventSetInfo_t *ESI;
393 ThreadInfo_t *master;
395 int i;
396
397 master = _papi_hwi_lookup_thread( tid );
398
400
401 for( i = 0; i < map->totalSlots; i++ ) {
402 ESI = map->dataSlotArray[i];
403 if ( ( ESI ) && (ESI->master!=NULL) ) {
404
405 if ( ESI->master == master ) {
406 THRDBG("Attempting to remove %d from tid %ld\n",ESI->EventSetIndex,tid);
407
408 /* Code copied from _papi_hwi_remove_EventSet(ESI); */
410 map->dataSlotArray[i] = NULL;
411 map->availSlots++;
412 map->fullSlots--;
413 }
414 }
415 }
416
418
419 return PAPI_OK;
420}
421
422
423int
425{
426 int retval = PAPI_OK;
427 unsigned long tid;
428 int i, failure = 0;
429
430 /* Clear event memory variables */
431 thread->tls_papi_event_code = -1;
432 thread->tls_papi_event_code_changed = -1;
433
434 /* Get thread id */
436 tid = ( *_papi_hwi_thread_id_fn ) ( );
437 else
438 tid = ( unsigned long ) getpid( );
439
440 THRDBG("Want to shutdown thread %ld, alloc %ld, our_tid: %ld\n",
441 thread->tid,
442 thread->allocator_tid,
443 tid);
444
445 if ((thread->tid==tid) || ( thread->allocator_tid == tid ) || force_shutdown) {
446
448
450 THRDBG( "Shutting down thread %ld at %p\n", thread->tid, thread );
451 for( i = 0; i < papi_num_components; i++ ) {
452 if (_papi_hwd[i]->cmp_info.disabled &&
453 _papi_hwd[i]->cmp_info.disabled != PAPI_EDELAY_INIT)
454 continue;
455 retval = _papi_hwd[i]->shutdown_thread( thread->context[i]);
456 if ( retval != PAPI_OK ) failure = retval;
457 }
459 return ( failure );
460 }
461
462 THRDBG( "Skipping shutdown thread %ld at %p, thread %ld not allocator!\n",
463 thread->tid, thread, tid );
464 return PAPI_EBUG;
465}
466
467/* THESE MUST BE CALLED WITH A GLOBAL LOCK */
468
469int
471{
472 int err,num_threads,i;
473 ThreadInfo_t *tmp,*next;
474 unsigned long our_tid;
475
477
478 if ( tmp == NULL ) {
479 THRDBG( "Did not find my thread for shutdown!\n" );
480 err = PAPI_EBUG;
481 }
482 else {
483 our_tid=tmp->tid;
484 (void)our_tid;
485
486 THRDBG("Shutting down %ld\n",our_tid);
487
488 err = _papi_hwi_shutdown_thread( tmp, 1 );
489
490 /* count threads */
492 num_threads=0;
493 while(tmp!=NULL) {
494 num_threads++;
495 if (tmp->next==_papi_hwi_thread_head) break;
496 tmp=tmp->next;
497 }
498
499 /* Shut down all threads allocated by this thread */
500 /* Urgh it's a circular list where we removed in the loop */
501 /* so the only sane way to do it is get a count in advance */
503
504 for(i=0;i<num_threads;i++) {
505
506 next=tmp->next;
507
508 THRDBG("looking at #%d %ld our_tid: %ld alloc_tid: %ld\n",
509 i,tmp->tid,our_tid,tmp->allocator_tid);
510
511 THRDBG("Also removing thread %ld\n",tmp->tid);
512 err = _papi_hwi_shutdown_thread( tmp, 1 );
513
514 tmp=next;
515
516 }
517 }
518
519
520#ifdef DEBUG
521 if ( ISLEVEL( DEBUG_THREADS ) ) {
522 if ( _papi_hwi_thread_head ) {
523 THRDBG( "Thread head %p still exists!\n", _papi_hwi_thread_head );
524 }
525 }
526#endif
527
528#if defined(HAVE_THREAD_LOCAL_STORAGE)
529 _papi_hwi_my_thread = NULL;
530#endif
533#if defined(ANY_THREAD_GETS_SIGNAL)
535#endif
536
537 return err;
538}
539
540int
542{
543 int retval;
545
547
548#if defined(HAVE_THREAD_LOCAL_STORAGE)
549 _papi_hwi_my_thread = NULL;
550#endif
553#if defined(ANY_THREAD_GETS_SIGNAL)
555#endif
556
558 if ( retval == PAPI_OK ) {
560 }
561
563
564 return ( retval );
565}
566
567int
569{
570 int didsomething = 0;
571 ThreadInfo_t *foo = NULL;
572
574
575 for ( foo = ( ThreadInfo_t * ) _papi_hwi_thread_head; foo != NULL;
576 foo = foo->next ) {
577 /* If we want thread ID's */
578 if ( where->id )
579 memcpy( &where->id[didsomething], &foo->tid,
580 sizeof ( where->id[didsomething] ) );
581
582 /* If we want data pointers */
583 if ( where->data )
584 where->data[didsomething] = foo->thread_storage[tag];
585
586 didsomething++;
587
588 if ( ( where->id ) || ( where->data ) ) {
589 if ( didsomething >= where->num )
590 break;
591 }
592
593 if ( foo->next == _papi_hwi_thread_head )
594 break;
595 }
596
597 where->num = didsomething;
599
600 return ( PAPI_OK );
601
602}
603
604#if defined(__NR_gettid) && !defined(HAVE_GETTID)
605 #include <syscall.h>
606 #include <unistd.h>
607 unsigned long _papi_gettid(void)
608 {
609 return (unsigned long)(syscall(__NR_gettid));
610 }
611#elif defined(HAVE_GETTID)
612 #include <sys/types.h>
613 unsigned long _papi_gettid(void)
614 {
615 return (unsigned long)(gettid());
616 }
617#elif defined(HAVE_SYSCALL_GETTID)
618 #include <syscall.h>
619 #include <sys/types.h>
620 unsigned long _papi_gettid(void)
621 {
622 return (unsigned long)(syscall(SYS_gettid));
623 }
624#else
625 #include <sys/types.h>
626 #include <unistd.h>
627 /* Fall-back on getpid for tid if not available. */
628 unsigned long _papi_gettid(void)
629 {
630 return (unsigned long)(getpid());
631 }
632#endif
633
634unsigned long _papi_getpid(void)
635{
636 return (unsigned long) getpid();
637}
static papi_handle_t handle
Definition: Gamum.c:21
double tmp
int i
PAPI_os_info_t _papi_os_info
Definition: aix.c:1210
int errno
struct papi_vectors * _papi_hwd[]
#define PAPI_EBUG
Definition: f90papi.h:176
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_EDELAY_INIT
Definition: f90papi.h:271
#define PAPI_EINVAL
Definition: f90papi.h:115
#define PAPI_MULTIPLEXING
Definition: f90papi.h:148
#define PAPI_EMISC
Definition: f90papi.h:122
#define PAPI_ESYS
Definition: f90papi.h:136
#define PAPI_OVERFLOWING
Definition: f90papi.h:240
#define PAPI_ENOMEM
Definition: f90papi.h:16
static int num_threads
void * thread(void *arg)
Definition: kufrin.c:38
Return codes and api definitions.
#define THRDBG(format, args...)
Definition: papi_debug.h:67
#define ISLEVEL(a)
Definition: papi_debug.h:55
#define DEBUG_THREADS
Definition: papi_debug.h:30
long unsigned int size_t
bool state
Definition: papi_hl.c:155
void _papi_hwi_free_EventSet(EventSetInfo_t *ESI)
void PAPIERROR(char *format,...)
int papi_num_components
#define INTERNAL_LOCK
Definition: papi_internal.h:85
#define THREADS_LOCK
Definition: papi_internal.h:87
#define GLOBAL_LOCK
Definition: papi_internal.h:91
#define papi_free(a)
Definition: papi_memory.h:35
#define papi_malloc(a)
Definition: papi_memory.h:34
papi_mdi_t _papi_hwi_system_info
Definition: papi_internal.c:56
int
Definition: sde_internal.h:89
long long int long long
Definition: sde_internal.h:85
EventSetInfo_t ** dataSlotArray
struct _ThreadInfo * master
PAPI_thread_id_t * id
Definition: papi.h:569
void ** data
Definition: papi.h:570
EventSetInfo_t ** running_eventset
Definition: threads.h:30
unsigned long int tid
Definition: threads.h:25
void * thread_storage[PAPI_MAX_TLS]
Definition: threads.h:29
struct _ThreadInfo * next
Definition: threads.h:27
DynamicArray_t global_eventset_map
static int remove_thread(ThreadInfo_t *entry)
Definition: threads.c:226
THREAD_LOCAL_STORAGE_KEYWORD ThreadInfo_t * _papi_hwi_my_thread
Definition: threads.c:37
static void insert_thread(ThreadInfo_t *entry, int tid)
Definition: threads.c:186
int _papi_hwi_init_global_threads(void)
Definition: threads.c:541
unsigned long(* _papi_hwi_thread_id_fn)(void)
Definition: threads.c:42
int _papi_hwi_initialize_thread(ThreadInfo_t **dest, int tid)
Definition: threads.c:278
unsigned long _papi_gettid(void)
Definition: threads.c:613
unsigned long _papi_getpid(void)
Definition: threads.c:634
int _papi_hwi_shutdown_thread(ThreadInfo_t *thread, int force_shutdown)
Definition: threads.c:424
static int _papi_hwi_thread_free_eventsets(long tid)
Definition: threads.c:390
static ThreadInfo_t * allocate_thread(int tid)
Definition: threads.c:96
int _papi_hwi_set_thread_id_fn(unsigned long(*id_fn)(void))
Definition: threads.c:358
int _papi_hwi_gather_all_thrspec_data(int tag, PAPI_all_thr_spec_t *where)
Definition: threads.c:568
static int lookup_and_set_thread_symbols(void)
Definition: threads.c:55
static void free_thread(ThreadInfo_t **thread)
Definition: threads.c:164
volatile ThreadInfo_t * _papi_hwi_thread_head
Definition: threads.c:32
int _papi_hwi_shutdown_global_threads(void)
Definition: threads.c:470
inline_static ThreadInfo_t * _papi_hwi_lookup_thread(int custom_tid)
Definition: threads.h:97
int(* _papi_hwi_thread_kill_fn)(int, int)
inline_static int _papi_hwi_lock(int lck)
Definition: threads.h:69
int _papi_hwi_broadcast_signal(unsigned int mytid)
#define THREAD_LOCAL_STORAGE_KEYWORD
Definition: threads.h:16
inline_static int _papi_hwi_unlock(int lck)
Definition: threads.h:83
int retval
Definition: zero_fork.c:53