diff options
| author | rpj <rpj> | 1998-07-19 16:48:18 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 1998-07-19 16:48:18 +0000 | 
| commit | 40cf527fe65e12a745ca7b981676da1fb691eee6 (patch) | |
| tree | 610ecbae27017092270f23c368b20a4a087b4c4a | |
| parent | b57e564c2812036e2660842dbb34a3962836a90b (diff) | |
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().
| -rw-r--r-- | ChangeLog | 28 | ||||
| -rw-r--r-- | create.c | 142 | ||||
| -rw-r--r-- | exit.c | 26 | ||||
| -rw-r--r-- | implement.h | 19 | ||||
| -rw-r--r-- | pthread.h | 27 | 
5 files changed, 207 insertions, 35 deletions
| @@ -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 .. @@ -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; +} @@ -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 */ + + @@ -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 */ | 
