X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FRWSpinLock.h;h=359343f80c1536d6c310d8f21cb6a10fc246aef4;hp=995c466f61786058bd1c7bf07ac1758a40bb41fc;hb=4b019355d99d1ddcc80c0d77da4e1f7540ae6ec0;hpb=ce64f0f685111ac24c7a321ea56d0c3524621df1 diff --git a/folly/RWSpinLock.h b/folly/RWSpinLock.h index 995c466f..359343f8 100644 --- a/folly/RWSpinLock.h +++ b/folly/RWSpinLock.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,18 @@ * RWTicketSpinLock<64> only allows up to 2^16 - 1 concurrent * readers and writers. * + * RWTicketSpinLock<..., true> (kFavorWriter = true, that is, strict + * writer priority) is NOT reentrant, even for lock_shared(). + * + * The lock will not grant any new shared (read) accesses while a thread + * attempting to acquire the lock in write mode is blocked. (That is, + * if the lock is held in shared mode by N threads, and a thread attempts + * to acquire it in write mode, no one else can acquire it in shared mode + * until these N threads release the lock and then the blocked thread + * acquires and releases the exclusive lock.) This also applies for + * attempts to reacquire the lock in shared mode by threads that already + * hold it in shared mode, making the lock non-reentrant. + * * RWSpinLock handles 2^30 - 1 concurrent readers. * * @author Xin Liu @@ -111,10 +123,19 @@ pthread_rwlock_t Read 728698 24us 101ns 7.28ms 194us #if defined(__GNUC__) && \ (defined(__i386) || FOLLY_X64 || \ defined(ARCH_K8)) -#define RW_SPINLOCK_USE_X86_INTRINSIC_ -#include +# define RW_SPINLOCK_USE_X86_INTRINSIC_ +# include +#elif defined(_MSC_VER) && defined(FOLLY_X64) +# define RW_SPINLOCK_USE_X86_INTRINSIC_ #else -#undef RW_SPINLOCK_USE_X86_INTRINSIC_ +# undef RW_SPINLOCK_USE_X86_INTRINSIC_ +#endif + +// iOS doesn't define _mm_cvtsi64_si128 and friends +#if (FOLLY_SSE >= 2) && !TARGET_OS_IPHONE +#define RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ +#else +#undef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ #endif #include @@ -274,7 +295,7 @@ class RWSpinLock : boost::noncopyable { lock_->lock_shared(); } - ReadHolder(ReadHolder&& other) : lock_(other.lock_) { + ReadHolder(ReadHolder&& other) noexcept : lock_(other.lock_) { other.lock_ = nullptr; } @@ -333,7 +354,7 @@ class RWSpinLock : boost::noncopyable { if (lock_) lock_->unlock_and_lock_upgrade(); } - UpgradedHolder(UpgradedHolder&& other) : lock_(other.lock_) { + UpgradedHolder(UpgradedHolder&& other) noexcept : lock_(other.lock_) { other.lock_ = nullptr; } @@ -383,7 +404,7 @@ class RWSpinLock : boost::noncopyable { if (lock_) lock_->unlock_upgrade_and_lock(); } - WriteHolder(WriteHolder&& other) : lock_(other.lock_) { + WriteHolder(WriteHolder&& other) noexcept : lock_(other.lock_) { other.lock_ = nullptr; } @@ -442,7 +463,7 @@ struct RWTicketIntTrait<64> { typedef uint32_t HalfInt; typedef uint16_t QuarterInt; -#ifdef __SSE2__ +#ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ static __m128i make128(const uint16_t v[4]) { return _mm_set_epi16(0, 0, 0, 0, v[3], v[2], v[1], v[0]); } @@ -464,7 +485,7 @@ struct RWTicketIntTrait<32> { typedef uint16_t HalfInt; typedef uint8_t QuarterInt; -#ifdef __SSE2__ +#ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ static __m128i make128(const uint8_t v[4]) { return _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v[3], v[2], v[1], v[0]); @@ -568,7 +589,7 @@ class RWTicketSpinLockT : boost::noncopyable { int count = 0; QuarterInt val = __sync_fetch_and_add(&ticket.users, 1); while (val != load_acquire(&ticket.write)) { - asm volatile("pause"); + asm_volatile_pause(); if (UNLIKELY(++count > 1000)) sched_yield(); } } @@ -598,7 +619,7 @@ class RWTicketSpinLockT : boost::noncopyable { t.whole = load_acquire(&ticket.whole); FullInt old = t.whole; -#ifdef __SSE2__ +#ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ // SSE2 can reduce the lock and unlock overhead by 10% static const QuarterInt kDeltaBuf[4] = { 1, 1, 0, 0 }; // write/read/user static const __m128i kDelta = IntTraitType::make128(kDeltaBuf); @@ -617,7 +638,7 @@ class RWTicketSpinLockT : boost::noncopyable { // need to let threads that already have a shared lock complete int count = 0; while (!LIKELY(try_lock_shared())) { - asm volatile("pause"); + asm_volatile_pause(); if (UNLIKELY((++count & 1023) == 0)) sched_yield(); } } @@ -626,7 +647,7 @@ class RWTicketSpinLockT : boost::noncopyable { RWTicket t, old; old.whole = t.whole = load_acquire(&ticket.whole); old.users = old.read; -#ifdef __SSE2__ +#ifdef RW_SPINLOCK_USE_SSE_INSTRUCTIONS_ // SSE2 may reduce the total lock and unlock overhead by 10% static const QuarterInt kDeltaBuf[4] = { 0, 1, 1, 0 }; // write/read/user static const __m128i kDelta = IntTraitType::make128(kDeltaBuf);