summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog28
-rw-r--r--create.c142
-rw-r--r--exit.c26
-rw-r--r--implement.h19
-rw-r--r--pthread.h27
5 files changed, 207 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index 53cd93f..e0846aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+Mon Jul 20 02:31:05 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (_pthread_getthreadindex): Implement.
+
+ * pthread.h: Add application static data dependent on
+ _PTHREADS_BUILD_DLL define. This is needed to avoid allocating
+ non-sharable static data within the pthread DLL.
+
+ * implement.h: Add _pthread_cleanup_stack_t, _pthread_cleanup_node_t
+ and _PTHREAD_HASH_INDEX.
+
+ * exit.c (pthread_exit): Begin work on cleanup and de-allocate
+ thread-private storage.
+
+ * create.c (pthread_create): Add thread to thread table.
+ Keep a thread-private copy of the attributes with default values
+ filled in when necessary. Same for the cleanup stack. Make
+ pthread_create C run-time library friendly by using _beginthreadex()
+ instead of CreateThread(). Fix error returns.
+
+Sun Jul 19 16:26:23 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Rename pthreads_thread_count to _pthread_threads_count.
+ Create _pthread_threads_thread_t struct to keep thread specific data.
+
+ * create.c: Rename pthreads_thread_count to _pthread_threads_count.
+ (pthread_create): Handle errors from CreateThread().
+
1998-07-19 Ben Elliston <bje@cygnus.com>
* condvar.c (pthread_cond_wait): Generalise. Moved from here ..
diff --git a/create.c b/create.c
index 7a374bb..6897a9f 100644
--- a/create.c
+++ b/create.c
@@ -6,23 +6,24 @@
* thread.
*/
+#include <windows.h>
+#include <process.h>
#include "pthread.h"
#include "implement.h"
-/* FIXME: There must be a Win32 routine to get this value. */
-DWORD pthread_threads_count = 0;
-
int
pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine) (void *), void * arg)
{
/* Call Win32 CreateThread.
Map attributes as correctly as possible.
+ The passed in attr structure will be modified by this routine
+ to reflect any default values used. This is POSIX semantics.
*/
- HANDLE handle;
- DWORD flags = 0; /* Always 0 for POSIX threads */
- DWORD stack = PTHREAD_STACK_MIN;
- LPSECURITY_ATTRIBUTES security = NULL;
+ HANDLE handle = NULL;
+ unsigned flags;
+ unsigned stack;
+ void * security = NULL;
/* FIXME: This needs to be moved into process space.
Perhaps into a structure that contains all
@@ -32,34 +33,111 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
*/
SECURITY_ATTRIBUTES security_attr;
DWORD threadID;
+ int t;
+ int ret = 0; /* Success unless otherwise set */
+ char * privmem;
+ pthread_attr_t * attr_copy;
+ _pthread_cleanup_stack_t * cleanup_stack;
+
+ /* Use and modify attr_copy. Only after we've succeeded in creating the
+ new thread can we modify any passed-in structures.
- if (pthread_threads_count >= PTHREAD_THREADS_MAX)
+ We use one malloc() to get all of our heap space and then allocate
+ it further.
+ */
+ if (NULL == (privmem = (char) malloc(sizeof(pthread_attr_t) +
+ sizeof(_pthread_cleanup_stack_t) +
+ sizeof(DWORD)))) {
return EAGAIN;
+ }
+
+ attr_copy = (pthread_attr_t *) privmem;
+ /* Force the next to a DWORD boundary.
+ This is all compile time arithmetic.
+ */
+ cleanup_stack =
+ (_pthread_cleanup_stack_t *) &privmem[((sizeof(pthread_attr_t) /
+ sizeof(DWORD)) + 1)
+ * sizeof(DWORD)];
+
+ (void) memcpy(attr_copy, attr);
+
+
+ /* CRITICAL SECTION */
+ pthread_mutex_lock(&_pthread_count_mutex);
+
+ if (_pthread_threads_count < PTHREAD_THREADS_MAX) {
+ switch (attr)
+ {
+ case NULL:
+ /* Use POSIX default attributes */
+ stack = attr_copy->stacksize = PTHREAD_STACK_MIN;
+ break;
+ default:
+ /* Map attributes */
+ if (attr_copy.stacksize != NULL)
+ stack = (DWORD) attr_copy->stacksize;
+ else
+ stack = attr_copy->stacksize = PTHREAD_STACK_MIN;
+ break;
+ }
+
+ flags = 1; /* Start suspended and resume at the last moment */
- switch (attr)
- {
- case NULL:
- /* Use POSIX default attributes */
- break;
- default:
- /* Map attributes */
- if (attr->stacksize != NULL)
- stack = (DWORD) attr->stacksize;
- break;
+ handle = (HANDLE) _beginthreadex(security,
+ stack,
+ (unsigned (_stdcall *)(void *)) start_routine,
+ arg,
+ flags,
+ &threadID);
+
+ if (handle != NULL) {
+ /* We have a new thread */
+ _pthread_threads_count++;
+
+ /* The hash table works as follows:
+ hash into the table,
+ if the slot is occupied then start single stepping from there
+ until we find an available slot.
+
+ There is at least one slot available at this point.
+ */
+ t = _PTHREAD_HASH_INDEX(handle);
+ while ((_pthread_threads_table[t])->thread != NULL) {
+ t++;
+ if (t == PTHREAD_THREADS_MAX)
+ t = 0; /* Wrap around to the first slot */
+ }
+ if ((_pthread_threads_table[t])->thread != NULL) {
+ /* INTERNAL ERROR */
+ } else {
+ (_pthread_threads_table[t])->thread = handle;
+ (_pthread_threads_table[t])->attr = attr_copy;
+ (_pthread_threads_table[t])->cleanupstack = cleanup_stack;
+ }
+ } else {
+ ret = EAGAIN;
}
+ } else {
+ ret = EAGAIN;
+ }
- /* FIXME: I don't have error return values to work with so
- I'm assuming this always succeeds (obviously not).
- */
- handle = CreateThread(security,
- stack,
- start_routine,
- arg,
- flags,
- &threadID);
-
- *thread = (pthread_t) handle;
- pthread_threads_count++;
- return 0;
-}
+ /* Let others in as soon as possible. */
+ pthread_mutex_unlock(&_pthread_count_mutex);
+ /* END CRITICAL SECTION */
+
+ if (ret == 0) {
+ *thread = (pthread_t) handle;
+ (void) memcpy(attr, attr_copy);
+ /* POSIX threads are always running after creation.
+ Start the thread only after passed-in structures have been
+ modified to avoid race conditions.
+ */
+ ResumeThread(handle);
+ } else {
+ free(privmem);
+ }
+
+ return ret;
+}
diff --git a/exit.c b/exit.c
index 5212854..a0b3b50 100644
--- a/exit.c
+++ b/exit.c
@@ -15,6 +15,30 @@ pthread_exit(void * value)
strict POSIX conformance. We must add code here later which
deals with executing cleanup handlers and such. For now, the
following is mostly correct: */
+ int t;
- ExitThread((DWORD) value);
+ t = _pthread_getthreadindex(pthread_self());
+ handler = _pthread_threads_table[t]->cleanupstack->first;
+
+ /* Run all the cleanup handlers */
+ while (handler != NULL) {
+ void (* func)(void *);
+ void * arg;
+ _pthread_cleanup_node_t * next;
+
+ func = handler->routine;
+ arg = handler->arg;
+ _pthread_threads_table[t]->cleanupstack->first = next = handler->next;
+ free(handler);
+ (void) func(arg);
+ }
+
+ /* CRITICAL SECTION */
+ pthread_mutex_lock(&_pthread_count_mutex);
+ free(_pthread_threads_table[t]->attr);
+ _pthread_threads_table[t]->thread = NULL;
+ pthread_mutex_unlock(&_pthread_count_mutex);
+ /* END CRITICAL SECTION */
+
+ _endthreadex((DWORD) value);
}
diff --git a/implement.h b/implement.h
index 254d86f..2e03c48 100644
--- a/implement.h
+++ b/implement.h
@@ -9,10 +9,23 @@
/* FIXME: Arbitrary. Need values from Win32.
*/
-#define PTHREAD_THREADS_MAX 256
+#define PTHREAD_THREADS_MAX 128
#define PTHREAD_STACK_MIN 65535
-extern DWORD pthreads_thread_count;
+#define _PTHREAD_HASH_INDEX(x) (((ULONG) x) % PTHREAD_THREADS_MAX)
+
+typedef struct _pthread_cleanup_stack _pthread_cleanup_stack_t;
+struct _pthread_cleanup_stck {
+ _pthread_cleanup_stack_t first;
+ int count;
+};
+
+typedef struct _pthread_cleanup_node _pthread_cleanup_node_t;
+struct _pthread_cleanup_node {
+ _pthread_cleanup_node_t next;
+ void (* routine)(void *);
+ void * arg;
+};
typedef struct {
size_t stacksize;
@@ -27,3 +40,5 @@ typedef struct {
} _pthread_condattr_t;
#endif /* _IMPLEMENT_H */
+
+
diff --git a/pthread.h b/pthread.h
index 8137f53..abce374 100644
--- a/pthread.h
+++ b/pthread.h
@@ -163,4 +163,31 @@ int pthread_key_delete(pthread_key_t key);
}
#endif /* __cplusplus */
+/* Below here goes all internal definitions required by this implementation
+ of pthreads for Win32.
+ */
+
+/* An element in the thread table. */
+typedef struct _pthread_threads_thread _pthread_threads_thread_t;
+struct _pthread_threads_thread {
+ pthread_t thread;
+ _pthread_attr_t *attr;
+};
+
+/* _PTHREAD_BUILD_DLL must only be defined if we are building the DLL. */
+#ifndef _PTHREADS_BUILD_DLL
+/* Static global data that must be static within the application
+ but not the DLL.
+ */
+pthread_mutex_t _pthread_count_mutex = PTHREAD_MUTEX_INITIALIZER;
+DWORD _pthread_threads_count = 0;
+_pthread_threads_thread_t _pthread_threads_table[PTHREAD_THREADS_MAX];
+#else
+extern pthread_mutex_t _pthread_count_mutex;
+extern DWORD _pthread_threads_count;
+extern _pthread_threads_thread_t _pthread_threads_table[];
+#endif
+
+/* End of application static data */
+
#endif /* _PTHREADS_H */