/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
-#include <assert.h>
+#include <cassert>
#include <climits>
-#include <stdint.h>
-#include <folly/detail/Futex.h>
+#include <cstdint>
+
#include <folly/Portability.h>
+#include <folly/detail/Futex.h>
+
+#if defined(__clang__)
+#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#else
+#define NO_SANITIZE_ADDRESS
+#endif
namespace folly {
* aliasing rules, character types may alias anything.)
*
* MicroLock uses a dirty trick: it actually operates on the full
- * word-size, word-aligned bit of memory into which it is embedded.
+ * 32-bit, four-byte-aligned bit of memory into which it is embedded.
* It never modifies bits outside the ones it's defined to modify, but
- * it _accesses_ all the bits in the word for purposes of
- * futex management.
+ * it _accesses_ all the bits in the 32-bit memory location for
+ * purposes of futex management.
*
* The MaxSpins template parameter controls the number of times we
* spin trying to acquire the lock. MaxYields controls the number of
*
* (The virtual dispatch benchmark is provided for scale.)
*
- * The contended case for MicroLock is likely to be worse compared to
- * std::mutex than the contended case is. Make sure to benchmark your
- * particular workload.
+ * While the uncontended case for MicroLock is competitive with the
+ * glibc 2.2.0 implementation of std::mutex, std::mutex is likely to be
+ * faster in the contended case, because we need to wake up all waiters
+ * when we release.
+ *
+ * Make sure to benchmark your particular workload.
*
*/
class MicroLockCore {
protected:
+#if defined(__SANITIZE_ADDRESS__) && !defined(__clang__) && \
+ (defined(__GNUC__) || defined(__GNUG__))
+ uint32_t lock_;
+#else
uint8_t lock_;
- inline detail::Futex<>* word() const;
+#endif
+ inline detail::Futex<>* word() const; // Well, halfword on 64-bit systems
inline uint32_t baseShift(unsigned slot) const;
inline uint32_t heldBit(unsigned slot) const;
inline uint32_t waitBit(unsigned slot) const;
unsigned maxYields);
public:
- inline void unlock(unsigned slot);
+ inline void unlock(unsigned slot) NO_SANITIZE_ADDRESS;
inline void unlock() { unlock(0); }
// Initializes all the slots.
inline void init() { lock_ = 0; }
unsigned offset_bytes = (unsigned)((uintptr_t)&lock_ - (uintptr_t)word());
- return kIsLittleEndian
- ? offset_bytes * CHAR_BIT + slot * 2
- : CHAR_BIT * (sizeof(uint32_t) - offset_bytes - 1) + slot * 2;
+ return (
+ unsigned)(kIsLittleEndian ? offset_bytes * CHAR_BIT + slot * 2 : CHAR_BIT * (sizeof(uint32_t) - offset_bytes - 1) + slot * 2);
}
inline uint32_t MicroLockCore::heldBit(unsigned slot) const {
template <unsigned MaxSpins = 1000, unsigned MaxYields = 0>
class MicroLockBase : public MicroLockCore {
public:
- inline void lock(unsigned slot);
+ inline void lock(unsigned slot) NO_SANITIZE_ADDRESS;
inline void lock() { lock(0); }
- inline bool try_lock(unsigned slot);
+ inline bool try_lock(unsigned slot) NO_SANITIZE_ADDRESS;
inline bool try_lock() { return try_lock(0); }
};
}
typedef MicroLockBase<> MicroLock;
-}
+} // namespace folly