diff options
| author | rpj <rpj> | 2001-10-25 13:24:58 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 2001-10-25 13:24:58 +0000 | 
| commit | 222a76c37c89ee37eebecd53dd32fd481245e6fa (patch) | |
| tree | 160ed8d069da4d9e94b16c436943def676e355c5 | |
| parent | 7b714286cfd65e797364fbdc583e13adba71a2ee (diff) | |
	* barrier.c: Move _LONG and _LPLONG defines into
	implement.h; rename to PTW32_INTERLOCKED_LONG and
	PTW32_INTERLOCKED_LPLONG respectively.
	* spin.c: Likewise; ptw32_interlocked_compare_exchange used
	in place of InterlockedCompareExchange directly.
	* global.c (ptw32_interlocked_compare_exchange): Add
	prototype for this new routine pointer to be used when
	InterlockedCompareExchange isn't supported by Windows.
	* nonportable.c (pthread_win32_process_attach_np): Check for
	support of InterlockedCompareExchange in kernel32 and assign its
	address to ptw32_interlocked_compare_exchange if it exists, or
	our own ix86 specific implementation ptw32_InterlockedCompareExchange.
	*private.c (ptw32_InterlockedCompareExchange): An
	implementation of InterlockedCompareExchange() which is
	specific to ix86; written directly in assembler for either
	MSVC or GNU C; needed because Windows 95 doesn't support
	InterlockedCompareExchange().
	* sched.c (sched_get_priority_min): Extend to return
	THREAD_PRIORITY_IDLE.
	(sched_get_priority_max): Extend to return
	THREAD_PRIORITY_CRITICAL.
| -rw-r--r-- | ChangeLog | 25 | ||||
| -rw-r--r-- | Nmakefile.tests | 2 | ||||
| -rw-r--r-- | barrier.c | 18 | ||||
| -rw-r--r-- | global.c | 8 | ||||
| -rw-r--r-- | implement.h | 18 | ||||
| -rw-r--r-- | nonportable.c | 47 | ||||
| -rw-r--r-- | private.c | 68 | ||||
| -rw-r--r-- | sched.c | 14 | ||||
| -rw-r--r-- | spin.c | 35 | ||||
| -rw-r--r-- | tests/GNUmakefile | 3 | ||||
| -rw-r--r-- | tests/Makefile | 3 | 
11 files changed, 200 insertions, 41 deletions
| @@ -7,6 +7,31 @@  	because STACK_MIN is 0 and stacksize is of type  	size_t (or unsigned int). +2001-10-17  Ross Johnson  <rpj@setup1.ise.canberra.edu.au> + +	* barrier.c: Move _LONG and _LPLONG defines into +	implement.h; rename to PTW32_INTERLOCKED_LONG and +	PTW32_INTERLOCKED_LPLONG respectively. +	* spin.c: Likewise; ptw32_interlocked_compare_exchange used +	in place of InterlockedCompareExchange directly. +	* global.c (ptw32_interlocked_compare_exchange): Add +	prototype for this new routine pointer to be used when +	InterlockedCompareExchange isn't supported by Windows. +	* nonportable.c (pthread_win32_process_attach_np): Check for +	support of InterlockedCompareExchange in kernel32 and assign its +	address to ptw32_interlocked_compare_exchange if it exists, or +	our own ix86 specific implementation ptw32_InterlockedCompareExchange. +	*private.c (ptw32_InterlockedCompareExchange): An +	implementation of InterlockedCompareExchange() which is +	specific to ix86; written directly in assembler for either +	MSVC or GNU C; needed because Windows 95 doesn't support +	InterlockedCompareExchange(). + +	* sched.c (sched_get_priority_min): Extend to return +	THREAD_PRIORITY_IDLE. +	(sched_get_priority_max): Extend to return +	THREAD_PRIORITY_CRITICAL. +  2001-10-15  Ross Johnson  <rpj@setup1.ise.canberra.edu.au>  	* spin.c (pthread_spin_lock): PTHREAD_SPINLOCK_INITIALIZER diff --git a/Nmakefile.tests b/Nmakefile.tests index 109a995..a99b1db 100644 --- a/Nmakefile.tests +++ b/Nmakefile.tests @@ -95,6 +95,7 @@ benchtest1::    benchtest1.c  benchtest2::    benchtest2.c
  benchtest3::    benchtest3.c
  benchtest4::    benchtest4.c
 +benchtest5::    benchtest5.c
  loadfree:	:test:
  mutex1		:test:	loadfree
 @@ -161,6 +162,7 @@ benchtest1      :test:  mutex3  benchtest2      :test:  benchtest1
  benchtest3      :test:  benchtest2
  benchtest4      :test:  benchtest3
 +benchtest5      :test:  benchtest4
  exception1	:test:	cancel4
  exception2	:test:	exception1
  exception3	:test:	exception2
 @@ -27,14 +27,6 @@  #include "implement.h" -#ifdef __MINGW32__ -#define _LONG long -#define _LPLONG long* -#else -#define _LONG PVOID -#define _LPLONG PVOID* -#endif -  int  pthread_barrier_init(pthread_barrier_t * barrier,                       const pthread_barrierattr_t * attr, @@ -169,14 +161,14 @@ pthread_barrier_wait(pthread_barrier_t *barrier)    /*     * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. -   * It also sets up the alternate semaphore as the next barrier. +   * This also sets up the alternate semaphore as the next barrier.     */    if (0 == result)      { -      result = ((_LONG) step == -                InterlockedCompareExchange((_LPLONG) &(b->iStep), -                                           (_LONG) (1L - step), -                                           (_LONG) step) +      result = ((PTW32_INTERLOCKED_LONG) step == +                ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(b->iStep), +                                                   (PTW32_INTERLOCKED_LONG) (1L - step), +                                                   (PTW32_INTERLOCKED_LONG) step)                  ? PTHREAD_BARRIER_SERIAL_THREAD                  : 0);      } @@ -34,6 +34,14 @@ pthread_key_t ptw32_cleanupKey = NULL;  int ptw32_concurrency = 0; +/*  + * Function pointer to InterlockedCompareExchange if it exists; otherwise NULL  + */ +PTW32_INTERLOCKED_LONG +(WINAPI *ptw32_interlocked_compare_exchange)(PTW32_INTERLOCKED_LPLONG, +                                             PTW32_INTERLOCKED_LONG, +                                             PTW32_INTERLOCKED_LONG) = NULL; +  /*   * Global lock for testing internal state of PTHREAD_MUTEX_INITIALIZER   * created mutexes. diff --git a/implement.h b/implement.h index 5c1d7ec..dfb2dba 100644 --- a/implement.h +++ b/implement.h @@ -45,6 +45,14 @@  #define INLINE  #endif +#ifdef __MINGW32__ +#define PTW32_INTERLOCKED_LONG long +#define PTW32_INTERLOCKED_LPLONG long* +#else +#define PTW32_INTERLOCKED_LONG PVOID +#define PTW32_INTERLOCKED_LPLONG PVOID* +#endif +  typedef enum {    /*     * This enumeration represents the state of the thread; @@ -410,6 +418,16 @@ extern "C" {   * =====================   * =====================   */ +PTW32_INTERLOCKED_LONG +(WINAPI *ptw32_interlocked_compare_exchange)(PTW32_INTERLOCKED_LPLONG, +                                             PTW32_INTERLOCKED_LONG, +                                             PTW32_INTERLOCKED_LONG); + +PTW32_INTERLOCKED_LONG +ptw32_InterlockedCompareExchange(PTW32_INTERLOCKED_LPLONG ptr, +                                 PTW32_INTERLOCKED_LONG   value, +                                 PTW32_INTERLOCKED_LONG   comparand); +  int ptw32_processInitialize (void);  void ptw32_processTerminate (void); diff --git a/nonportable.c b/nonportable.c index 5fcb1b8..de9dc07 100644 --- a/nonportable.c +++ b/nonportable.c @@ -179,6 +179,11 @@ pthread_getprocessors_np(int * count)  } +/* + * Handle to kernel32.dll  + */ +static HINSTANCE ptw32_h_kernel32; +  BOOL  pthread_win32_process_attach_np ()  { @@ -189,6 +194,43 @@ pthread_win32_process_attach_np ()    pthread_count++;  #endif +  /* +   * Load KERNEL32 and try to get address of InterlockedCompareExchange +   */ +  ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); + +  ptw32_interlocked_compare_exchange = +    (PTW32_INTERLOCKED_LONG (PT_STDCALL *)(PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG)) +#if defined(NEED_UNICODE_CONSTS) +    GetProcAddress(ptw32_h_kernel32, +                   (const TCHAR *)TEXT("InterlockedCompareExchange")); +#else +    GetProcAddress(ptw32_h_kernel32, +                   (LPCSTR) "InterlockedCompareExchange"); +#endif + +  if (ptw32_interlocked_compare_exchange == NULL) +    { +      ptw32_interlocked_compare_exchange = &ptw32_InterlockedCompareExchange; + +      /* +       * If InterlockedCompareExchange is not being used, then free +       * the kernel32.dll handle now, rather than leaving it until +       * DLL_PROCESS_DETACH. +       * +       * Note: this is not a pedantic exercise in freeing unused +       * resources!  It is a work-around for a bug in Windows 95 +       * (see microsoft knowledge base article, Q187684) which +       * does Bad Things when FreeLibrary is called within +       * the DLL_PROCESS_DETACH code, in certain situations. +       * Since w95 just happens to be a platform which does not +       * provide InterlockedCompareExchange, the bug will be +       * effortlessly avoided. +       */ +      (void) FreeLibrary(ptw32_h_kernel32); +      ptw32_h_kernel32 = 0; +    } +    return result;  } @@ -214,6 +256,11 @@ pthread_win32_process_detach_np ()         * The DLL is being unmapped into the process's address space         */        ptw32_processTerminate (); + +      if (ptw32_h_kernel32) +        { +           (void) FreeLibrary(ptw32_h_kernel32); +        }      }    return TRUE; @@ -1020,3 +1020,71 @@ 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 +ptw32_InterlockedCompareExchange(PTW32_INTERLOCKED_LPLONG ptr, +                                 PTW32_INTERLOCKED_LONG   value, +                                 PTW32_INTERLOCKED_LONG   comparand) +{ +  PTW32_INTERLOCKED_LONG result; + +#if defined(_M_IX86) || defined(_X86_) + +#if defined(__MSVCRT__) + +  _asm { +    PUSH         ecx +    PUSH         edx +    MOV          ecx,dword ptr [ptr]        ; Load ECX with plTarget +    MOV          edx,dword ptr [value]      ; Load EDX with lValue +    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 == [ptr]), */ +                                 /*   [ptr] = value    */ +                                 /* else               */ +                                 /*   EAX = [ptr]      */ +     :"=r" (ptr), "=a" (result) +     :"0"  (ptr), "q" (value), "a" (comparand) +     : "memory" ); + +#endif + +#else + +  /* +   * If we get 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; +} @@ -155,6 +155,8 @@ int  pthread_setschedparam(pthread_t thread, int policy,  			  const struct sched_param *param)  { +  int prio; +    /* Validate the thread id. */    if (thread == NULL || thread->threadH == 0)      { @@ -173,15 +175,17 @@ pthread_setschedparam(pthread_t thread, int policy,        return ENOTSUP;      } +  prio = param->sched_priority; +    /* Validate priority level. */ -  if (param->sched_priority < sched_get_priority_min(policy) || -      param->sched_priority > sched_get_priority_max(policy)) +  if (prio < sched_get_priority_min(policy) || +      prio > sched_get_priority_max(policy))      {        return EINVAL;      }    /* This is practically guaranteed to return TRUE. */ -  (void) SetThreadPriority(thread->threadH, param->sched_priority); +  (void) SetThreadPriority(thread->threadH, prio);    return 0;  } @@ -253,7 +257,7 @@ sched_get_priority_max(int policy)    return sched_Max(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);  #else    /* This is independent of scheduling policy in Win32. */ -  return sched_Max(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST); +  return sched_Max(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL)  #endif  } @@ -271,7 +275,7 @@ sched_get_priority_min(int policy)    return sched_Min(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);  #else    /* This is independent of scheduling policy in Win32. */ -  return sched_Min(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST); +  return sched_Min(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);  #endif  } @@ -26,13 +26,6 @@  #include "pthread.h"  #include "implement.h" -#ifdef __MINGW32__ -#define _LONG long -#define _LPLONG long* -#else -#define _LONG PVOID -#define _LPLONG PVOID* -#endif  static INLINE int  ptw32_spinlock_check_need_init(pthread_spinlock_t *lock) @@ -177,10 +170,10 @@ pthread_spin_destroy(pthread_spinlock_t *lock)            return pthread_mutex_destroy(&(s->u.mutex));          } -      if ( (_LONG) PTW32_SPIN_UNLOCKED == -           InterlockedCompareExchange((_LPLONG) &(s->interlock), -                                      (_LONG) PTW32_OBJECT_INVALID, -                                      (_LONG) PTW32_SPIN_UNLOCKED)) +      if ( (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED == +           ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(s->interlock), +                                              (PTW32_INTERLOCKED_LONG) PTW32_OBJECT_INVALID, +                                              (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED))          {            return 0;          } @@ -243,10 +236,10 @@ pthread_spin_lock(pthread_spinlock_t *lock)    s = *lock; -  while ( (_LONG) PTW32_SPIN_LOCKED == -          InterlockedCompareExchange((_LPLONG) &(s->interlock), -                                     (_LONG) PTW32_SPIN_LOCKED, -                                     (_LONG) PTW32_SPIN_UNLOCKED) ) +  while ( (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED == +          ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(s->interlock), +                                             (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, +                                             (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED) )      {}    if (s->interlock == PTW32_SPIN_LOCKED) @@ -271,9 +264,9 @@ pthread_spin_unlock(pthread_spinlock_t *lock)        return EPERM;      } -  switch ((long) InterlockedCompareExchange((_LPLONG) &(s->interlock), -                                            (_LONG) PTW32_SPIN_UNLOCKED, -                                            (_LONG) PTW32_SPIN_LOCKED )) +  switch ((long) ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(s->interlock), +                                                    (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED, +                                                    (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED ))      {        case PTW32_SPIN_LOCKED:    return 0;        case PTW32_SPIN_UNLOCKED:  return EPERM; @@ -298,9 +291,9 @@ pthread_spin_trylock(pthread_spinlock_t *lock)          }      } -  switch ((long) InterlockedCompareExchange((_LPLONG) &(s->interlock), -                                            (_LONG) PTW32_SPIN_LOCKED, -                                            (_LONG) PTW32_SPIN_UNLOCKED )) +  switch ((long) ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(s->interlock), +                                                    (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, +                                                    (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED ))      {        case PTW32_SPIN_UNLOCKED:  return 0;        case PTW32_SPIN_LOCKED:    return EBUSY; diff --git a/tests/GNUmakefile b/tests/GNUmakefile index d62e45c..8e06c68 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -53,7 +53,7 @@ TESTS	= loadfree \  	  exception1 exception2 exception3  BENCHTESTS = \ -	benchtest1 benchtest2 benchtest3 benchtest4 +	benchtest1 benchtest2 benchtest3 benchtest4 benchtest5  PASSES		= $(TESTS:%=%.pass)  BENCHRESULTS	= $(BENCHTESTS:%=%.bench) @@ -91,6 +91,7 @@ benchtest1.bench:  benchtest2.bench:  benchtest3.bench:  benchtest4.bench: +benchtest5.bench:  barrier1.pass:  barrier2.pass: barrier1.pass diff --git a/tests/Makefile b/tests/Makefile index dba30d3..1a7b6bf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -62,7 +62,7 @@ PASSES= loadfree.pass \  	  exception1.pass  exception2.pass  exception3.pass
  BENCHRESULTS = \
 -	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench
 +	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
  all:
  	@ $(ECHO) Run one of the following command lines:
 @@ -147,6 +147,7 @@ benchtest1.bench:  benchtest2.bench:
  benchtest3.bench:
  benchtest4.bench:
 +benchtest5.bench:
  barrier1.pass:
  barrier2.pass: barrier1.pass
  barrier3.pass: barrier2.pass
 | 
