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.   */ | 
