diff options
author | rpj <rpj> | 1998-07-21 17:04:38 +0000 |
---|---|---|
committer | rpj <rpj> | 1998-07-21 17:04:38 +0000 |
commit | 492c73cf1f1b3e35b394aec991d1201726ec606d (patch) | |
tree | f7bddcaa8a2f89e567b94b20bde64973bb626fd2 | |
parent | e51aa9d5fe177407b0c29903fec27b589ea529da (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-- | ChangeLog | 24 | ||||
-rw-r--r-- | cleanup.c | 67 | ||||
-rw-r--r-- | create.c | 34 | ||||
-rw-r--r-- | exit.c | 24 | ||||
-rw-r--r-- | implement.h | 16 | ||||
-rw-r--r-- | private.c | 11 | ||||
-rw-r--r-- | pthread.h | 20 |
7 files changed, 158 insertions, 38 deletions
@@ -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); + } +} @@ -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 { @@ -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 */ @@ -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; @@ -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. */ |