diff options
| -rw-r--r-- | ChangeLog | 8 | ||||
| -rw-r--r-- | misc.c | 105 | ||||
| -rw-r--r-- | pthread.h | 8 | 
3 files changed, 99 insertions, 22 deletions
@@ -1,3 +1,11 @@ +Sat Feb 13 03:03:30 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* pthread.h (struct pthread_once_t_): Replaced. + +	* misc.c (pthread_once): Replace with John Bossom's version; +	has lighter weight serialisation; fixes problem of not holding +	competing threads until after the init_routine completes. +  Thu Feb 11 13:34:14 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* misc.c (CancelableWait): Change C++ exception throw. @@ -8,39 +8,102 @@  #include "pthread.h"  #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ +  int -pthread_once(pthread_once_t *once_control, -	     void (*init_routine)(void)) +pthread_once ( +               pthread_once_t * once_control, +               void (*init_routine) (void) +) +        /* +         * ------------------------------------------------------ +         * DOCPUBLIC +         *      If any thread in a process  with  a  once_control  parameter +         *      makes  a  call to pthread_once(), the first call will summon +         *      the init_routine(), but  subsequent  calls  will  not. The +         *      once_control  parameter  determines  whether  the associated +         *      initialization routine has been called.  The  init_routine() +         *      is complete upon return of pthread_once(). +         *      This function guarantees that one and only one thread +         *      executes the initialization routine, init_routine when +         *      access is controlled by the pthread_once_t control +         *      key. +         * +         * PARAMETERS +         *      once_control +         *              pointer to an instance of pthread_once_t +         * +         *      init_routine +         *              pointer to an initialization routine +         * +         * +         * DESCRIPTION +         *      See above. +         * +         * RESULTS +         *              0               success, +         *              EINVAL          once_control or init_routine is NULL +         * +         * ------------------------------------------------------ +         */  { -  /* A flag, allocated per invocation, that indicates if the atomic -     test-and-set occured. */ -  unsigned short flag = 0; +  int result;    if (once_control == NULL || init_routine == NULL)      { -      return EINVAL; -    } -  /* An atomic test-and-set of the "once" flag. */ -  pthread_mutex_lock(&once_control->lock); -  if (once_control->flag == 0) +      result = EINVAL; +      goto FAIL0; + +    } +  else      { -      flag = once_control->flag = 1; +      result = 0;      } -  pthread_mutex_unlock(&once_control->lock); -  if (flag) +  if (!once_control->done)      { -      /* Run the init routine. */ -      init_routine(); +      if (InterlockedIncrement (&(once_control->started)) == 0) +        { +          /* +           * First thread to increment the started variable +           */ +          (*init_routine) (); +          once_control->done = TRUE; + +        } +      else +        { +          /* +           * Block until other thread finishes executing the onceRoutine +           */ +          while (!(once_control->done)) +            { +              /* +               * The following gives up CPU cycles without pausing +               * unnecessarily +               */ +              Sleep (0); +            } +        }      } -   -  return 0; -} -/* - * Code contributed by John E. Bossom <JEB>. - */ +  /* +   * Fall through Intentionally +   */ + +  /* +   * ------------ +   * Failure Code +   * ------------ +   */ +FAIL0: +  return (result); + +}                               /* pthread_once */ +  pthread_t  pthread_self (void) @@ -491,8 +491,14 @@ extern "C"   * ====================   * ====================   */ -#define PTHREAD_ONCE_INIT	 { 0, PTHREAD_MUTEX_INITIALIZER } +#define PTHREAD_ONCE_INIT       { FALSE, -1 } +struct pthread_once_t_ +{ +  int done;                 /* indicates if user function executed  */ +  long started;             /* First thread to increment this value */ +                            /* to zero executes the user function   */ +};  /*   * ====================  | 
