summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>1998-07-21 17:04:38 +0000
committerrpj <rpj>1998-07-21 17:04:38 +0000
commit492c73cf1f1b3e35b394aec991d1201726ec606d (patch)
treef7bddcaa8a2f89e567b94b20bde64973bb626fd2
parente51aa9d5fe177407b0c29903fec27b589ea529da (diff)
Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* cleanup.c (_pthread_cleanup_push): Implement. (_pthread_cleanup_pop): Implement. (_pthread_do_cancellation): Implement. These are private to the implementation. The real cleanup functions are macros. See below. * pthread.h (pthread_cleanup_push): Implement as a macro. (pthread_cleanup_pop): Implement as a macro. Because these are macros which start and end a block, the POSIX scoping requirement is observed. See the comment in the file. * exit.c (pthread_exit): Refine the code. * create.c (pthread_create): Code cleanup. * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T) up to multiple of DWORD. Add function prototypes. * private.c (_pthread_getthreadindex): "*thread" should have been "thread". Detect empty slot fail condition.
-rw-r--r--ChangeLog24
-rw-r--r--cleanup.c67
-rw-r--r--create.c34
-rw-r--r--exit.c24
-rw-r--r--implement.h16
-rw-r--r--private.c11
-rw-r--r--pthread.h20
7 files changed, 158 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index 6a1b02f..ba6e725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * cleanup.c (_pthread_cleanup_push): Implement.
+ (_pthread_cleanup_pop): Implement.
+ (_pthread_do_cancellation): Implement.
+ These are private to the implementation. The real cleanup functions
+ are macros. See below.
+
+ * pthread.h (pthread_cleanup_push): Implement as a macro.
+ (pthread_cleanup_pop): Implement as a macro.
+ Because these are macros which start and end a block, the POSIX scoping
+ requirement is observed. See the comment in the file.
+
+ * exit.c (pthread_exit): Refine the code.
+
+ * create.c (pthread_create): Code cleanup.
+
+ * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T)
+ up to multiple of DWORD.
+ Add function prototypes.
+
+ * private.c (_pthread_getthreadindex): "*thread" should have been
+ "thread". Detect empty slot fail condition.
+
1998-07-20 Ben Elliston <bje@cygnus.com>
* misc.c (pthread_once): Implement. Don't use a per-application
diff --git a/cleanup.c b/cleanup.c
new file mode 100644
index 0000000..f670b97
--- /dev/null
+++ b/cleanup.c
@@ -0,0 +1,67 @@
+/*
+ * cleanup.c
+ *
+ * Description:
+ * This translation unit implements routines associated cleaning up
+ * threads.
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+void
+_pthread_cleanup_push(void (*routine)(void *), void *arg)
+{
+ _pthread_cleanup_node_t * next;
+ int t;
+
+ t = _pthread_getthreadindex(pthread_self());
+
+ next = (_pthread_cleanup_node_t *) malloc(sizeof(_pthread_cleanup_node_t));
+ if (next == NULL) {
+ /* FIXME: INTERNAL ERROR */
+ }
+
+ next->next = _pthread_threads_table[t]->cleanupstack->first;
+ next->routine = routine;
+ next->arg = arg;
+ _pthread_threads_table[t]->cleanupstack->first = next;
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ _pthread_cleanup_node_t * handler;
+ void (* func)(void *);
+ void * arg;
+ int t;
+
+ t = _pthread_getthreadindex(pthread_self());
+ handler = _pthread_threads_table[t]->cleanupstack->first;
+
+ if (handler != NULL) {
+ next = handler->next;
+ func = handler->routine;
+ arg = handler->arg;
+
+ free(handler);
+
+ if (execute != 0)
+ (void) func(arg);
+
+ _pthread_threads_table[t]->cleanupstack->first = next;
+ }
+}
+
+void
+_pthread_do_cancellation(int tindex)
+{
+ _pthread_cleanup_stack_t * stack;
+
+ stack = _pthread_threads_table[tindex]->cleanupstack;
+
+ /* Run all the cleanup handlers */
+ while (stack->first != NULL) {
+ _pthread_cleanup_pop(1);
+ }
+}
diff --git a/create.c b/create.c
index 6897a9f..3814a23 100644
--- a/create.c
+++ b/create.c
@@ -42,26 +42,24 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
/* Use and modify attr_copy. Only after we've succeeded in creating the
new thread can we modify any passed-in structures.
- We use one malloc() to get all of our heap space and then allocate
- it further.
+ To save time 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)))) {
+
+ if (NULL ==
+ (privmem = (char) malloc(RND_SIZEOF(pthread_attr_t) +
+ RND_SIZEOF(_pthread_cleanup_stack_t)))) {
return EAGAIN;
}
attr_copy = (pthread_attr_t *) privmem;
- /* Force the next to a DWORD boundary.
- This is all compile time arithmetic.
+
+ /* Force cleanup_stack to start at a DWORD boundary within privmem.
*/
cleanup_stack =
- (_pthread_cleanup_stack_t *) &privmem[((sizeof(pthread_attr_t) /
- sizeof(DWORD)) + 1)
- * sizeof(DWORD)];
+ (_pthread_cleanup_stack_t *) &privmem[RND_SIZEOF(pthread_attr_t)];
(void) memcpy(attr_copy, attr);
-
/* CRITICAL SECTION */
pthread_mutex_lock(&_pthread_count_mutex);
@@ -82,7 +80,10 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
break;
}
- flags = 1; /* Start suspended and resume at the last moment */
+ flags = 1; /* Start suspended and resume at the last moment to avoid
+ race conditions, ie. where a thread may enquire it's
+ attributes before we finish storing them away.
+ */
handle = (HANDLE) _beginthreadex(security,
stack,
@@ -92,22 +93,21 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
&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 */
+ t = 0; /* Wrap to the top of the table. */
}
+
if ((_pthread_threads_table[t])->thread != NULL) {
/* INTERNAL ERROR */
} else {
@@ -131,8 +131,6 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
(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 {
diff --git a/exit.c b/exit.c
index a0b3b50..0778fc2 100644
--- a/exit.c
+++ b/exit.c
@@ -6,37 +6,29 @@
* a thread.
*/
+#include <windows.h>
+#include <process.h>
#include "pthread.h"
+#include "implement.h"
void
pthread_exit(void * value)
{
- /* The semantics are such that additional tasks must be done for
- 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;
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);
- }
+ _pthread_do_cancellation(t);
/* CRITICAL SECTION */
pthread_mutex_lock(&_pthread_count_mutex);
+
+ /* Frees attr and cleanupstack */
free(_pthread_threads_table[t]->attr);
+
_pthread_threads_table[t]->thread = NULL;
+
pthread_mutex_unlock(&_pthread_count_mutex);
/* END CRITICAL SECTION */
diff --git a/implement.h b/implement.h
index 2e03c48..2a7e192 100644
--- a/implement.h
+++ b/implement.h
@@ -14,6 +14,10 @@
#define _PTHREAD_HASH_INDEX(x) (((ULONG) x) % PTHREAD_THREADS_MAX)
+/* This is all compile time arithmetic */
+#define RND_SIZEOF(T) (((sizeof(T) / sizeof(DWORD)) + 1) * sizeof(DWORD))
+
+
typedef struct _pthread_cleanup_stack _pthread_cleanup_stack_t;
struct _pthread_cleanup_stck {
_pthread_cleanup_stack_t first;
@@ -39,6 +43,18 @@ typedef struct {
/* Nothing needed yet. */
} _pthread_condattr_t;
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void _pthread_cleanup_push(void (*routine)(void *), void *arg);
+void _pthread_cleanup_pop(int execute);
+void _pthread_do_cancellation(int tindex);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif /* _IMPLEMENT_H */
diff --git a/private.c b/private.c
index a880042..9499e07 100644
--- a/private.c
+++ b/private.c
@@ -17,7 +17,8 @@ _pthread_getthreadindex(pthread_t thread)
/* 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.
+ 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
@@ -25,14 +26,16 @@ _pthread_getthreadindex(pthread_t thread)
- 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; /* The initial thread index */
+ 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 (t == it)
+
+ if ((_pthread_threads_table[t])->thread == NULL || t == it)
return -1; /* Failed to find the thread */
}
return t;
diff --git a/pthread.h b/pthread.h
index 974a163..bf9ff7b 100644
--- a/pthread.h
+++ b/pthread.h
@@ -170,6 +170,26 @@ int pthread_key_delete(pthread_key_t key);
}
#endif /* __cplusplus */
+/* The following #defines implement POSIX cleanup handlers.
+ The standard requires that these functions be used as statements and
+ be used pairwise in the same scope. The standard suggests that, in C, they
+ may be implemented as macros starting and ending the same block.
+ */
+#ifdef pthread_cleanup_push
+#undef pthread_cleanup_push
+#endif
+#define pthread_cleanup_push(routine, arg) \
+{ \
+ _pthread_cleanup_push(routine, arg);
+
+#ifdef pthread_cleanup_pop
+#undef pthread_cleanup_pop
+#endif
+#define pthread_cleanup_pop(execute) \
+ _pthread_cleanup_pop(execute);\
+}
+
+
/* Below here goes all internal definitions required by this implementation
of pthreads for Win32.
*/