summaryrefslogtreecommitdiffstats
path: root/src/H5TS.c
diff options
context:
space:
mode:
authorDana Robinson <derobins@hdfgroup.org>2020-07-20 21:06:54 (GMT)
committerDana Robinson <derobins@hdfgroup.org>2020-07-20 21:06:54 (GMT)
commita3aedfff18d9e0f75f53a9b55ed8112bc991a26b (patch)
tree62aa1bc5c0efbcddce3cf5b8440bf616f0bed08f /src/H5TS.c
parent09c266186d68e78055ba05d509e28ffe1589a27a (diff)
downloadhdf5-a3aedfff18d9e0f75f53a9b55ed8112bc991a26b.zip
hdf5-a3aedfff18d9e0f75f53a9b55ed8112bc991a26b.tar.gz
hdf5-a3aedfff18d9e0f75f53a9b55ed8112bc991a26b.tar.bz2
Brought over thread-safety changes from develop.
Diffstat (limited to 'src/H5TS.c')
-rw-r--r--src/H5TS.c153
1 files changed, 151 insertions, 2 deletions
diff --git a/src/H5TS.c b/src/H5TS.c
index adc31dc..ee3b219 100644
--- a/src/H5TS.c
+++ b/src/H5TS.c
@@ -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 H5TS_tid_t is a record of a thread identifier that is
+ * available for reuse.
+ */
+struct _tid;
+typedef struct _tid H5TS_tid_t;
+
+struct _tid {
+ H5TS_tid_t *next;
+ uint64_t id;
+};
+
+/* Pointer to first free thread ID record or NULL. */
+static H5TS_tid_t *H5TS_tid_next_free = NULL;
+static uint64_t H5TS_tid_next_id = 0;
+
+/* Mutual exclusion for access to H5TS_tid_next_free and H5TS_tid_next_id. */
+static pthread_mutex_t H5TS_tid_mtx;
+
+/* Key for thread-local storage of the thread ID. */
+static H5TS_key_t H5TS_tid_key;
+
+#endif /* H5_HAVE_WIN_THREADS */
+
/*--------------------------------------------------------------------------
* NAME
@@ -70,6 +95,127 @@ H5TS_key_destructor(void *key_val)
/*--------------------------------------------------------------------------
* NAME
+ * H5TS_tid_destructor
+ *
+ * USAGE
+ * H5TS_tid_destructor()
+ *
+ * RETURNS
+ *
+ * DESCRIPTION
+ * When a thread shuts down, put its ID record on the free list.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+H5TS_tid_destructor(void *_v)
+{
+ H5TS_tid_t *tid = _v;
+
+ if (tid == NULL)
+ return;
+
+ /* TBD use an atomic CAS */
+ pthread_mutex_lock(&H5TS_tid_mtx);
+ tid->next = H5TS_tid_next_free;
+ H5TS_tid_next_free = tid;
+ pthread_mutex_unlock(&H5TS_tid_mtx);
+}
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_tid_init
+ *
+ * USAGE
+ * H5TS_tid_init()
+ *
+ * RETURNS
+ *
+ * DESCRIPTION
+ * Initialize for integer thread identifiers.
+ *
+ *--------------------------------------------------------------------------
+ */
+static void
+H5TS_tid_init(void)
+{
+ pthread_mutex_init(&H5TS_tid_mtx, NULL);
+ pthread_key_create(&H5TS_tid_key, H5TS_tid_destructor);
+}
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS_thread_id
+ *
+ * USAGE
+ * uint64_t id = H5TS_thread_id()
+ *
+ * RETURNS
+ * Return an integer identifier, ID, for the current thread.
+ *
+ * DESCRIPTION
+ * The ID satisfies 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)
+{
+ H5TS_tid_t *tid = pthread_getspecific(H5TS_tid_key);
+ H5TS_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(&H5TS_tid_mtx);
+ if ((tid = H5TS_tid_next_free) != NULL)
+ H5TS_tid_next_free = tid->next;
+ else if (H5TS_tid_next_id != UINT64_MAX) {
+ tid = &proto_tid;
+ tid->id = ++H5TS_tid_next_id;
+ }
+ pthread_mutex_unlock(&H5TS_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(H5TS_tid_key, tid) != 0) {
+ H5TS_tid_destructor(tid);
+ return 0;
+ }
+
+ return tid->id;
+}
+
+/*--------------------------------------------------------------------------
+ * NAME
* H5TS_pthread_first_thread_init
*
* USAGE
@@ -104,6 +250,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. */
+ H5TS_tid_init();
+
/* initialize key for thread-specific error stacks */
pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor);
@@ -151,7 +300,7 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
if (ret_value)
return ret_value;
- if(mutex->lock_count && pthread_equal(HDpthread_self(), mutex->owner_thread)) {
+ if(mutex->lock_count && pthread_equal(pthread_self(), mutex->owner_thread)) {
/* already owned by self - increment count */
mutex->lock_count++;
} else {
@@ -160,7 +309,7 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
pthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock);
/* After we've received the signal, take ownership of the mutex */
- mutex->owner_thread = HDpthread_self();
+ mutex->owner_thread = pthread_self();
mutex->lock_count = 1;
}