summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2011-07-05 00:23:41 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2011-07-05 00:23:41 +0000
commitaa4d6a3e6c5e8c4e4837409c7f331324d620a9c9 (patch)
treed7677cda2fe8dc3398c477a332718b741e2bacf0
parentf17051621fe5f212b673ad665c91f756ab6857c8 (diff)
fix a few bugs in the thread specific data functions
-rw-r--r--lib/librthread/rthread_tls.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/lib/librthread/rthread_tls.c b/lib/librthread/rthread_tls.c
index 1e415872386..572c3ba83c7 100644
--- a/lib/librthread/rthread_tls.c
+++ b/lib/librthread/rthread_tls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rthread_tls.c,v 1.11 2008/10/13 05:42:46 kevlo Exp $ */
+/* $OpenBSD: rthread_tls.c,v 1.12 2011/07/05 00:23:40 tedu Exp $ */
/*
* Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
* All Rights Reserved.
@@ -71,16 +71,33 @@ pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
int
pthread_key_delete(pthread_key_t key)
{
+ pthread_t thread;
+ struct rthread_storage *rs;
+ int rv = 0;
- if (!rkeys[key].used)
+ if (key < 0 || key >= PTHREAD_KEYS_MAX)
return (EINVAL);
_spinlock(&rkeyslock);
+ if (!rkeys[key].used) {
+ rv = EINVAL;
+ goto out;
+ }
+
rkeys[key].used = 0;
rkeys[key].destructor = NULL;
- _spinunlock(&rkeyslock);
+ _spinlock(&_thread_lock);
+ LIST_FOREACH(thread, &_thread_list, threads) {
+ for (rs = thread->local_storage; rs; rs = rs->next) {
+ if (rs->keyid == key)
+ rs->data = NULL;
+ }
+ }
+ _spinunlock(&_thread_lock);
- return (0);
+out:
+ _spinunlock(&rkeyslock);
+ return (rv);
}
static struct rthread_storage *
@@ -89,6 +106,12 @@ _rthread_findstorage(pthread_key_t key)
struct rthread_storage *rs;
pthread_t self;
+ _spinlock(&rkeyslock);
+ if (!rkeys[key].used) {
+ rs = NULL;
+ goto out;
+ }
+
self = pthread_self();
for (rs = self->local_storage; rs; rs = rs->next) {
@@ -98,13 +121,15 @@ _rthread_findstorage(pthread_key_t key)
if (!rs) {
rs = calloc(1, sizeof(*rs));
if (!rs)
- return (NULL);
+ goto out;
rs->keyid = key;
rs->data = NULL;
rs->next = self->local_storage;
self->local_storage = rs;
}
+out:
+ _spinunlock(&rkeyslock);
return (rs);
}
@@ -113,6 +138,9 @@ pthread_getspecific(pthread_key_t key)
{
struct rthread_storage *rs;
+ if (key < 0 || key >= PTHREAD_KEYS_MAX)
+ return (NULL);
+
rs = _rthread_findstorage(key);
if (!rs)
return (NULL);
@@ -125,6 +153,9 @@ pthread_setspecific(pthread_key_t key, const void *data)
{
struct rthread_storage *rs;
+ if (key < 0 || key >= PTHREAD_KEYS_MAX)
+ return (EINVAL);
+
rs = _rthread_findstorage(key);
if (!rs)
return (ENOMEM);