summaryrefslogtreecommitdiff
path: root/private.c
diff options
context:
space:
mode:
Diffstat (limited to 'private.c')
-rw-r--r--private.c158
1 files changed, 132 insertions, 26 deletions
diff --git a/private.c b/private.c
index 9499e07..77f0334 100644
--- a/private.c
+++ b/private.c
@@ -11,32 +11,138 @@
#include "pthread.h"
#include "implement.h"
+/* The threads table works as follows:
+ hash into the table,
+ if the thread in this slot doesn't match then start single
+ stepping from there until we find it, or we hit an empty slot, or
+ we end up where we started from.
+
+ The scheme should have these characteristics:
+ - if the thread handle is a sequence number then the hash will
+ succeed first time every time,
+ - if the thread handle is a pseudo randomish value (eg. a pointer)
+ then the hash should succeed first time most times.
+ */
+
int
-_pthread_getthreadindex(pthread_t thread)
+_pthread_new_thread_entry(pthread_t thread,
+ _pthread_threads_thread_t ** entry)
{
- /* The hash table works as follows:
- hash into the table,
- if the thread in this slot doesn't match then start single
- stepping from there until we find it, or we hit an empty slot, or
- we end up where we started from.
-
- The scheme should have these characteristics:
- - if the thread handle is a sequence number then the hash will
- succeed first time every time,
- - if the thread handle is a pseudo randomish value (eg. a pointer)
- then the hash should succeed first time most times.
- */
- int t = _PTHREAD_HASH_INDEX(thread);
- int it = t; /* Remember where we started from. */
-
- while ((_pthread_threads_table[t])->thread != thread) {
- t++;
-
- if (t == PTHREAD_THREADS_MAX)
- t = 0; /* Wrap around to the first slot */
-
- if ((_pthread_threads_table[t])->thread == NULL || t == it)
- return -1; /* Failed to find the thread */
- }
- return t;
+ _pthread_threads_thread_t ** this;
+
+ if (_pthread_threads_count >= PTHREAD_THREADS_MAX)
+ {
+ return EAGAIN;
+ }
+
+ this = &_pthread_threads_table[_PTHREAD_HASH_INDEX(thread)];
+
+ while ((*this)->thread != NULL)
+ {
+ this++;
+
+ if (this == &_pthread_threads_table[PTHREAD_THREADS_MAX])
+ {
+ /* Wrap to the top of the table. */
+ this == _pthread_threads_table;
+ }
+ }
+
+ if ((*this)->thread != NULL)
+ {
+ /* INTERNAL ERROR: There should be at least one slot left. */
+ return ESRCH;
+ }
+ else
+ {
+ new = (_pthread_threads_thread_t *) malloc(sizeof(_pthread_threads_thread_t));
+
+ if (new == NULL)
+ {
+ return ENOMEM;
+ }
+
+ new->thread = thread;
+ pthread_attr_init(&(new->attr));
+ new->cleanupstack = NULL;
+ new->destructorstack = NULL;
+ new->forkpreparestack = NULL;
+ new->forkparentstack = NULL;
+ new->forkchildstack = NULL;
+ *this = new;
+ }
+
+ _pthread_threads_count++;
+ entry = this;
+
+ return 0;
}
+
+_pthread_threads_thread **
+_pthread_find_thread_entry(pthread_t thread)
+{
+ _pthread_threads_thread_t ** this;
+ _pthread_threads_thread_t ** start;
+
+ start = this = &_pthread_threads_table[_PTHREAD_HASH_INDEX(thread)];
+
+ while ((*this)->thread != thread)
+ {
+ this++;
+
+ if (this == &_pthread_threads_table[PTHREAD_THREADS_MAX])
+ {
+ /* Wrap to top of table. */
+ this = _pthread_threads_table;
+ }
+
+ if ((*this)->thread == NULL || this == start)
+ {
+ /* Failed to find the thread. */
+ return -1;
+ }
+ }
+
+ return this;
+}
+
+void
+_pthread_delete_thread_entry(_pthread_threads_thread_t ** this)
+{
+ /* We don't check that the thread has been properly cleaned up, so
+ it had better be done already. */
+ _pthread_threads_thread ** this;
+ _pthread_threads_thread ** entry;
+
+ /* CRITICAL SECTION */
+ pthread_mutex_lock(&_pthread_count_mutex);
+
+ /* If this is not NULL then we are removing an entry for a
+ failed thread start. If this is NULL we need to get this
+ here within the critical section. */
+ if (this == NULL)
+ {
+ this = _PTHREAD_THIS;
+ }
+
+ if (this != NULL)
+ {
+ entry = this;
+ /* Do this first to avoid contention and then free the storage. */
+ this = NULL;
+ free(*entry);
+
+ if (_pthread_threads_count > 0)
+ {
+ _pthread_threads_count--;
+ }
+ else
+ {
+ /* FIXME: INTERNAL ERROR: This should not happen. */
+ }
+ }
+
+ pthread_mutex_unlock(&_pthread_count_mutex);
+ /* END CRITICAL SECTION */
+}
+