/*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* @author Jordan DeLong <delong.j@fb.com>
*/
+#include <array>
#include <cinttypes>
#include <type_traits>
#include <ctime>
#include <mutex>
#include <glog/logging.h>
+#include <folly/Portability.h>
-#ifndef __x86_64__
+#if !FOLLY_X64
# error "SmallLocks.h is currently x64-only."
#endif
* linux this varies by kernel version from 1ms to 10ms).
*/
struct timespec ts = { 0, 500000 };
- nanosleep(&ts, NULL);
+ nanosleep(&ts, nullptr);
}
}
};
*/
bool cas(uint8_t compare, uint8_t newVal) {
bool out;
- asm volatile("lock; cmpxchgb %2, (%3);"
- "setz %0;"
- : "=r" (out)
+ bool memVal; // only set if the cmpxchg fails
+ asm volatile("lock; cmpxchgb %[newVal], (%[lockPtr]);"
+ "setz %[output];"
+ : [output] "=r" (out), "=a" (memVal)
: "a" (compare), // cmpxchgb constrains this to be in %al
- "q" (newVal), // Needs to be byte-accessible
- "r" (&lock_)
+ [newVal] "q" (newVal), // Needs to be byte-accessible
+ [lockPtr] "r" (&lock_)
: "memory", "flags");
return out;
}
sizeof(IntType) == 8,
"PicoSpinLock can't work on integers smaller than 2 bytes");
-public:
+ public:
static const UIntType kLockBitMask_ = UIntType(1) << Bit;
UIntType lock_;
//////////////////////////////////////////////////////////////////////
+/**
+ * Array of spinlocks where each one is padded to prevent false sharing.
+ * Useful for shard-based locking implementations in environments where
+ * contention is unlikely.
+ */
+
+// TODO: generate it from configure (`getconf LEVEL1_DCACHE_LINESIZE`)
+#define FOLLY_CACHE_LINE_SIZE 64
+
+template <class T, size_t N>
+struct SpinLockArray {
+ T& operator[](size_t i) {
+ return data_[i].lock;
+ }
+
+ const T& operator[](size_t i) const {
+ return data_[i].lock;
+ }
+
+ constexpr size_t size() const { return N; }
+
+ private:
+ struct PaddedSpinLock {
+ PaddedSpinLock() : lock() { }
+ T lock;
+ char padding[FOLLY_CACHE_LINE_SIZE - sizeof(T)];
+ };
+ static_assert(sizeof(PaddedSpinLock) == FOLLY_CACHE_LINE_SIZE,
+ "Invalid size of PaddedSpinLock");
+
+ // Check if T can theoretically cross a cache line.
+ // NOTE: It should be alignof(std::max_align_t), but max_align_t
+ // isn't supported by gcc 4.6.2.
+ static_assert(alignof(MaxAlign) > 0 &&
+ FOLLY_CACHE_LINE_SIZE % alignof(MaxAlign) == 0 &&
+ sizeof(T) <= alignof(MaxAlign),
+ "T can cross cache line boundaries");
+
+ char padding_[FOLLY_CACHE_LINE_SIZE];
+ std::array<PaddedSpinLock, N> data_;
+} __attribute__((aligned));
+
+//////////////////////////////////////////////////////////////////////
+
typedef std::lock_guard<MicroSpinLock> MSLGuard;
//////////////////////////////////////////////////////////////////////