summaryrefslogtreecommitdiff
path: root/sysdeps/generic
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2018-01-06 03:03:30 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2018-01-06 03:03:30 +0100
commitada00b30cf36beecdf4b900b67ffb602fd0b89ca (patch)
treefe3378dcb34fae36e93ea0b4711aba21389f7b86 /sysdeps/generic
parent7d4a84731cd80a1ef711c83535c6340f0e2b143f (diff)
Move key management to sysdeps/generic
Now that it does not use libihash any more, it is not hurd-dependent any more. * sysdeps/hurd/pt-destroy-specific.c: Move to sysdeps/generic/pt-destroy-specific.c * sysdeps/hurd/pt-key-create.c: Move to sysdeps/generic/pt-key-create.c. * sysdeps/hurd/pt-key-delete.c: Move to sysdeps/generic/pt-key-delete.c. * sysdeps/hurd/pt-key.h: Move to sysdeps/generic/pt-key.h. * sysdeps/hurd/pt-getspecific.c: Move to sysdeps/generic/pt-getspecific.c. * sysdeps/hurd/pt-init-specific.c: Move to sysdeps/generic/pt-init-specific.c. * sysdeps/hurd/pt-setspecific.c: Move to sysdeps/generic/pt-setspecific.c.
Diffstat (limited to 'sysdeps/generic')
-rw-r--r--sysdeps/generic/pt-destroy-specific.c57
-rw-r--r--sysdeps/generic/pt-getspecific.c20
-rw-r--r--sysdeps/generic/pt-init-specific.c6
-rw-r--r--sysdeps/generic/pt-key-create.c88
-rw-r--r--sysdeps/generic/pt-key-delete.c43
-rw-r--r--sysdeps/generic/pt-key.h59
-rw-r--r--sysdeps/generic/pt-setspecific.c28
7 files changed, 280 insertions, 21 deletions
diff --git a/sysdeps/generic/pt-destroy-specific.c b/sysdeps/generic/pt-destroy-specific.c
index b627f87..642c61c 100644
--- a/sysdeps/generic/pt-destroy-specific.c
+++ b/sysdeps/generic/pt-destroy-specific.c
@@ -1,4 +1,4 @@
-/* __pthread_destory_specific. Generic version.
+/* __pthread_destory_specific. Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,11 +18,60 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+#include <stdlib.h>
+
#include <pt-internal.h>
void
-__pthread_destory_specifc (struct __pthread *thread)
+__pthread_destroy_specific (struct __pthread *thread)
{
- /* Not support, thus there cannot be any. */
- return;
+ int i;
+ int seen_one;
+
+ /* Check if there is any thread specific data. */
+ if (! thread->thread_specifics)
+ return;
+
+ __pthread_key_lock_ready ();
+
+ /* Iterate and call the destructors on any thread specific data. */
+ for (;;)
+ {
+ seen_one = 0;
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ for (i = 0; i < __pthread_key_count && i < thread->thread_specifics_size; i ++)
+ {
+ void *value;
+
+ if (__pthread_key_destructors[i] == PTHREAD_KEY_INVALID)
+ continue;
+
+ value = thread->thread_specifics[i];
+ if (value)
+ {
+ thread->thread_specifics[i] = 0;
+
+ if (__pthread_key_destructors[i])
+ {
+ seen_one = 1;
+ __pthread_key_destructors[i] (value);
+ }
+ }
+ }
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+
+ if (! seen_one)
+ break;
+
+ /* This may take a very long time. Let those blocking on
+ pthread_key_create or pthread_key_delete make progress. */
+ sched_yield ();
+ }
+
+ free (thread->thread_specifics);
+ thread->thread_specifics = 0;
+ thread->thread_specifics_size = 0;
}
diff --git a/sysdeps/generic/pt-getspecific.c b/sysdeps/generic/pt-getspecific.c
index 2a7c4a9..1f49c03 100644
--- a/sysdeps/generic/pt-getspecific.c
+++ b/sysdeps/generic/pt-getspecific.c
@@ -1,4 +1,4 @@
-/* pthread_getspecific. Generic version.
+/* pthread_getspecific. Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,10 +18,22 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+
#include <pt-internal.h>
-int
-pthread_getspecific (pthread_key_t key)
+void *
+__pthread_getspecific (pthread_key_t key)
{
- return EINVAL;
+ struct __pthread *self;
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ return NULL;
+
+ self = _pthread_self ();
+ if (key >= self->thread_specifics_size)
+ return 0;
+
+ return self->thread_specifics[key];
}
+strong_alias (__pthread_getspecific, pthread_getspecific);
diff --git a/sysdeps/generic/pt-init-specific.c b/sysdeps/generic/pt-init-specific.c
index 00744fb..78958cb 100644
--- a/sysdeps/generic/pt-init-specific.c
+++ b/sysdeps/generic/pt-init-specific.c
@@ -1,4 +1,4 @@
-/* __pthread_init_specific. Generic version.
+/* __pthread_init_specific. Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,10 +18,14 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+#include <stdlib.h>
+
#include <pt-internal.h>
error_t
__pthread_init_specific (struct __pthread *thread)
{
+ thread->thread_specifics = 0;
+ thread->thread_specifics_size = 0;
return 0;
}
diff --git a/sysdeps/generic/pt-key-create.c b/sysdeps/generic/pt-key-create.c
index 33f691b..f26ec36 100644
--- a/sysdeps/generic/pt-key-create.c
+++ b/sysdeps/generic/pt-key-create.c
@@ -1,4 +1,4 @@
-/* pthread_key_create. Generic version.
+/* pthread_key_create. Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,13 +18,93 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+#include <stdlib.h>
+#include <assert.h>
+
#include <pt-internal.h>
+pthread_mutex_t __pthread_key_lock;
+
+void (**__pthread_key_destructors) (void *arg);
+int __pthread_key_size;
+int __pthread_key_count;
+int __pthread_key_invalid_count;
+
int
__pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
{
- return ENOSYS;
-}
+ /* Where to look for the next key slot. */
+ static int index;
+
+ __pthread_key_lock_ready ();
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ do_search:
+ /* Use the search hint and try to find a free slot. */
+ for (; index < __pthread_key_count
+ && __pthread_key_destructors[index] != PTHREAD_KEY_INVALID;
+ index ++)
+ ;
+
+ /* See if we actually found a free element. */
+ if (index < __pthread_key_count)
+ {
+ assert (__pthread_key_destructors[index] == PTHREAD_KEY_INVALID);
+ assert (__pthread_key_invalid_count > 0);
+
+ __pthread_key_invalid_count --;
+ __pthread_key_destructors[index] = destructor;
+ *key = index ++;
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return 0;
+ }
+ assert (index == __pthread_key_count);
+
+ /* No space at the end. */
+ if (__pthread_key_size == __pthread_key_count)
+ {
+ /* See if it is worth looking for a free element. */
+ if (__pthread_key_invalid_count > 4
+ && __pthread_key_invalid_count > __pthread_key_size / 8)
+ {
+ index = 0;
+ goto do_search;
+ }
+
+
+ /* Resize the array. */
+ {
+ void *t;
+ int newsize;
+
+ if (__pthread_key_size == 0)
+ newsize = 8;
+ else
+ newsize = __pthread_key_size * 2;
+
+ t = realloc (__pthread_key_destructors,
+ newsize * sizeof (*__pthread_key_destructors));
+ if (! t)
+ {
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return ENOMEM;
+ }
+
+ __pthread_key_size = newsize;
+ __pthread_key_destructors = t;
+ }
+ }
+
+ __pthread_key_destructors[index] = destructor;
+ *key = index;
+
+ index ++;
+ __pthread_key_count ++;
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+ return 0;
+}
strong_alias (__pthread_key_create, pthread_key_create)
-stub_warning (pthread_key_create)
diff --git a/sysdeps/generic/pt-key-delete.c b/sysdeps/generic/pt-key-delete.c
index 7b4ff63..499e9f3 100644
--- a/sysdeps/generic/pt-key-delete.c
+++ b/sysdeps/generic/pt-key-delete.c
@@ -1,4 +1,4 @@
-/* pthread_key_delete. Generic version.
+/* pthread_key_delete. Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,12 +18,47 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+
#include <pt-internal.h>
int
pthread_key_delete (pthread_key_t key)
{
- return ENOSYS;
-}
+ error_t err = 0;
+
+ __pthread_key_lock_ready ();
+
+ __pthread_mutex_lock (&__pthread_key_lock);
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ err = EINVAL;
+ else
+ {
+ int i;
+
+ __pthread_key_destructors[key] = PTHREAD_KEY_INVALID;
+ __pthread_key_invalid_count ++;
-stub_warning (pthread_key_delete)
+ __pthread_rwlock_rdlock (&__pthread_threads_lock);
+ for (i = 0; i < __pthread_num_threads; ++i)
+ {
+ struct __pthread *t;
+
+ t = __pthread_threads[i];
+
+ if (t == NULL)
+ continue;
+
+ /* Just remove the key, no need to care whether it was
+ already there. */
+ if (key < t->thread_specifics_size)
+ t->thread_specifics[key] = 0;
+ }
+ __pthread_rwlock_unlock (&__pthread_threads_lock);
+ }
+
+ __pthread_mutex_unlock (&__pthread_key_lock);
+
+ return err;
+}
diff --git a/sysdeps/generic/pt-key.h b/sysdeps/generic/pt-key.h
index 544eb20..46830d7 100644
--- a/sysdeps/generic/pt-key.h
+++ b/sysdeps/generic/pt-key.h
@@ -1,4 +1,4 @@
-/* pthread_key internal declatations. Generic version.
+/* pthread_key internal declatations for the Hurd version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,5 +18,60 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+#include <libc-lockP.h>
-#define PTHREAD_KEY_MEMBERS
+#define PTHREAD_KEY_MEMBERS \
+ void **thread_specifics; /* This is only resized by the thread, and always growing */ \
+ unsigned thread_specifics_size; /* Number of entries in thread_specifics */
+
+#define PTHREAD_KEY_INVALID (void *) (-1)
+
+
+/* __PTHREAD_KEY_DESTRUCTORS is an array of destructors with
+ __PTHREAD_KEY_SIZE elements. If an element with index less than
+ __PTHREAD_KEY_COUNT is invalid, it shall contain the value
+ PTHREAD_KEY_INVALID which shall be distinct from NULL.
+
+ Normally, we just add new keys to the end of the array and realloc
+ it as necessary. The pthread_key_create routine may decide to
+ rescan the array if __PTHREAD_KEY_FREE is large. */
+extern void (**__pthread_key_destructors) (void *arg);
+extern int __pthread_key_size;
+extern int __pthread_key_count;
+/* Number of invalid elements in the array. Does not include elements
+ for which memory has been allocated but which have not yet been
+ used (i.e. those elements with indexes greater than
+ __PTHREAD_KEY_COUNT). */
+extern int __pthread_key_invalid_count;
+
+/* Protects the above variables. This must be a recursive lock: the
+ destructors may call pthread_key_delete. */
+extern pthread_mutex_t __pthread_key_lock;
+
+#include <assert.h>
+
+static inline void
+__pthread_key_lock_ready (void)
+{
+ static pthread_once_t o = PTHREAD_ONCE_INIT;
+
+ void do_init (void)
+ {
+ int err;
+ pthread_mutexattr_t attr;
+
+ err = __pthread_mutexattr_init (&attr);
+ assert_perror (err);
+
+ err = __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert_perror (err);
+
+ err = _pthread_mutex_init (&__pthread_key_lock, &attr);
+ assert_perror (err);
+
+ err = __pthread_mutexattr_destroy (&attr);
+ assert_perror (err);
+ }
+
+ __pthread_once (&o, do_init);
+}
diff --git a/sysdeps/generic/pt-setspecific.c b/sysdeps/generic/pt-setspecific.c
index d520c5d..871560c 100644
--- a/sysdeps/generic/pt-setspecific.c
+++ b/sysdeps/generic/pt-setspecific.c
@@ -18,10 +18,34 @@
Boston, MA 02111-1307, USA. */
#include <pthread.h>
+
#include <pt-internal.h>
int
-pthread_setspecific (pthread_key_t key, const void *value)
+__pthread_setspecific (pthread_key_t key, const void *value)
{
- return EINVAL;
+ struct __pthread *self = _pthread_self ();
+
+ if (key < 0 || key >= __pthread_key_count
+ || __pthread_key_destructors[key] == PTHREAD_KEY_INVALID)
+ return EINVAL;
+
+ if (key >= self->thread_specifics_size)
+ {
+ /* Amortize reallocation cost. */
+ int newsize = 2 * key + 1;
+ void **new = realloc (self->thread_specifics,
+ newsize * sizeof (new[0]));
+ if (! new )
+ return ENOMEM;
+
+ memset (&new[self->thread_specifics_size], 0,
+ (newsize - self->thread_specifics_size) * sizeof (new[0]));
+ self->thread_specifics = new;
+ self->thread_specifics_size = newsize;
+ }
+
+ self->thread_specifics[key] = (void*) value;
+ return 0;
}
+strong_alias (__pthread_setspecific, pthread_setspecific);