diff --git a/server/core/spinlock.c b/server/core/spinlock.c index 614d1249b..3c75e9c94 100644 --- a/server/core/spinlock.c +++ b/server/core/spinlock.c @@ -30,6 +30,7 @@ #include #include +#include /** * Initialise a spinlock. @@ -39,13 +40,13 @@ void spinlock_init(SPINLOCK *lock) { - lock->lock = 0; + lock->lock = 0; #if SPINLOCK_PROFILE - lock->spins = 0; - lock->acquired = 0; - lock->waiting = 0; - lock->max_waiting = 0; - lock->contended = 0; + lock->spins = 0; + lock->acquired = 0; + lock->waiting = 0; + lock->max_waiting = 0; + lock->contended = 0; #endif } @@ -62,24 +63,30 @@ int spins = 0; atomic_add(&(lock->waiting), 1); #endif - while (atomic_add(&(lock->lock), 1) != 0) - { - atomic_add(&(lock->lock), -1); + +#ifdef __GNUC__ + while (__sync_lock_test_and_set(&(lock->lock), 1)) + while (lock->lock) { +#else + while (atomic_add(&(lock->lock), 1) != 0) + { + atomic_add(&(lock->lock), -1); +#endif #if SPINLOCK_PROFILE atomic_add(&(lock->spins), 1); spins++; #endif } #if SPINLOCK_PROFILE - if (spins) - { - lock->contended++; - if (lock->maxspins < spins) - lock->maxspins = spins; - } - lock->acquired++; - lock->owner = THREAD_SHELF(); - atomic_add(&(lock->waiting), -1); + if (spins) + { + lock->contended++; + if (lock->maxspins < spins) + lock->maxspins = spins; + } + lock->acquired++; + lock->owner = THREAD_SHELF(); + atomic_add(&(lock->waiting), -1); #endif } @@ -92,16 +99,20 @@ int spins = 0; int spinlock_acquire_nowait(SPINLOCK *lock) { - if (atomic_add(&(lock->lock), 1) != 0) - { - atomic_add(&(lock->lock), -1); - return FALSE; - } -#if SPINLOCK_PROFILE - lock->acquired++; - lock->owner = THREAD_SHELF(); +#ifdef __GNUC__ + if (__sync_lock_test_and_set(&(lock->lock), 1)) return FALSE; +#else + if (atomic_add(&(lock->lock), 1) != 0) + { + atomic_add(&(lock->lock), -1); + return FALSE; + } #endif - return TRUE; +#if SPINLOCK_PROFILE + lock->acquired++; + lock->owner = THREAD_SHELF(); +#endif + return TRUE; } /* @@ -112,11 +123,16 @@ spinlock_acquire_nowait(SPINLOCK *lock) void spinlock_release(SPINLOCK *lock) { -#if SPINLOCK_PROFILE - if (lock->waiting > lock->max_waiting) - lock->max_waiting = lock->waiting; + #if SPINLOCK_PROFILE + if (lock->waiting > lock->max_waiting) + lock->max_waiting = lock->waiting; +#endif +#ifdef __GNUC__ + __sync_synchronize(); // Memory barrier. + lock->lock = 0; +#else + atomic_add(&(lock->lock), -1); #endif - atomic_add(&(lock->lock), -1); } /** diff --git a/server/core/test/testspinlock.c b/server/core/test/testspinlock.c index f6ea810c8..a62e995a6 100644 --- a/server/core/test/testspinlock.c +++ b/server/core/test/testspinlock.c @@ -105,12 +105,16 @@ test2() { SPINLOCK lck; void *handle; +struct timespec sleeptime; + + sleeptime.tv_sec = 10; + sleeptime.tv_nsec = 0; acquire_time = 0; spinlock_init(&lck); spinlock_acquire(&lck); handle = thread_start(test2_helper, (void *)&lck); - sleep(10); + nanosleep(&sleeptime, NULL); spinlock_release(&lck); thread_wait(handle); @@ -122,12 +126,118 @@ void *handle; return 0; } -main(int argc, char **argv) +/** + * test3 spinlock_acquire tests process bound threads + * + * Check that spinlock correctly blocks all other threads whilst the spinlock + * is held. + * + * Start multiple threads that obtain spinlock and run process bound + */ +#define THREADS 5 +#define ITERATIONS 25000 +#define PROCESS_LOOP 10000 +#define SECONDS 15 +#define NANOTIME 100000 + +static int times_run, failures; +static volatile int active; +static int threadrun[THREADS]; +static int nowait[THREADS]; +static SPINLOCK lck; +static void +test3_helper(void *data) +{ +// SPINLOCK *lck = (SPINLOCK *)data; +int i; +int n = *(int *)data; +struct timespec sleeptime; +time_t rawtime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = 1; + + while (1) { + if (spinlock_acquire_nowait(&lck)) { + nowait[n]++; + } + else { + spinlock_acquire(&lck); + } + if (times_run++ > ITERATIONS) { + break; + } + threadrun[n]++; + /* + if (99 == (times_run % 100)) { + time ( &rawtime ); + fprintf(stderr, "%s Done %d iterations of test, in thread %d.\n", asctime (localtime ( &rawtime )), times_run, n); + } + */ + if (0 != active) { + fprintf(stderr, "spinlock: test 3 failed with active non-zero after lock obtained.\n"); + failures++; + } + else { + active = 1; + for (i=0; i