/* * 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 = NULL; /* * need to ensure there always is a self */ if ((self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey)) == NULL) { /* * Need to create an implicit 'self' for the currently * executing thread. */ self = (pthread_t) calloc (1, sizeof (*self)); if (self != NULL) { self->implicit = 1; self->detachState = PTHREAD_CREATE_DETACHED; self->thread = GetCurrentThreadId (); #ifdef UNDER_CE /* DuplicateHandle does not exist on WinCE */ self->threadH = GetCurrentThread(); #else if( !DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &self->threadH, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) { free( self ); return (NULL); } #endif } pthread_setspecific (_pthread_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; result = ((t1 == t2) && (t1->thread == t2->thread)); return (result); } /* pthread_equal */ static int CancelableWait (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_t) pthread_getspecific (_pthread_selfThreadKey)) != 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 */ #ifdef _MSC_VER DWORD exceptionInformation[3]; exceptionInformation[0] = (DWORD) (0); exceptionInformation[1] = (DWORD) (0); exceptionInformation[2] = (DWORD) (0); RaiseException ( EXCEPTION_PTHREAD_SERVICES, 0, 3, exceptionInformation); #else /* _MSC_VER */ #ifdef __cplusplus throw Pthread_exception(); #endif /* __cplusplus */ #endif /* _MSC_VER */ } /* Should never get to here. */ result = EINVAL; break; default: result = EINVAL; break; } } return (result); } /* pthreadCancelableWait */ int pthreadCancelableWait (HANDLE waitHandle) { return (CancelableWait(waitHandle, INFINITE)); } int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) { return (CancelableWait(waitHandle, timeout)); } #ifdef NEED_CALLOC void *_pthread_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