summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>1999-02-12 08:19:34 +0000
committerrpj <rpj>1999-02-12 08:19:34 +0000
commit44f6c8a35ca491b1f04d6b460ab5d0d8a3cf6083 (patch)
tree43343d58f15346fea6d09371c7d6abb090fa8842
parenteb222bd25ddfc39ac156d59331f1dd4c3ef5df9b (diff)
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.
-rw-r--r--ChangeLog8
-rw-r--r--misc.c105
-rw-r--r--pthread.h8
3 files changed, 99 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 269e7d4..469b7cb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/misc.c b/misc.c
index b3c5246..1b558f4 100644
--- a/misc.c
+++ b/misc.c
@@ -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)
diff --git a/pthread.h b/pthread.h
index 415602c..d08eac3 100644
--- a/pthread.h
+++ b/pthread.h
@@ -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 */
+};
/*
* ====================