about summary refs log tree commit diff
path: root/src/thread
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread')
-rw-r--r--src/thread/pthread_key_create.c80
-rw-r--r--src/thread/pthread_key_delete.c14
2 files changed, 19 insertions, 75 deletions
diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c
index 0903d48f..da1fb116 100644
--- a/src/thread/pthread_key_create.c
+++ b/src/thread/pthread_key_create.c
@@ -13,49 +13,17 @@ static void nodtor(void *dummy)
 {
 }
 
-static void dirty(void *dummy)
+static void dummy_0(void)
 {
 }
 
-struct cleanup_args {
-	pthread_t caller;
-	int ret;
-};
-
-static void clean_dirty_tsd_callback(void *p)
-{
-	struct cleanup_args *args = p;
-	pthread_t self = __pthread_self();
-	pthread_key_t i;
-	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
-		if (keys[i] == dirty && self->tsd[i])
-			self->tsd[i] = 0;
-	}
-	/* Arbitrary choice to avoid data race. */
-	if (args->caller == self) args->ret = 0;
-}
-
-static void dummy2(void (*f)(void *), void *p)
-{
-}
-
-weak_alias(dummy2, __pthread_key_delete_synccall);
-
-static int clean_dirty_tsd(void)
-{
-	struct cleanup_args args = {
-		.caller = __pthread_self(),
-		.ret = EAGAIN
-	};
-	__pthread_key_delete_synccall(clean_dirty_tsd_callback, &args);
-	return args.ret;
-}
+weak_alias(dummy_0, __tl_lock);
+weak_alias(dummy_0, __tl_unlock);
 
 int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
 {
 	pthread_key_t j = next_key;
 	pthread_t self = __pthread_self();
-	int found_dirty = 0;
 
 	/* This can only happen in the main thread before
 	 * pthread_create has been called. */
@@ -70,40 +38,29 @@ int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
 			keys[next_key = *k = j] = dtor;
 			pthread_rwlock_unlock(&key_lock);
 			return 0;
-		} else if (keys[j] == dirty) {
-			found_dirty = 1;
 		}
 	} while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
 
-	/* It's possible that all slots are in use or __synccall fails. */
-	if (!found_dirty || clean_dirty_tsd()) {
-		pthread_rwlock_unlock(&key_lock);
-		return EAGAIN;
-	}
-
-	/* If this point is reached there is necessarily a newly-cleaned
-	 * slot to allocate to satisfy the caller's request. Find it and
-	 * mark any additional previously-dirty slots clean. */
-	for (j=0; j<PTHREAD_KEYS_MAX; j++) {
-		if (keys[j] == dirty) {
-			if (dtor) {
-				keys[next_key = *k = j] = dtor;
-				dtor = 0;
-			} else {
-				keys[j] = 0;
-			}
-		}
-	}
-
 	pthread_rwlock_unlock(&key_lock);
-	return 0;
+	return EAGAIN;
 }
 
-int __pthread_key_delete_impl(pthread_key_t k)
+int __pthread_key_delete(pthread_key_t k)
 {
+	sigset_t set;
+	pthread_t self = __pthread_self(), td=self;
+
+	__block_app_sigs(&set);
+	__tl_lock();
+	do td->tsd[k] = 0;
+	while ((td=td->next)!=self);
+	__tl_unlock();
+	__restore_sigs(&set);
+
 	pthread_rwlock_wrlock(&key_lock);
-	keys[k] = dirty;
+	keys[k] = 0;
 	pthread_rwlock_unlock(&key_lock);
+
 	return 0;
 }
 
@@ -118,7 +75,7 @@ void __pthread_tsd_run_dtors()
 			void *val = self->tsd[i];
 			void (*dtor)(void *) = keys[i];
 			self->tsd[i] = 0;
-			if (val && dtor && dtor != nodtor && dtor != dirty) {
+			if (val && dtor && dtor != nodtor) {
 				pthread_rwlock_unlock(&key_lock);
 				dtor(val);
 				pthread_rwlock_rdlock(&key_lock);
@@ -129,3 +86,4 @@ void __pthread_tsd_run_dtors()
 }
 
 weak_alias(__pthread_key_create, pthread_key_create);
+weak_alias(__pthread_key_delete, pthread_key_delete);
diff --git a/src/thread/pthread_key_delete.c b/src/thread/pthread_key_delete.c
deleted file mode 100644
index 012fe2da..00000000
--- a/src/thread/pthread_key_delete.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "pthread_impl.h"
-#include "libc.h"
-
-void __pthread_key_delete_synccall(void (*f)(void *), void *p)
-{
-	__synccall(f, p);
-}
-
-int __pthread_key_delete(pthread_key_t k)
-{
-	return __pthread_key_delete_impl(k);
-}
-
-weak_alias(__pthread_key_delete, pthread_key_delete);