diff options
| author | rpj <rpj> | 2002-02-18 03:16:52 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 2002-02-18 03:16:52 +0000 | 
| commit | a416ab17ecf9f2cb0f1e3f7bd645a8d1ce690ca2 (patch) | |
| tree | 72f776cd64e48824a5578ff7a523bc69097143b4 /private.c | |
| parent | e6f1797e9e9925ae7f9dda54806ef8f52ae3ed07 (diff) | |
Major reorganisation of source code; new routine and tests added.
Diffstat (limited to 'private.c')
| -rw-r--r-- | private.c | 980 | 
1 files changed, 12 insertions, 968 deletions
| @@ -36,974 +36,18 @@   */  #include "pthread.h" -#include "semaphore.h"  #include "implement.h" -int -ptw32_processInitialize (void) -     /* -      * ------------------------------------------------------ -      * DOCPRIVATE -      *      This function performs process wide initialization for -      *      the pthread library. -      * -      * PARAMETERS -      *      N/A -      * -      * DESCRIPTION -      *      This function performs process wide initialization for -      *      the pthread library. -      *      If successful, this routine sets the global variable -      *      ptw32_processInitialized to TRUE. -      * -      * RESULTS -      * 	     TRUE    if successful, -      * 	     FALSE   otherwise -      * -      * ------------------------------------------------------ -      */ -{ -	if (ptw32_processInitialized) { -		/*  -		 * ignore if already initialized. this is useful for  -		 * programs that uses a non-dll pthread -		 * library. such programs must call ptw32_processInitialize() explicitely, -		 * since this initialization routine is automatically called only when -		 * the dll is loaded. -		 */ -		return TRUE; -	} - -  ptw32_processInitialized = TRUE; - -  /* -   * Initialize Keys -   */ -  if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) || -      (pthread_key_create (&ptw32_cleanupKey, NULL) != 0)) -    { - -      ptw32_processTerminate (); -    } - -  /*  -   * Set up the global test and init check locks. -   */ -  InitializeCriticalSection(&ptw32_mutex_test_init_lock); -  InitializeCriticalSection(&ptw32_cond_test_init_lock); -  InitializeCriticalSection(&ptw32_rwlock_test_init_lock); -  InitializeCriticalSection(&ptw32_spinlock_test_init_lock); - -  return (ptw32_processInitialized); - -}				/* processInitialize */ - -void -ptw32_processTerminate (void) -     /* -      * ------------------------------------------------------ -      * DOCPRIVATE -      *      This function performs process wide termination for -      *      the pthread library. -      * -      * PARAMETERS -      *      N/A -      * -      * DESCRIPTION -      *      This function performs process wide termination for -      *      the pthread library. -      *      This routine sets the global variable -      *      ptw32_processInitialized to FALSE -      * -      * RESULTS -      * 	     N/A -      * -      * ------------------------------------------------------ -      */ -{ -  if (ptw32_processInitialized) -    { - -      if (ptw32_selfThreadKey != NULL) -	{ -	  /* -	   * Release ptw32_selfThreadKey -	   */ -	  pthread_key_delete (ptw32_selfThreadKey); - -	  ptw32_selfThreadKey = NULL; -	} - -      if (ptw32_cleanupKey != NULL) -	{ -	  /* -	   * Release ptw32_cleanupKey -	   */ -	  pthread_key_delete (ptw32_cleanupKey); - -	  ptw32_cleanupKey = NULL; -	} - -      /*  -       * Destroy the global test and init check locks. -       */ -      DeleteCriticalSection(&ptw32_spinlock_test_init_lock); -      DeleteCriticalSection(&ptw32_rwlock_test_init_lock); -      DeleteCriticalSection(&ptw32_cond_test_init_lock); -      DeleteCriticalSection(&ptw32_mutex_test_init_lock); - -      ptw32_processInitialized = FALSE; -    } - -}				/* processTerminate */ - -#ifdef __CLEANUP_SEH - -static DWORD -ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) -{ -  switch (ep->ExceptionRecord->ExceptionCode) -    { -      case EXCEPTION_PTW32_SERVICES: -	{ -	  DWORD param; -	  DWORD numParams = ep->ExceptionRecord->NumberParameters; - -	  numParams = (numParams > 3) ? 3 : numParams; - -	  for (param = 0; param < numParams; param++) -	    { -	      ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; -	    } - -	  return EXCEPTION_EXECUTE_HANDLER; -	  break; -	} -      default: -	{ -	  /* -	   * A system unexpected exception has occurred running the user's -	   * routine. We need to cleanup before letting the exception -	   * out of thread scope. -	   */ -	  pthread_t self = pthread_self(); - -	  (void) pthread_mutex_destroy(&self->cancelLock); -	  ptw32_callUserDestroyRoutines(self); - -	  return EXCEPTION_CONTINUE_SEARCH; -	  break; -	} -    } -} - -#elif defined(__CLEANUP_CXX) - -#if defined(_MSC_VER) -#include <eh.h> -static terminate_function ptw32_oldTerminate; -#else -#include <new.h> -static terminate_handler ptw32_oldTerminate; -#endif - -#if 0 -#include <stdio.h> -static pthread_mutex_t termLock = PTHREAD_MUTEX_INITIALIZER; -#endif - -void -ptw32_terminate () -{ -  pthread_t self = pthread_self(); -#if 0 -  FILE * fp; -  pthread_mutex_lock(&termLock); -  fp = fopen("pthread.log", "a"); -  fprintf(fp, "Terminate\n"); -  fclose(fp); -  pthread_mutex_unlock(&termLock); -#endif -  set_terminate(ptw32_oldTerminate); -  (void) pthread_mutex_destroy(&self->cancelLock); -  ptw32_callUserDestroyRoutines(self); -  terminate(); -} - -#endif /* _MSC_VER */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -unsigned __stdcall -#else -void -#endif -ptw32_threadStart (void * vthreadParms) -{ -  ThreadParms *threadParms = (ThreadParms *) vthreadParms; -  pthread_t self; -  void *(*start) (void *); -  void *arg; - -#ifdef __CLEANUP_SEH -  DWORD ei[] = {0,0,0}; -#endif - -#ifdef __CLEANUP_C -  int setjmp_rc; -#endif - -  void * status = (void *) 0; - -  self = threadParms->tid; -  start = threadParms->start; -  arg = threadParms->arg; - -  free (threadParms); - -#if defined (__MINGW32__) && ! defined (__MSVCRT__) -  /* -   * beginthread does not return the thread id and is running -   * before it returns us the thread handle, and so we do it here. -   */ -  self->thread = GetCurrentThreadId (); -  /* -   * Here we're using cancelLock as a general-purpose lock -   * to make the new thread wait until the creating thread -   * has the new handle. -   */ -  if (pthread_mutex_lock(&self->cancelLock) == 0) -    { -      (void) pthread_mutex_unlock(&self->cancelLock); -    } -#endif - -  pthread_setspecific (ptw32_selfThreadKey, self); - -  self->state = PThreadStateRunning; - -#ifdef __CLEANUP_SEH - -  __try -  { -    /* -     * Run the caller's routine; -     */ -    status = self->exitStatus = (*start) (arg); - -#ifdef _UWIN -	if (--pthread_count <= 0) -		exit(0); -#endif - -  } -  __except (ExceptionFilter(GetExceptionInformation(), ei)) -  { -     switch (ei[0]) -       { -	case PTW32_EPS_CANCEL: -	  status = PTHREAD_CANCELED; -#ifdef _UWIN -		if (--pthread_count <= 0) -			exit(0); -#endif -	  break; -	case PTW32_EPS_EXIT: -	  status = self->exitStatus; -	  break; -	default: -	  status = PTHREAD_CANCELED; -	  break; -       } -  } - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - -  setjmp_rc = setjmp( self->start_mark ); - -  if( 0 == setjmp_rc ) { - -	  /* -	   * Run the caller's routine; -	   */ -	  status = self->exitStatus = (*start) (arg); -  } - -  else { - -     switch (setjmp_rc) -       { -	case PTW32_EPS_CANCEL: -	  status = PTHREAD_CANCELED; -	  break; -	case PTW32_EPS_EXIT: -	  status = self->exitStatus; -	  break; -	default: -	  status = PTHREAD_CANCELED; -	  break; -       } -  } - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - -  ptw32_oldTerminate = set_terminate(&ptw32_terminate); - -  try -  { -    /* -     * Run the caller's routine in a nested try block so that we -     * can run the user's terminate function, which may call -     * pthread_exit() or be canceled. -     */ -    try -      { -	status = self->exitStatus = (*start) (arg); -      } -    catch (ptw32_exception &) -      { -	/* -	 * Pass these through to the outer block. -	 */ -	throw; -      } -    catch(...) -     { -       /* -	* We want to run the user's terminate function if supplied. -	* That function may call pthread_exit() or be canceled, which will -	* be handled by the outer try block. -	* -	* ptw32_terminate() will be called if there is no user -	* supplied function. -	*/ - -#if defined(_MSC_VER) -       terminate_function term_func = set_terminate(0); -#else -       terminate_handler term_func = set_terminate(0); -#endif - -       set_terminate(term_func); - -       if (term_func != 0) { -	   term_func(); -       } - -       throw; -     } -  } -  catch (ptw32_exception_cancel &) -    { -      /* -       * Thread was canceled. -       */ -      status = self->exitStatus = PTHREAD_CANCELED; -    } -  catch (ptw32_exception_exit &) -    { -      /* -       * Thread was exited via pthread_exit(). -       */ -      status = self->exitStatus; -    } -  catch (...) -    { -      /* -       * A system unexpected exception has occurred running the user's -       * terminate routine. We get control back within this block - cleanup -       * and release the exception out of thread scope. -       */ -      status = self->exitStatus = PTHREAD_CANCELED; -      (void) pthread_mutex_lock(&self->cancelLock); -      self->state = PThreadStateException; -      (void) pthread_mutex_unlock(&self->cancelLock); -      (void) pthread_mutex_destroy(&self->cancelLock); -      (void) set_terminate(ptw32_oldTerminate); -      ptw32_callUserDestroyRoutines(self); -      throw; - -      /* -       * Never reached. -       */ -    } - -  (void) set_terminate(ptw32_oldTerminate); - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ -#endif /* __CLEANUP_C */ -#endif /* __CLEANUP_SEH */ - -  (void) pthread_mutex_lock(&self->cancelLock); -  self->state = PThreadStateLast; -  (void) pthread_mutex_unlock(&self->cancelLock); - - -  (void) pthread_mutex_destroy(&self->cancelLock); - -#if 1 -  if (self->detachState == PTHREAD_CREATE_DETACHED) -    { -      /* -       * We need to cleanup the pthread now in case we have -       * been statically linked, in which case the cleanup -       * in dllMain won't get done. Joinable threads will -       * be cleaned up by pthread_join(). -       * -       * Note that implicitly created pthreads (those created -       * for Win32 threads which have called pthreads routines) -       * must be cleaned up explicitly by the application  -       * (by calling pthread_win32_thread_detach_np()) if -       * this library has been statically linked. For the dll, -       * dllMain will do the cleanup automatically. -       */ -      (void) pthread_win32_thread_detach_np (); -    } -  else -    { -      ptw32_callUserDestroyRoutines (self); -    } -#else -  ptw32_callUserDestroyRoutines (self); -#endif - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -  _endthreadex ((unsigned) status); -#else -  _endthread (); -#endif - -  /* -   * Never reached. -   */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -  return (unsigned) status; -#endif - -}				/* ptw32_threadStart */ - -void -ptw32_threadDestroy (pthread_t thread) -{ -  if (thread != NULL) -    { -      ptw32_callUserDestroyRoutines (thread); - -      if (thread->cancelEvent != NULL) -	{ -	  CloseHandle (thread->cancelEvent); -	} - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) -      /* See documentation for endthread vs endthreadex. */ -      if( thread->threadH != 0 ) -	{ -	  CloseHandle( thread->threadH ); -	} -#endif - -      free (thread); -    } - -}				/* ptw32_threadDestroy */ - -int -ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP, -			pthread_t thread, -			pthread_key_t key) -     /* -      * ------------------------------------------------------------------- -      * This routine creates an association that -      * is unique for the given (thread,key) combination.The association  -      * is referenced by both the thread and the key. -      * This association allows us to determine what keys the -      * current thread references and what threads a given key -      * references. -      * See the detailed description -      * at the beginning of this file for further details. -      * -      * Notes: -      *      1)      New associations are pushed to the beginning of the -      * 	     chain so that the internal ptw32_selfThreadKey association -      * 	     is always last, thus allowing selfThreadExit to -      * 	     be implicitly called by pthread_exit last. -      * -      * Parameters: -      * 	     assocP -      * 		     address into which the association is returned. -      * 	     thread -      * 		     current running thread. If NULL, then association -      * 		     is only added to the key. A NULL thread indicates -      * 		     that the user called pthread_setspecific prior -      * 		     to starting a thread. That's ok. -      * 	     key -      * 		     key on which to create an association. -      * Returns: -      *       0 	     - if successful, -      *       ENOMEM	     - not enough memory to create assoc or other object -      *       EINVAL	     - an internal error occurred -      *       ENOSYS	     - an internal error occurred -      * ------------------------------------------------------------------- -      */ -{ -  int result; -  ThreadKeyAssoc *assoc; - -  /* -   * Have to create an association and add it -   * to both the key and the thread. -   */ -  assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); - -  if (assoc == NULL) -    { -      result = ENOMEM; -      goto FAIL0; -    } - -  /* -   * Initialise only when used for the first time. -   */ -  assoc->lock = PTHREAD_MUTEX_INITIALIZER; -  assoc->thread = thread; -  assoc->key = key; - -  /* -   * Register assoc with key -   */ -  if ((result = pthread_mutex_lock (&(key->threadsLock))) != 0) -    { -      goto FAIL2; -    } - -  assoc->nextThread = (ThreadKeyAssoc *) key->threads; -  key->threads = (void *) assoc; - -  pthread_mutex_unlock (&(key->threadsLock)); - -  if (thread != NULL) -    { -      /* -       * Register assoc with thread -       */ -      assoc->nextKey = (ThreadKeyAssoc *) thread->keys; -      thread->keys = (void *) assoc; -    } - -  *assocP = assoc; - -  return (result); - -  /* -   * ------------- -   * Failure Code -   * ------------- -   */ -FAIL2: -  pthread_mutex_destroy (&(assoc->lock)); -  free (assoc); - -FAIL0: - -  return (result); - -}				/* ptw32_tkAssocCreate */ - - -void -ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) -     /* -      * ------------------------------------------------------------------- -      * This routine releases all resources for the given ThreadKeyAssoc -      * once it is no longer being referenced -      * ie) both the key and thread have stopped referencing it. -      * -      * Parameters: -      * 	     assoc -      * 		     an instance of ThreadKeyAssoc. -      * Returns: -      *      N/A -      * ------------------------------------------------------------------- -      */ -{ - -  if ((assoc != NULL) && -      (assoc->key == NULL && assoc->thread == NULL)) -    { - -      pthread_mutex_destroy (&(assoc->lock)); - -      free (assoc); -    } - -}				/* ptw32_tkAssocDestroy */ - - -void -ptw32_callUserDestroyRoutines (pthread_t thread) -     /* -      * ------------------------------------------------------------------- -      * DOCPRIVATE -      * -      * This the routine runs through all thread keys and calls -      * the destroy routines on the user's data for the current thread. -      * It simulates the behaviour of POSIX Threads. -      * -      * PARAMETERS -      * 	     thread -      * 		     an instance of pthread_t -      * -      * RETURNS -      * 	     N/A -      * ------------------------------------------------------------------- -      */ -{ -  ThreadKeyAssoc **nextP; -  ThreadKeyAssoc *assoc; - -  if (thread != NULL) -    { -      /* -       * Run through all Thread<-->Key associations -       * for the current thread. -       * If the pthread_key_t still exits (ie the assoc->key -       * is not NULL) then call the user's TSD destroy routine. -       * Notes: -       *      If assoc->key is NULL, then the user previously called -       *      PThreadKeyDestroy. The association is now only referenced -       *      by the current thread and must be released; otherwise -       *      the assoc will be destroyed when the key is destroyed. -       */ -      nextP = (ThreadKeyAssoc **) & (thread->keys); -      assoc = *nextP; - -      while (assoc != NULL) -	{ - -	  if (pthread_mutex_lock (&(assoc->lock)) == 0) -	    { -	      pthread_key_t k; -	      if ((k = assoc->key) != NULL) -		{ -		  /* -		   * Key still active; pthread_key_delete -		   * will block on this same mutex before -		   * it can release actual key; therefore, -		   * key is valid and we can call the destroy -		   * routine; -		   */ -		  void *value = NULL; - -		  value = pthread_getspecific (k); -		  if (value != NULL && k->destructor != NULL) -		    { - -#ifdef __cplusplus - -		      try -		      { -			/* -			 * Run the caller's cleanup routine. -			 */ -			(*(k->destructor)) (value); -		      } -		      catch (...) -		      { -			/* -			 * A system unexpected exception has occurred -			 * running the user's destructor. -			 * We get control back within this block in case -			 * the application has set up it's own terminate -			 * handler. Since we are leaving the thread we -			 * should not get any internal pthreads -			 * exceptions. -			 */ -			terminate(); -		      } - -#else  /* __cplusplus */ - -			/* -			 * Run the caller's cleanup routine. -			 */ -			(*(k->destructor)) (value); - -#endif /* __cplusplus */ -		    } -		} - -	      /* -	       * mark assoc->thread as NULL to indicate the -	       * thread no longer references this association -	       */ -	      assoc->thread = NULL; - -	      /* -	       * Remove association from the pthread_t chain -	       */ -	      *nextP = assoc->nextKey; - -	      pthread_mutex_unlock (&(assoc->lock)); - -	      ptw32_tkAssocDestroy (assoc); - -	      assoc = *nextP; -	    } -	} -    } - -}				/* ptw32_callUserDestroyRoutines */ - - - -#ifdef NEED_FTIME - -/* - * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds - */ -#define TIMESPEC_TO_FILETIME_OFFSET \ -	  ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) - -static INLINE void -timespec_to_filetime(const struct timespec *ts, FILETIME *ft) -     /* -      * ------------------------------------------------------------------- -      * converts struct timespec -      * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. -      * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is -      * expressed in 100 nanoseconds from Jan 1, 1601, -      * ------------------------------------------------------------------- -      */ -{ -	*(LONGLONG *)ft = ts->tv_sec * 10000000 + (ts->tv_nsec + 50) / 100 + TIMESPEC_TO_FILETIME_OFFSET; -} - -static INLINE void -filetime_to_timespec(const FILETIME *ft, struct timespec *ts) -     /* -      * ------------------------------------------------------------------- -      * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is -      * expressed in 100 nanoseconds from Jan 1, 1601, -      * into struct timespec -      * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. -      * ------------------------------------------------------------------- -      */ -{ -	ts->tv_sec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); -	ts->tv_nsec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG)ts->tv_sec * (LONGLONG)10000000)) * 100); -} - -#endif /* NEED_FTIME */ - - -DWORD -ptw32_get_exception_services_code(void) -{ -#ifdef __CLEANUP_SEH - -  return EXCEPTION_PTW32_SERVICES; - -#else - -  return (DWORD) NULL; - -#endif -} - - -void -ptw32_throw(DWORD exception) -{ -#ifdef __CLEANUP_C -  pthread_t self = pthread_self(); -#endif - - -#ifdef __CLEANUP_SEH -  DWORD exceptionInformation[3]; -#endif - -  if (exception != PTW32_EPS_CANCEL && -      exception != PTW32_EPS_EXIT) -    { -      /* Should never enter here */ -      exit(1); -    } - -#ifdef __CLEANUP_SEH - - -  exceptionInformation[0] = (DWORD) (exception); -  exceptionInformation[1] = (DWORD) (0); -  exceptionInformation[2] = (DWORD) (0); - -  RaiseException ( -		  EXCEPTION_PTW32_SERVICES, -		  0, -		  3, -		  exceptionInformation); - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - -  ptw32_pop_cleanup_all( 1 ); - -  longjmp( self->start_mark, exception ); - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - -  switch (exception) -    { -    case PTW32_EPS_CANCEL: -      throw ptw32_exception_cancel(); -      break; -    case PTW32_EPS_EXIT: -      throw ptw32_exception_exit(); -      break; -    } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - -  /* Never reached */ -} - -void -ptw32_pop_cleanup_all(int execute) -{ -	while( NULL != ptw32_pop_cleanup(execute) ) { -	} -} - - -/* - * ptw32_InterlockedCompareExchange -- - * - * Needed because W95 doesn't support InterlockedCompareExchange. - * It is only used when running the dll on W95. Other versions of - * Windows use the Win32 supported version, which may be running on - * different processor types. - * - * This can't be inlined because we need to know it's address so that - * we can call it through a pointer. - */ -PTW32_INTERLOCKED_LONG WINAPI -ptw32_InterlockedCompareExchange(PTW32_INTERLOCKED_LPLONG location, -				 PTW32_INTERLOCKED_LONG   value, -				 PTW32_INTERLOCKED_LONG   comparand) -{ -  PTW32_INTERLOCKED_LONG result; - -#if defined(_M_IX86) || defined(_X86_) - -#if defined(_MSC_VER) - -  _asm { -    PUSH	 ecx -    PUSH	 edx -    MOV 	 ecx,dword ptr [location] -    MOV 	 edx,dword ptr [value] -    MOV 	 eax,dword ptr [comparand] -    LOCK CMPXCHG dword ptr [ecx],edx	    ; if (EAX == [ECX]),  -					    ;	[ECX] = EDX -					    ; else -					    ;	EAX = [ECX] -    MOV 	 dword ptr [result], eax -    POP 	 edx -    POP 	 ecx -  } - -#elif defined(__GNUC__) - -  __asm__ -    ( -     "lock\n\t" -     "cmpxchgl	     %3,(%0)"	 /* if (EAX == [location]), */ -				 /*   [location] = value    */ -				 /* else		    */ -				 /*   EAX = [location]		 */ -     :"=r" (location), "=a" (result) -     :"0"  (location), "q" (value), "a" (comparand) -     : "memory" ); - -#endif - -#else - -  /* -   * If execution gets to here then we should be running on a Win95 system -   * but either running on something other than an X86 processor, or a -   * compiler other than MSVC or GCC. Pthreads-win32 doesn't support that -   * platform (yet). -   */ - -  result = 0; - -#endif - -  return result; -} - - -/* - * ptw32_getprocessors() - * - * Get the number of CPUs available to the process. - * - * If the available number of CPUs is 1 then pthread_spin_lock() - * will block rather than spin if the lock is already owned. - * - * pthread_spin_init() calls this routine when initialising - * a spinlock. If the number of available processors changes - * (after a call to SetProcessAffinityMask()) then only - * newly initialised spinlocks will notice. - */ -int -ptw32_getprocessors(int * count) -{ -  DWORD vProcessCPUs; -  DWORD vSystemCPUs; -  int result = 0; - -  if (GetProcessAffinityMask(GetCurrentProcess(), -			     &vProcessCPUs, -			     &vSystemCPUs)) -    { -      DWORD bit; -      int CPUs = 0; - -      for (bit = 1; bit != 0; bit <<= 1) -	{ -	  if (vProcessCPUs & bit) -	    { -	      CPUs++; -	    } -	} -      *count = CPUs; -    } -  else -    { -      result = EAGAIN; -    } - -  return(result); -} +#include "ptw32_is_attr.c" +#include "ptw32_processInitialize.c" +#include "ptw32_processTerminate.c" +#include "ptw32_threadStart.c" +#include "ptw32_threadDestroy.c" +#include "ptw32_tkAssocCreate.c" +#include "ptw32_tkAssocDestroy.c" +#include "ptw32_callUserDestroyRoutines.c" +#include "ptw32_timespec.c" +#include "ptw32_throw.c" +#include "ptw32_InterlockedCompareExchange.c" +#include "ptw32_getprocessors.c" | 
