diff options
Diffstat (limited to 'win32/contrib/pthreads/misc.c')
-rw-r--r-- | win32/contrib/pthreads/misc.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/win32/contrib/pthreads/misc.c b/win32/contrib/pthreads/misc.c new file mode 100644 index 000000000..aa06013b4 --- /dev/null +++ b/win32/contrib/pthreads/misc.c @@ -0,0 +1,420 @@ +/*
+ * misc.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+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
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if (once_control == NULL || init_routine == NULL)
+ {
+
+ result = EINVAL;
+ goto FAIL0;
+
+ }
+ else
+ {
+ result = 0;
+ }
+
+ if (!once_control->done)
+ {
+ 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);
+ }
+ }
+ }
+
+ /*
+ * Fall through Intentionally
+ */
+
+ /*
+ * ------------
+ * Failure Code
+ * ------------
+ */
+FAIL0:
+ return (result);
+
+} /* pthread_once */
+
+
+pthread_t
+pthread_self (void)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns a reference to the current running
+ * thread.
+ *
+ * PARAMETERS
+ * N/A
+ *
+ *
+ * DESCRIPTION
+ * This function returns a reference to the current running
+ * thread.
+ *
+ * RESULTS
+ * pthread_t reference to the current thread
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t self;
+
+#ifdef _UWIN
+ if(!ptw32_selfThreadKey)
+ return(NULL);
+#endif
+
+ self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ if (self == NULL)
+ {
+ /*
+ * Need to create an implicit 'self' for the currently
+ * executing thread.
+ */
+ self = ptw32_new();
+
+ if (self != NULL)
+ {
+ /*
+ * This is a non-POSIX thread which has chosen to call
+ * a POSIX threads function for some reason. We assume that
+ * it isn't joinable, but we do assume that it's
+ * (deferred) cancelable.
+ */
+ self->implicit = 1;
+ self->detachState = PTHREAD_CREATE_DETACHED;
+ self->thread = GetCurrentThreadId ();
+
+#ifdef NEED_DUPLICATEHANDLE
+ /*
+ * DuplicateHandle does not exist on WinCE.
+ *
+ * NOTE:
+ * GetCurrentThread only returns a pseudo-handle
+ * which is only valid in the current thread context.
+ * Therefore, you should not pass the handle to
+ * other threads for whatever purpose.
+ */
+ self->threadH = GetCurrentThread();
+#else
+ if( !DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &self->threadH,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS ) )
+ {
+ free( self );
+ return (NULL);
+ }
+#endif
+ }
+
+ pthread_setspecific (ptw32_selfThreadKey, self);
+ }
+
+ return (self);
+
+} /* pthread_self */
+
+int
+pthread_equal (pthread_t t1, pthread_t t2)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns zero if t1 and t2 are equal, else
+ * returns nonzero
+ *
+ * PARAMETERS
+ * t1,
+ * t2
+ * references to an instances of thread_t
+ *
+ *
+ * DESCRIPTION
+ * This function returns nonzero if t1 and t2 are equal, else
+ * returns zero.
+ *
+ * RESULTS
+ * non-zero if t1 and t2 refer to the same thread,
+ * 0 t1 and t2 do not refer to the same thread
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ /*
+ * We also accept NULL == NULL - treating NULL as a thread
+ * for this special case, because there is no error that we can return.
+ */
+ result = ( ( t1 == t2 ) && ( t1 == NULL || ( t1->thread == t2->thread ) ) );
+
+ return (result);
+
+} /* pthread_equal */
+
+
+int
+pthread_setconcurrency(int level)
+{
+ if (level < 0)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ ptw32_concurrency = level;
+ return 0;
+ }
+}
+
+
+int
+pthread_getconcurrency(void)
+{
+ return ptw32_concurrency;
+}
+
+
+static INLINE int
+ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
+ /*
+ * -------------------------------------------------------------------
+ * This provides an extra hook into the pthread_cancel
+ * mechanism that will allow you to wait on a Windows handle and make it a
+ * cancellation point. This function blocks until the given WIN32 handle is
+ * signaled or pthread_cancel has been called. It is implemented using
+ * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
+ * event used to implement pthread_cancel.
+ *
+ * Given this hook it would be possible to implement more of the cancellation
+ * points.
+ * -------------------------------------------------------------------
+ */
+{
+ int result;
+ pthread_t self;
+ HANDLE handles[2];
+ DWORD nHandles = 1;
+ DWORD status;
+
+ handles[0] = waitHandle;
+
+ if ((self = pthread_self()) != NULL)
+ {
+ /*
+ * Get cancelEvent handle
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE)
+ {
+
+ if ((handles[1] = self->cancelEvent) != NULL)
+ {
+ nHandles++;
+ }
+ }
+ }
+ else
+ {
+ handles[1] = NULL;
+ }
+
+ status = WaitForMultipleObjects (
+ nHandles,
+ handles,
+ FALSE,
+ timeout);
+
+
+ if (status == WAIT_FAILED)
+ {
+ result = EINVAL;
+ }
+ else if (status == WAIT_TIMEOUT)
+ {
+ result = ETIMEDOUT;
+ }
+ else if (status == WAIT_ABANDONED_0)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ /*
+ * Either got the mutex or the cancel event
+ * was signaled
+ */
+ switch (status - WAIT_OBJECT_0)
+ {
+
+ case 0:
+ /*
+ * Got the mutex
+ */
+ result = 0;
+ break;
+
+ case 1:
+ /*
+ * Got cancel request
+ */
+ ResetEvent (handles[1]);
+
+ if (self != NULL && !self->implicit)
+ {
+ /*
+ * Thread started with pthread_create
+ */
+ ptw32_throw(PTW32_EPS_CANCEL);
+ }
+
+ /* Should never get to here. */
+ result = EINVAL;
+ break;
+
+ default:
+ result = EINVAL;
+ break;
+ }
+ }
+
+ return (result);
+
+} /* CancelableWait */
+
+int
+pthreadCancelableWait (HANDLE waitHandle)
+{
+ return (ptw32_cancelable_wait(waitHandle, INFINITE));
+}
+
+int
+pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout)
+{
+ return (ptw32_cancelable_wait(waitHandle, timeout));
+}
+
+
+pthread_t
+ptw32_new (void)
+{
+ pthread_t t;
+
+ t = (pthread_t) calloc (1, sizeof (*t));
+
+ if (t != NULL)
+ {
+ t->detachState = PTHREAD_CREATE_JOINABLE;
+ t->cancelState = PTHREAD_CANCEL_ENABLE;
+ t->cancelType = PTHREAD_CANCEL_DEFERRED;
+ t->cancelLock = PTHREAD_MUTEX_INITIALIZER;
+ }
+
+ return t;
+
+}
+
+
+#ifdef NEED_CALLOC
+void *
+ptw32_calloc(size_t n, size_t s) {
+ unsigned int m = n*s;
+ void *p;
+
+ p = malloc(m);
+ if (p == NULL) return NULL;
+
+ memset(p, 0, m);
+
+ return p;
+}
+#endif
|