summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--Nmakefile.tests2
-rw-r--r--barrier.c18
-rw-r--r--global.c8
-rw-r--r--implement.h18
-rw-r--r--nonportable.c47
-rw-r--r--private.c68
-rw-r--r--sched.c14
-rw-r--r--spin.c35
-rw-r--r--tests/GNUmakefile3
-rw-r--r--tests/Makefile3
11 files changed, 200 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index c4c90fd..489aa84 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/barrier.c b/barrier.c
index 3cfa66f..e989095 100644
--- a/barrier.c
+++ b/barrier.c
@@ -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);
}
diff --git a/global.c b/global.c
index 92ea8da..3a1c635 100644
--- a/global.c
+++ b/global.c
@@ -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;
diff --git a/private.c b/private.c
index a332385..f97d9f4 100644
--- a/private.c
+++ b/private.c
@@ -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;
+}
diff --git a/sched.c b/sched.c
index bc8aca0..8ef502f 100644
--- a/sched.c
+++ b/sched.c
@@ -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
}
diff --git a/spin.c b/spin.c
index b35b9f0..09c5031 100644
--- a/spin.c
+++ b/spin.c
@@ -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