diff options
author | Igor Sysoev <igor@sysoev.ru> | 2017-01-17 20:00:00 +0300 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2017-01-17 20:00:00 +0300 |
commit | 16cbf3c076a0aca6d47adaf3f719493674cf2363 (patch) | |
tree | e6530480020f62a2bdbf249988ec3e2a751d3927 /src/nxt_spinlock.c | |
download | unit-16cbf3c076a0aca6d47adaf3f719493674cf2363.tar.gz unit-16cbf3c076a0aca6d47adaf3f719493674cf2363.tar.bz2 |
Initial version.
Diffstat (limited to 'src/nxt_spinlock.c')
-rw-r--r-- | src/nxt_spinlock.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/nxt_spinlock.c b/src/nxt_spinlock.c new file mode 100644 index 00000000..0348ae23 --- /dev/null +++ b/src/nxt_spinlock.c @@ -0,0 +1,152 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * Linux supports pthread spinlocks since glibc 2.3. Spinlock is an + * atomic integer with zero initial value. On i386/amd64 however the + * initial value is one. Spinlock never yields control. + * + * FreeBSD 5.2 and Solaris 10 support pthread spinlocks. Spinlock is a + * structure and uses mutex implementation so it must be initialized by + * by pthread_spin_init() and destroyed by pthread_spin_destroy(). + */ + +#if (NXT_HAVE_MACOSX_SPINLOCK) + +/* + * OSSpinLockLock() tries to acquire a lock atomically. If the lock is + * busy, on SMP system it tests the lock 1000 times in a tight loop with + * "pause" instruction. If the lock has been released, OSSpinLockLock() + * tries to acquire it again. On failure it goes again in the tight loop. + * If the lock has not been released during spinning in the loop or + * on UP system, OSSpinLockLock() calls thread_switch() to run 1ms + * with depressed (the lowest) priority. + */ + +void +nxt_thread_spin_lock(nxt_thread_spinlock_t *lock) +{ + nxt_thread_log_debug("OSSpinLockLock(%p) enter", lock); + + OSSpinLockLock(lock); +} + + +nxt_bool_t +nxt_thread_spin_trylock(nxt_thread_spinlock_t *lock) +{ + nxt_thread_log_debug("OSSpinLockTry(%p) enter", lock); + + if (OSSpinLockTry(lock)) { + return 1; + } + + nxt_thread_log_debug("OSSpinLockTry(%p) failed", lock); + + return 0; +} + + +void +nxt_thread_spin_unlock(nxt_thread_spinlock_t *lock) +{ + OSSpinLockUnlock(lock); + + nxt_thread_log_debug("OSSpinLockUnlock(%p) exit", lock); +} + + +#else + + +/* It should be adjusted with the "spinlock_count" directive. */ +static nxt_uint_t nxt_spinlock_count = 1000; + + +void +nxt_thread_spin_init(nxt_uint_t ncpu, nxt_uint_t count) +{ + switch (ncpu) { + + case 0: + /* Explicit spinlock count. */ + nxt_spinlock_count = count; + break; + + case 1: + /* Spinning is useless on UP. */ + nxt_spinlock_count = 0; + break; + + default: + /* + * SMP. + * + * TODO: The count should be 10 on a virtualized system + * since virtualized CPUs may share the same physical CPU. + */ + nxt_spinlock_count = 1000; + break; + } +} + + +void +nxt_thread_spin_lock(nxt_thread_spinlock_t *lock) +{ + nxt_uint_t n; + + nxt_thread_log_debug("spin_lock(%p) enter", lock); + + for ( ;; ) { + + again: + + if (nxt_fast_path(nxt_atomic_try_lock(lock))) { + return; + } + + for (n = nxt_spinlock_count; n != 0; n--) { + + nxt_cpu_pause(); + + if (*lock == 0) { + goto again; + } + } + + nxt_thread_yield(); + } +} + + +nxt_bool_t +nxt_thread_spin_trylock(nxt_thread_spinlock_t *lock) +{ + nxt_thread_log_debug("spin_trylock(%p) enter", lock); + + if (nxt_fast_path(nxt_atomic_try_lock(lock))) { + return 1; + } + + nxt_thread_log_debug("spin_trylock(%p) failed", lock); + + return 0; +} + + +void +nxt_thread_spin_unlock(nxt_thread_spinlock_t *lock) +{ + nxt_atomic_release(lock); + + nxt_thread_log_debug("spin_unlock(%p) exit", lock); +} + +#endif |