diff options
Diffstat (limited to 'src/H5TS.c')
-rw-r--r-- | src/H5TS.c | 112 |
1 files changed, 111 insertions, 1 deletions
@@ -37,6 +37,31 @@ H5TS_key_t H5TS_funcstk_key_g; H5TS_key_t H5TS_apictx_key_g; H5TS_key_t H5TS_cancel_key_g; +#ifndef H5_HAVE_WIN_THREADS + +/* An h5_tid_t is a record of a thread identifier that is + * available for reuse. + */ +struct _tid; +typedef struct _tid h5_tid_t; + +struct _tid { + h5_tid_t *next; + uint64_t id; +}; + +/* Pointer to first free thread ID record or NULL. */ +static h5_tid_t *tid_next_free = NULL; +static uint64_t tid_next_id = 0; + +/* Mutual exclusion for access to tid_next_free and tid_next_id. */ +static pthread_mutex_t tid_mtx; + +/* Key for thread-local storage of the thread ID. */ +static H5TS_key_t tid_key; + +#endif /* H5_HAVE_WIN_THREADS */ + /*-------------------------------------------------------------------------- * NAME @@ -68,6 +93,89 @@ H5TS_key_destructor(void *key_val) #ifndef H5_HAVE_WIN_THREADS +/* When a thread shuts down, put its ID record on the free list. */ +static void +tid_destructor(void *_v) +{ + h5_tid_t *tid = _v; + + if (tid == NULL) + return; + + /* XXX I can use mutexes in destructors, right? */ + /* TBD use an atomic CAS */ + pthread_mutex_lock(&tid_mtx); + tid->next = tid_next_free; + tid_next_free = tid; + pthread_mutex_unlock(&tid_mtx); +} + +/* Initialize for integer thread identifiers. */ +static void +tid_init(void) +{ + pthread_mutex_init(&tid_mtx, NULL); + pthread_key_create(&tid_key, tid_destructor); +} + +/* Return an integer identifier, ID, for the current thread satisfying the + * following properties: + * + * 1 1 <= ID <= UINT64_MAX + * 2 ID is constant over the thread's lifetime. + * 3 No two threads share an ID during their lifetimes. + * 4 A thread's ID is available for reuse as soon as it is joined. + * + * ID 0 is reserved. H5TS_thread_id() returns 0 if the library was not built + * with thread safety or if an error prevents it from assigning an ID. + */ +uint64_t +H5TS_thread_id(void) +{ + h5_tid_t *tid = pthread_getspecific(tid_key); + h5_tid_t proto_tid; + + /* An ID is already assigned. */ + if (tid != NULL) + return tid->id; + + /* An ID is *not* already assigned: reuse an ID that's on the + * free list, or else generate a new ID. + * + * Allocating memory while holding a mutex is bad form, so + * point `tid` at `proto_tid` if we need to allocate some + * memory. + */ + pthread_mutex_lock(&tid_mtx); + if ((tid = tid_next_free) != NULL) + tid_next_free = tid->next; + else if (tid_next_id != UINT64_MAX) { + tid = &proto_tid; + tid->id = ++tid_next_id; + } + pthread_mutex_unlock(&tid_mtx); + + /* If a prototype ID record was established, copy it to the heap. */ + if (tid == &proto_tid) { + if ((tid = HDmalloc(sizeof(*tid))) != NULL) + *tid = proto_tid; + } + + if (tid == NULL) + return 0; + + /* Finish initializing the ID record and set a thread-local pointer + * to it. + */ + tid->next = NULL; + if (pthread_setspecific(tid_key, tid) != 0) { + tid_destructor(tid); + return 0; + } + + return tid->id; +} + /*-------------------------------------------------------------------------- * NAME * H5TS_pthread_first_thread_init @@ -104,6 +212,9 @@ H5TS_pthread_first_thread_init(void) pthread_cond_init(&H5_g.init_lock.cond_var, NULL); H5_g.init_lock.lock_count = 0; + /* Initialize integer thread identifiers. */ + tid_init(); + /* initialize key for thread-specific error stacks */ pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor); @@ -529,4 +640,3 @@ H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata) } /* H5TS_create_thread */ #endif /* H5_HAVE_THREADSAFE */ - |