// hooray!
return true;
}
-#if FOLLY_X64
// The pause instruction is the polite way to spin, but it doesn't
// actually affect correctness to omit it if we don't have it.
// Pausing donates the full capabilities of the current core to
// its other hyperthreads for a dozen cycles or so
- asm volatile ("pause");
-#endif
+ asm_volatile_pause();
}
return false;
# define FOLLY_X64 0
#endif
+#if defined(__aarch64__)
+# define FOLLY_A64 1
+#else
+# define FOLLY_A64 0
+#endif
+
// packing is very ugly in msvc
#ifdef _MSC_VER
# define FOLLY_PACK_ATTR /**/
# define FOLLY_HAS_RTTI 1
#endif
+namespace folly {
+
+inline void asm_volatile_pause() {
+#if defined(__i386__) || FOLLY_X64
+ asm volatile ("pause");
+#elif FOLLY_A64
+ asm volatile ("wfe");
+#endif
+}
+inline void asm_pause() {
+#if defined(__i386__) || FOLLY_X64
+ asm ("pause");
+#elif FOLLY_A64
+ asm ("wfe");
+#endif
+}
+
+}
+
#endif // FOLLY_PORTABILITY_H_
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();
}
}
// 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();
}
}
if ((state & goal) == 0) {
return true;
}
-#if FOLLY_X64
- asm volatile("pause");
-#endif
+ asm_volatile_pause();
++spinCount;
if (UNLIKELY(spinCount >= kMaxSpinCount)) {
return ctx.canBlock() &&
return;
}
}
-#if FOLLY_X64
- asm("pause");
-#endif
+ asm_pause();
if (UNLIKELY(++spinCount >= kMaxSpinCount)) {
applyDeferredReaders(state, ctx, slot);
return;
#include <glog/logging.h>
#include <folly/Portability.h>
-#if !FOLLY_X64
-# error "SmallLocks.h is currently x64-only."
+#if !FOLLY_X64 && !FOLLY_A64
+# error "SmallLocks.h is currently x64 and aarch64 only."
#endif
namespace folly {
void wait() {
if (spinCount < kMaxActiveSpin) {
++spinCount;
- asm volatile("pause");
+ asm_volatile_pause();
} else {
/*
* Always sleep 0.5ms, assuming this will make the kernel put
bool try_lock() const {
bool ret = false;
+#if FOLLY_X64
#define FB_DOBTS(size) \
asm volatile("lock; bts" #size " %1, (%2); setnc %0" \
: "=r" (ret) \
}
#undef FB_DOBTS
+#elif FOLLY_A64
+ ret = __atomic_fetch_or(&lock_, 1 << Bit, __ATOMIC_SEQ_CST);
+#else
+#error "x86 aarch64 only"
+#endif
return ret;
}
* integer.
*/
void unlock() const {
+#if FOLLY_X64
#define FB_DOBTR(size) \
asm volatile("lock; btr" #size " %0, (%1)" \
: \
}
#undef FB_DOBTR
+#elif FOLLY_A64
+ __atomic_fetch_and(&lock_, ~(1 << Bit), __ATOMIC_SEQ_CST);
+#else
+# error "x64 aarch64 only"
+#endif
}
};
// the first effectSpinCutoff tries are spins, after that we will
// record ourself as a waiter and block with futexWait
if (tries < effectiveSpinCutoff) {
-#if defined(__i386__) || FOLLY_X64
- asm volatile ("pause");
-#endif
+ asm_volatile_pause();
continue;
}
// hooray!
return true;
}
-#if FOLLY_X64
// The pause instruction is the polite way to spin, but it doesn't
// actually affect correctness to omit it if we don't have it.
// Pausing donates the full capabilities of the current core to
// its other hyperthreads for a dozen cycles or so
- asm volatile ("pause");
-#endif
+ asm_volatile_pause();
}
return false;
const int max = 1000;
unsigned int seed = (uintptr_t)pthread_self();
for (int i = 0; i < max; i++) {
- asm("pause");
+ folly::asm_pause();
MSLGuard g(v.lock);
int first = v.ar[0];
std::lock_guard<PicoSpinLock<T>> guard(lock);
lock.setData(ourVal);
for (int n = 0; n < 10; ++n) {
- asm volatile("pause");
+ folly::asm_volatile_pause();
EXPECT_EQ(lock.getData(), ourVal);
}
}
const int max = 1000;
unsigned int seed = (uintptr_t)pthread_self();
for (int i = 0; i < max; i++) {
- asm("pause");
+ folly::asm_pause();
SpinLockGuardImpl<LOCK> g(v->lock);
int first = v->ar[0];
template <typename LOCK>
void trylockTestThread(TryLockState<LOCK>* state, size_t count) {
while (true) {
- asm("pause");
+ folly::asm_pause();
SpinLockGuardImpl<LOCK> g(state->lock1);
if (state->obtained >= count) {
break;
auto oldFailed = state->failed;
while (state->failed == oldFailed && state->obtained < count) {
state->lock1.unlock();
- asm("pause");
+ folly::asm_pause();
state->lock1.lock();
}