summaryrefslogtreecommitdiff
path: root/spin.c
diff options
context:
space:
mode:
Diffstat (limited to 'spin.c')
-rw-r--r--spin.c281
1 files changed, 6 insertions, 275 deletions
diff --git a/spin.c b/spin.c
index 5d33214..8947164 100644
--- a/spin.c
+++ b/spin.c
@@ -38,279 +38,10 @@
#include "implement.h"
-static INLINE int
-ptw32_spinlock_check_need_init(pthread_spinlock_t *lock)
-{
- int result = 0;
+#include "ptw32_spinlock_check_need_init.c"
+#include "pthread_spin_init.c"
+#include "pthread_spin_destroy.c"
+#include "pthread_spin_lock.c"
+#include "pthread_spin_unlock.c"
+#include "pthread_spin_trylock.c"
- /*
- * The following guarded test is specifically for statically
- * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER).
- *
- * Note that by not providing this synchronisation we risk
- * introducing race conditions into applications which are
- * correctly written.
- */
- EnterCriticalSection(&ptw32_spinlock_test_init_lock);
-
- /*
- * We got here possibly under race
- * conditions. Check again inside the critical section
- * and only initialise if the spinlock is valid (not been destroyed).
- * If a static spinlock has been destroyed, the application can
- * re-initialise it only by calling pthread_spin_init()
- * explicitly.
- */
- if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
- {
- result = pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE);
- }
- else if (*lock == NULL)
- {
- /*
- * The spinlock has been destroyed while we were waiting to
- * initialise it, so the operation that caused the
- * auto-initialisation should fail.
- */
- result = EINVAL;
- }
-
- LeaveCriticalSection(&ptw32_spinlock_test_init_lock);
-
- return(result);
-}
-
-
-int
-pthread_spin_init(pthread_spinlock_t *lock, int pshared)
-{
- pthread_spinlock_t s;
- int cpus = 0;
- int result = 0;
-
- if (lock == NULL)
- {
- return EINVAL;
- }
-
- if (0 != ptw32_getprocessors(&cpus))
- {
- cpus = 1;
- }
-
- if (cpus > 1)
- {
- if (pshared == PTHREAD_PROCESS_SHARED)
- {
- /*
- * Creating spinlock that can be shared between
- * processes.
- */
-#if _POSIX_THREAD_PROCESS_SHARED
-
- /*
- * Not implemented yet.
- */
-
-#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet.
-
-#else
-
- return ENOSYS;
-
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
-
- }
- }
-
- s = (pthread_spinlock_t) calloc(1, sizeof(*s));
-
- if (s == NULL)
- {
- return ENOMEM;
- }
-
- if (cpus > 1)
- {
- s->u.cpus = cpus;
- s->interlock = PTW32_SPIN_UNLOCKED;
- }
- else
- {
- pthread_mutexattr_t ma;
- result = pthread_mutexattr_init(&ma);
-
- if (0 == result)
- {
- ma->pshared = pshared;
- result = pthread_mutex_init(&(s->u.mutex), &ma);
- if (0 == result)
- {
- s->interlock = PTW32_SPIN_USE_MUTEX;
- }
- }
- (void) pthread_mutexattr_destroy(&ma);
- }
-
- if (0 == result)
- {
- *lock = s;
- }
- else
- {
- (void) free(s);
- *lock = NULL;
- }
-
- return(result);
-}
-
-int
-pthread_spin_destroy(pthread_spinlock_t *lock)
-{
- register pthread_spinlock_t s;
-
- if (lock == NULL || *lock == NULL)
- {
- return EINVAL;
- }
-
- if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER)
- {
- if (s->interlock == PTW32_SPIN_USE_MUTEX)
- {
- return pthread_mutex_destroy(&(s->u.mutex));
- }
-
- 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;
- }
-
- return EINVAL;
- }
- else
- {
- int result = 0;
-
- /*
- * See notes in ptw32_spinlock_check_need_init() above also.
- */
- EnterCriticalSection(&ptw32_spinlock_test_init_lock);
-
- /*
- * Check again.
- */
- if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
- {
- /*
- * This is all we need to do to destroy a statically
- * initialised spinlock that has not yet been used (initialised).
- * If we get to here, another thread
- * waiting to initialise this mutex will get an EINVAL.
- */
- *lock = NULL;
- }
- else
- {
- /*
- * The spinlock has been initialised while we were waiting
- * so assume it's in use.
- */
- result = EBUSY;
- }
-
- LeaveCriticalSection(&ptw32_spinlock_test_init_lock);
- return(result);
- }
-}
-
-/*
- * NOTE: For speed, these routines don't check if "lock" is valid.
- */
-int
-pthread_spin_lock(pthread_spinlock_t *lock)
-{
- register pthread_spinlock_t s;
-
- if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
- {
- int result;
-
- if ((result = ptw32_spinlock_check_need_init(lock)) != 0)
- {
- return(result);
- }
- }
-
- s = *lock;
-
- 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)
- {
- return 0;
- }
- else if (s->interlock == PTW32_SPIN_USE_MUTEX)
- {
- return pthread_mutex_lock(&(s->u.mutex));
- }
-
- return EINVAL;
-}
-
-int
-pthread_spin_unlock(pthread_spinlock_t *lock)
-{
- register pthread_spinlock_t s = *lock;
-
- if (s == PTHREAD_SPINLOCK_INITIALIZER)
- {
- return EPERM;
- }
-
- 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;
- case PTW32_SPIN_USE_MUTEX: return pthread_mutex_unlock(&(s->u.mutex));
- }
-
- return EINVAL;
-}
-
-int
-pthread_spin_trylock(pthread_spinlock_t *lock)
-{
- pthread_spinlock_t s = *lock;
-
- if (s == PTHREAD_SPINLOCK_INITIALIZER)
- {
- int result;
-
- if ((result = ptw32_spinlock_check_need_init(lock)) != 0)
- {
- return(result);
- }
- }
-
- 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;
- case PTW32_SPIN_USE_MUTEX: return pthread_mutex_trylock(&(s->u.mutex));
- }
-
- return EINVAL;
-}