foundationdb/flow/Platform.h

876 lines
30 KiB
C++

/*
* Platform.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLOW_PLATFORM_H
#define FLOW_PLATFORM_H
#pragma once
#include "flow/config.h"
#if (defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__))
#define __unixish__ 1
#endif
#define FLOW_THREAD_SAFE 0
#include <stdlib.h>
#define FDB_EXIT_SUCCESS 0
#define FDB_EXIT_ERROR 1
#define FDB_EXIT_ABORT 3
#define FDB_EXIT_MAIN_ERROR 10
#define FDB_EXIT_MAIN_EXCEPTION 11
#define FDB_EXIT_NO_MEM 20
#define FDB_EXIT_INIT_SEMAPHORE 21
#ifdef __cplusplus
#define EXTERNC extern "C"
#include <cstdlib>
#include <cstdint>
#include <stdio.h>
#ifdef __unixish__
#include <unistd.h>
#endif
#if !(defined(_WIN32) || defined(__unixish__))
#error Compiling on unknown platform
#endif
#if defined(__linux__)
#if defined(__clang__)
#if ((__clang_major__ * 100 + __clang_minor__) < 303)
#error Clang 3.3 or later is required on this platform
#endif
#elif ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40500)
#error GCC 4.5.0 or later required on this platform
#endif
#endif
#if defined(_WIN32) && (_MSC_VER < 1600)
#error Visual Studio 2010 required on this platform
#endif
#if defined(__APPLE__) && \
(!((__clang__ == 1) || ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40800)))
#error Either Clang or GCC 4.8.0 or later required on this platform
#endif
#if (__clang__ == 1)
#define DISABLE_ZERO_DIVISION_FLAG _Pragma("GCC diagnostic ignored \"-Wdivision-by-zero\"")
#elif defined(_MSC_VER)
#define DISABLE_ZERO_DIVISION_FLAG __pragma("GCC diagnostic ignored \"-Wdiv-by-zero\"")
#else
#define DISABLE_ZERO_DIVISION_FLAG _Pragma("GCC diagnostic ignored \"-Wdiv-by-zero\"")
#endif
#if defined(__GNUG__)
#define force_inline inline __attribute__((__always_inline__))
#elif defined(_MSC_VER)
#define force_inline __forceinline
#else
#error Missing force inline
#endif
/*
* Visual Studio (.NET 2003 and beyond) has an __assume compiler
* intrinsic to hint to the compiler that a given condition is true
* and will remain true until the expression is altered. This can be
* emulated on GCC and ignored elsewhere.
*
* http://en.chys.info/2010/07/counterpart-of-assume-in-gcc/
*/
#ifndef _MSC_VER
#if defined(__GNUG__)
#define __assume(cond) \
do { \
if (!(cond)) \
__builtin_unreachable(); \
} while (0)
#else
#define __assume(cond)
#endif
#endif
#ifdef __unixish__
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define InitializeCriticalSection(m) \
do { \
pthread_mutexattr_t mta; \
pthread_mutexattr_init(&mta); \
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); \
pthread_mutex_init(m, &mta); \
pthread_mutexattr_destroy(&mta); \
} while (0)
#define DeleteCriticalSection(m) pthread_mutex_destroy(m)
#define EnterCriticalSection(m) pthread_mutex_lock(m)
#define LeaveCriticalSection(m) pthread_mutex_unlock(m)
#endif
#if (defined(__GNUG__))
#include <memory>
#include <functional>
#endif
// g++ requires that non-dependent names have to be looked up at
// template definition, which makes circular dependencies a royal
// pain. (For whatever it's worth, g++ appears to be adhering to spec
// here.) Fixing this properly requires quite a bit of reordering
// and/or splitting things into multiple files, but Scherer pointed
// out that it's simple to force a name to be dependent, which is what
// we'll do for now.
template <class Ignore, class T>
inline static T& makeDependent(T& value) {
return value;
}
#include <string>
#include <vector>
#if defined(_WIN32)
#include <process.h>
#define THREAD_FUNC static void __cdecl
#define THREAD_FUNC_RETURN void
#define THREAD_HANDLE void*
THREAD_HANDLE startThread(void(func)(void*), void* arg, int stackSize = 0, const char* name = nullptr);
#define THREAD_RETURN return
#elif defined(__unixish__)
#define THREAD_FUNC static void*
#define THREAD_FUNC_RETURN void*
#define THREAD_HANDLE pthread_t
// The last parameter is an optional name for the thread. It is only supported on Linux and has a
// limit of 16 characters.
THREAD_HANDLE startThread(void*(func)(void*), void* arg, int stackSize = 0, const char* name = nullptr);
#define THREAD_RETURN return NULL
#else
#error How do I start a new thread on this platform?
#endif
#if defined(_WIN32)
#define DYNAMIC_LIB_EXT ".dll"
#elif defined(__linux)
#define DYNAMIC_LIB_EXT ".so"
#elif defined(__FreeBSD__)
#define DYNAMIC_LIB_EXT ".so"
#elif defined(__APPLE__)
#define DYNAMIC_LIB_EXT ".dylib"
#else
#error Port me
#endif
#if defined(_WIN32)
#define ENV_VAR_PATH_SEPARATOR ';'
#elif defined(__unixish__)
#define ENV_VAR_PATH_SEPARATOR ':'
#else
#error Port me
#endif
void waitThread(THREAD_HANDLE thread);
// Linux-only for now. Set thread priority.
void setThreadPriority(int pri);
#define DEBUG_DETERMINISM 0
std::string removeWhitespace(const std::string& t);
struct SystemStatistics {
bool initialized;
double elapsed;
double processCPUSeconds, mainThreadCPUSeconds;
uint64_t processMemory;
uint64_t processResidentMemory;
uint64_t processDiskTotalBytes;
uint64_t processDiskFreeBytes;
double processDiskQueueDepth;
double processDiskIdleSeconds;
double processDiskReadSeconds;
double processDiskWriteSeconds;
double processDiskRead;
double processDiskWrite;
uint64_t processDiskReadCount;
uint64_t processDiskWriteCount;
double processDiskWriteSectors;
double processDiskReadSectors;
double machineMegabitsSent;
double machineMegabitsReceived;
uint64_t machineOutSegs;
uint64_t machineRetransSegs;
double machineCPUSeconds;
int64_t machineTotalRAM;
int64_t machineCommittedRAM;
int64_t machineAvailableRAM;
SystemStatistics()
: initialized(false), elapsed(0), processCPUSeconds(0), mainThreadCPUSeconds(0), processMemory(0),
processResidentMemory(0), processDiskTotalBytes(0), processDiskFreeBytes(0), processDiskQueueDepth(0),
processDiskIdleSeconds(0), processDiskReadSeconds(0), processDiskWriteSeconds(0), processDiskRead(0),
processDiskWrite(0), processDiskReadCount(0), processDiskWriteCount(0), processDiskWriteSectors(0),
processDiskReadSectors(0), machineMegabitsSent(0), machineMegabitsReceived(0), machineOutSegs(0),
machineRetransSegs(0), machineCPUSeconds(0), machineTotalRAM(0), machineCommittedRAM(0),
machineAvailableRAM(0) {}
};
struct SystemStatisticsState;
struct IPAddress;
SystemStatistics getSystemStatistics(std::string const& dataFolder,
const IPAddress* ip,
SystemStatisticsState** statState,
bool logDetails);
double getProcessorTimeThread();
double getProcessorTimeProcess();
uint64_t getMemoryUsage();
uint64_t getResidentMemoryUsage();
struct MachineRAMInfo {
int64_t total;
int64_t committed;
int64_t available;
};
void getMachineRAMInfo(MachineRAMInfo& memInfo);
void getDiskBytes(std::string const& directory, int64_t& free, int64_t& total);
void getNetworkTraffic(uint64_t& bytesSent, uint64_t& bytesReceived, uint64_t& outSegs, uint64_t& retransSegs);
void getDiskStatistics(std::string const& directory,
uint64_t& currentIOs,
uint64_t& readMilliSecs,
uint64_t& writeMilliSecs,
uint64_t& IOMilliSecs,
uint64_t& reads,
uint64_t& writes,
uint64_t& writeSectors);
void getMachineLoad(uint64_t& idleTime, uint64_t& totalTime, bool logDetails);
double
timer(); // Returns the system real time clock with high precision. May jump around when system time is adjusted!
double timer_monotonic(); // Returns a high precision monotonic clock which is adjusted to be kind of similar to timer()
// at startup, but might not be a globally accurate time.
uint64_t timer_int(); // Return timer as uint64_t representing epoch nanoseconds
void getLocalTime(const time_t* timep, struct tm* result);
// get GMT time string from an epoch seconds double
std::string epochsToGMTString(double epochs);
void setMemoryQuota(size_t limit);
void* allocate(size_t length, bool allowLargePages, bool includeGuardPages);
void setAffinity(int proc);
void threadSleep(double seconds);
void threadYield(); // Attempt to yield to other processes or threads
// Returns true iff the file exists
bool fileExists(std::string const& filename);
// Returns true iff the directory exists
bool directoryExists(std::string const& path);
// Returns size of file in bytes
int64_t fileSize(std::string const& filename);
// Returns true if file is deleted, false if it was not found, throws platform_error() otherwise
// Consider using IAsyncFileSystem::filesystem()->deleteFile() instead, especially if you need durability!
bool deleteFile(std::string const& filename);
// Renames the given file. Does not fsync the directory.
void renameFile(std::string const& fromPath, std::string const& toPath);
// Atomically replaces the contents of the specified file.
void atomicReplace(std::string const& path, std::string const& content, bool textmode = true);
// Read a file into memory
std::string readFileBytes(std::string const& filename, int maxSize);
// Read a file into memory supplied by the caller
// If 'len' is greater than file size, then read the filesize bytes.
void readFileBytes(std::string const& filename, uint8_t* buff, int64_t len);
// Write data buffer into file
void writeFileBytes(std::string const& filename, const char* data, size_t count);
// Write text into file
void writeFile(std::string const& filename, std::string const& content);
std::string joinPath(std::string const& directory, std::string const& filename);
// cleanPath() does a 'logical' resolution of the given path string to a canonical form *without*
// following symbolic links or verifying the existence of any path components. It removes redundant
// "." references and duplicate separators, and resolves any ".." references that can be resolved
// using the preceding path components.
// Relative paths remain relative and are NOT rebased on the current working directory.
std::string cleanPath(std::string const& path);
// Removes the last component from a path string (if possible) and returns the result with one trailing separator.
// If there is only one path component, the result will be "" for relative paths and "/" for absolute paths.
// Note that this is NOT the same as getting the parent of path, as the final component could be ".."
// or "." and it would still be simply removed.
// ALL of the following inputs will yield the result "/a/"
// /a/b
// /a/b/
// /a/..
// /a/../
// /a/.
// /a/./
// /a//..//
std::string popPath(const std::string& path);
// abspath() resolves the given path to a canonical form.
// If path is relative, the result will be based on the current working directory.
// If resolveLinks is true then symbolic links will be expanded BEFORE resolving '..' references.
// An empty path or a non-existent path when mustExist is true will result in a platform_error() exception.
// Upon success, all '..' references will be resolved with the assumption that non-existent components
// are NOT symbolic links.
// User directory references such as '~' or '~user' are effectively treated as symbolic links which
// are impossible to resolve, so resolveLinks=true results in failure and resolveLinks=false results
// in the reference being left in-tact prior to resolving '..' references.
std::string abspath(std::string const& path, bool resolveLinks = true, bool mustExist = false);
// parentDirectory() returns the parent directory of the given file or directory in a canonical form,
// with a single trailing path separator.
// It uses absPath() with the same bool options to initially obtain a canonical form, and upon success
// removes the final path component, if present.
std::string parentDirectory(std::string const& path, bool resolveLinks = true, bool mustExist = false);
// Returns the portion of the path following the last path separator (e.g. the filename or directory name)
std::string basename(std::string const& filename);
// Returns the home directory of the current user
std::string getUserHomeDirectory();
namespace platform {
// Returns true if directory was created, false if it existed, throws platform_error() otherwise
bool createDirectory(std::string const& directory);
// e.g. extension==".fdb", returns filenames relative to directory
std::vector<std::string> listFiles(std::string const& directory, std::string const& extension = "");
// returns directory names relative to directory
std::vector<std::string> listDirectories(std::string const& directory);
void findFilesRecursively(std::string const& path, std::vector<std::string>& out);
// Tag the given file as "temporary", i.e. not really needing commits to disk
void makeTemporary(const char* filename);
void setCloseOnExec(int fd);
// Logs an out of memory error and exits the program
void outOfMemory();
int getRandomSeed();
bool getEnvironmentVar(const char* name, std::string& value);
int setEnvironmentVar(const char* name, const char* value, int overwrite);
std::string getWorkingDirectory();
// Returns the absolute platform-dependant path for server-based files
std::string getDefaultConfigPath();
// Returns the absolute platform-dependant path for the default fdb.cluster file
std::string getDefaultClusterFilePath();
struct ImageInfo {
void* offset = nullptr;
std::string fileName = "unknown";
std::string symbolFileName = "unknown";
};
ImageInfo getImageInfo();
// Places the frame pointers in a string formatted as parameters for addr2line.
size_t raw_backtrace(void** addresses, int maxStackDepth);
std::string get_backtrace();
std::string format_backtrace(void** addresses, int numAddresses);
// Avoid in production code: not atomic, not fast, not reliable in all environments
int eraseDirectoryRecursive(std::string const& directory);
bool isHwCrcSupported();
// Creates a temporary file; file gets destroyed/deleted along with object destruction.
// If 'tmpDir' is empty, code defaults to 'boost::filesystem::temp_directory_path()'
// If 'pattern' is empty, code defaults to 'fdbtmp'
struct TmpFile {
public:
TmpFile();
TmpFile(const std::string& tempDir);
TmpFile(const std::string& tempDir, std::string const& prefix);
~TmpFile();
size_t read(uint8_t* buff, size_t len);
void write(const uint8_t* buff, size_t len);
bool destroyFile();
std::string getFileName() const { return filename; }
private:
std::string filename;
constexpr static std::string_view defaultPrefix = "fdbtmp";
void createTmpFile(const std::string_view dir, const std::string_view prefix);
};
} // namespace platform
#ifdef __linux__
typedef struct {
double timestamp;
size_t length;
void* frames[];
} ProfilingSample;
dev_t getDeviceId(std::string path);
#endif
#if defined(__aarch64__)
#include "sse2neon.h"
// aarch64 does not have rdtsc counter
// Use cntvct_el0 virtual counter instead
inline static uint64_t timestampCounter() {
uint64_t timer;
asm volatile("mrs %0, cntvct_el0" : "=r"(timer));
return timer;
}
#elif defined(_powerpc64_)
#include <emmintrin.h>
#elif defined(__linux__)
#include <x86intrin.h>
#define timestampCounter() __rdtsc()
#elif defined(__APPLE__) // macOS on Intel
// Version of CLang bundled with XCode doesn't yet include ia32intrin.h.
#if !(__has_builtin(__rdtsc))
inline static uint64_t timestampCounter() {
uint64_t lo, hi;
asm("rdtsc" : "=a"(lo), "=d"(hi));
return (lo | (hi << 32));
}
#else
#define timestampCounter() __rdtsc()
#endif
#else
#define timestampCounter() __rdtsc()
#endif
#ifdef __FreeBSD__
#if !(__has_builtin(__rdtsc))
inline static uint64_t __rdtsc() {
uint64_t lo, hi;
asm("rdtsc" : "=a"(lo), "=d"(hi));
return (lo | (hi << 32));
}
#endif
#elif defined(__powerpc64__) || defined(__ppc64__)
inline static uint64_t __rdtsc() {
uint64_t tb;
__asm__ volatile("mfspr %0, 268" : "=r"(tb));
return tb;
}
#endif
#if defined(__linux__)
#include <features.h>
#endif
#include <sys/stat.h>
#ifdef _WIN32
#include <intrin.h>
inline static int32_t interlockedIncrement(volatile int32_t* a) {
return _InterlockedIncrement((long*)a);
}
inline static int64_t interlockedIncrement64(volatile int64_t* a) {
return _InterlockedIncrement64(a);
}
inline static int32_t interlockedDecrement(volatile int32_t* a) {
return _InterlockedDecrement((long*)a);
}
inline static int64_t interlockedDecrement64(volatile int64_t* a) {
return _InterlockedDecrement64(a);
}
inline static int32_t interlockedCompareExchange(volatile int32_t* a, int32_t b, int32_t c) {
return _InterlockedCompareExchange((long*)a, (long)b, (long)c);
}
inline static int64_t interlockedExchangeAdd64(volatile int64_t* a, int64_t b) {
return _InterlockedExchangeAdd64(a, b);
}
inline static int64_t interlockedExchange64(volatile int64_t* a, int64_t b) {
return _InterlockedExchange64(a, b);
}
inline static int64_t interlockedOr64(volatile int64_t* a, int64_t b) {
return _InterlockedOr64(a, b);
}
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#ifndef __aarch64__
#include <xmmintrin.h>
#endif
inline static int32_t interlockedIncrement(volatile int32_t* a) {
return __sync_add_and_fetch(a, 1);
}
inline static int64_t interlockedIncrement64(volatile int64_t* a) {
return __sync_add_and_fetch(a, 1);
}
inline static int32_t interlockedDecrement(volatile int32_t* a) {
return __sync_add_and_fetch(a, -1);
}
inline static int64_t interlockedDecrement64(volatile int64_t* a) {
return __sync_add_and_fetch(a, -1);
}
inline static int32_t interlockedCompareExchange(volatile int32_t* a, int32_t b, int32_t c) {
return __sync_val_compare_and_swap(a, c, b);
}
inline static int64_t interlockedExchangeAdd64(volatile int64_t* a, int64_t b) {
return __sync_fetch_and_add(a, b);
}
inline static int64_t interlockedExchange64(volatile int64_t* a, int64_t b) {
__sync_synchronize();
return __sync_lock_test_and_set(a, b);
}
inline static int64_t interlockedOr64(volatile int64_t* a, int64_t b) {
return __sync_fetch_and_or(a, b);
}
#else
#error No implementation of atomic instructions
#endif
template <class T>
inline static T* interlockedExchangePtr(T* volatile* a, T* b) {
static_assert(sizeof(T*) == sizeof(int64_t), "Port me!");
return (T*)interlockedExchange64((volatile int64_t*)a, (int64_t)b);
}
#if FLOW_THREAD_SAFE
#define thread_volatile volatile
inline static int64_t flowInterlockedExchangeAdd64(volatile int64_t* p, int64_t a) {
return interlockedExchangeAdd64(p, a);
}
inline static int64_t flowInterlockedIncrement64(volatile int64_t* p) {
return interlockedIncrement64(p);
}
inline static int64_t flowInterlockedDecrement64(volatile int64_t* p) {
return interlockedDecrement64(p);
}
inline static int64_t flowInterlockedExchange64(volatile int64_t* p, int64_t a) {
return interlockedExchange64(p, a);
}
inline static int64_t flowInterlockedOr64(volatile int64_t* p, int64_t a) {
return interlockedOr64(p, a);
}
inline static int64_t flowInterlockedAnd64(volatile int64_t* p, int64_t a) {
return interlockedAnd64(p, a);
}
#else
#define thread_volatile
inline static int64_t flowInterlockedExchangeAdd64(int64_t* p, int64_t a) {
auto old = *p;
*p += a;
return old;
}
inline static int64_t flowInterlockedIncrement64(int64_t* p) {
return ++*p;
}
inline static int64_t flowInterlockedDecrement64(int64_t* p) {
return --*p;
}
inline static int64_t flowInterlockedExchange64(int64_t* p, int64_t a) {
auto old = *p;
*p = a;
return old;
}
inline static int64_t flowInterlockedOr64(int64_t* p, int64_t a) {
auto old = *p;
*p |= a;
return old;
}
inline static int64_t flowInterlockedAnd64(int64_t* p, int64_t a) {
auto old = *p;
*p &= a;
return old;
}
#endif
// We only run on little-endian system, so conversion to/from bigEndian64 is always a byte swap
#ifdef _MSC_VER
#define bigEndian16(value) uint16_t(_byteswap_ushort(value))
#define bigEndian32(value) uint32_t(_byteswap_ulong(value))
#define bigEndian64(value) uint64_t(_byteswap_uint64(value))
#define fromBigEndian16(value) uint16_t(_byteswap_ushort(value))
#define fromBigEndian32(value) uint32_t(_byteswap_ulong(value))
#define fromBigEndian64(value) uint64_t(_byteswap_uint64(value))
#elif __GNUG__
#define bigEndian16(value) uint16_t((value >> 8) | (value << 8))
#define bigEndian32(value) uint32_t(__builtin_bswap32(value))
#define bigEndian64(value) uint64_t(__builtin_bswap64(value))
#define fromBigEndian16(value) uint16_t((value >> 8) | (value << 8))
#define fromBigEndian32(value) uint32_t(__builtin_bswap32(value))
#define fromBigEndian64(value) uint64_t(__builtin_bswap64(value))
#else
#error Missing byte swap methods
#endif
#define littleEndian16(value) uint16_t(value)
#define littleEndian32(value) uint32_t(value)
#define littleEndian64(value) uint64_t(value)
#if defined(_WIN32)
inline static void flushOutputStreams() {
_flushall();
}
#elif defined(__unixish__)
inline static void flushOutputStreams() {
fflush(nullptr);
}
#else
#error Missing flush output stream
#endif
#if defined(_MSC_VER)
#define DLLEXPORT __declspec(dllexport)
#elif defined(__GNUG__)
#undef DLLEXPORT
#define DLLEXPORT __attribute__((visibility("default")))
#else
#error Missing symbol export
#endif
#define crashAndDie() (*(volatile int*)0 = 0)
#ifdef _WIN32
#define strcasecmp stricmp
#endif
#if defined(__GNUG__)
#define DEFAULT_CONSTRUCTORS(X) \
X(X const& rhs) = default; \
X& operator=(X const& rhs) = default;
#else
#define DEFAULT_CONSTRUCTORS(X)
#endif
#if defined(_WIN32)
#define strtoull(nptr, endptr, base) _strtoui64(nptr, endptr, base)
#endif
#if defined(_MSC_VER)
inline static void* aligned_alloc(size_t alignment, size_t size) {
return _aligned_malloc(size, alignment);
}
inline static void aligned_free(void* ptr) {
_aligned_free(ptr);
}
#elif defined(__linux__)
#include <malloc.h>
inline static void aligned_free(void* ptr) {
free(ptr);
}
#if (!defined(_ISOC11_SOURCE)) // old libc versions
inline static void* aligned_alloc(size_t alignment, size_t size) {
return memalign(alignment, size);
}
#endif
#elif defined(__FreeBSD__)
inline static void aligned_free(void* ptr) {
free(ptr);
}
#elif defined(__APPLE__)
#if !defined(HAS_ALIGNED_ALLOC)
#include <cstdlib>
inline static void* aligned_alloc(size_t alignment, size_t size) {
void* ptr = nullptr;
posix_memalign(&ptr, alignment, size);
return ptr;
}
#endif
inline static void aligned_free(void* ptr) {
free(ptr);
}
#endif
// lib_path may be a relative or absolute path or a name to be
// resolved by whatever linker is hanging around on this system
bool isLibraryLoaded(const char* lib_path);
void* loadLibrary(const char* lib_path);
void closeLibrary(void* handle);
void* loadFunction(void* lib, const char* func_name);
std::string exePath();
// get the absolute path
std::string getExecPath();
#ifdef _WIN32
inline static int ctzll(uint64_t value) {
unsigned long count = 0;
if (_BitScanForward64(&count, value)) {
return count;
}
return 64;
}
inline static int clzll(uint64_t value) {
unsigned long count = 0;
if (_BitScanReverse64(&count, value)) {
return 63 - count;
}
return 64;
}
inline static int ctz(uint32_t value) {
unsigned long count = 0;
if (_BitScanForward(&count, value)) {
return count;
}
return 64;
}
inline static int clz(uint32_t value) {
unsigned long count = 0;
if (_BitScanReverse(&count, value)) {
return 63 - count;
}
return 64;
}
#else
#define ctzll __builtin_ctzll
#define clzll __builtin_clzll
#define ctz __builtin_ctz
#define clz __builtin_clz
#endif
// These return thread local counts
int64_t getNumProfilesDeferred();
int64_t getNumProfilesOverflowed();
int64_t getNumProfilesCaptured();
#else
#define EXTERNC
#endif // __cplusplus
/*
* Multiply Defined Symbol (support for weak function declaration).
*/
#ifndef MULTIPLY_DEFINED_SYMBOL
#if defined(_MSC_VER)
#define MULTIPLY_DEFINED_SYMBOL
#else
#define MULTIPLY_DEFINED_SYMBOL __attribute__((weak))
#endif
#endif
// Logs a critical error message and exits the program
EXTERNC void criticalError(int exitCode, const char* type, const char* message);
EXTERNC void flushAndExit(int exitCode);
// Initilization code that's run at the beginning of every entry point (except fdbmonitor)
void platformInit();
void registerCrashHandler();
void setupRunLoopProfiler();
EXTERNC void setProfilingEnabled(int enabled);
// Use _exit() or criticalError(), not exit()
#define exit static_assert(false, "Calls to exit() are forbidden by policy");
#if defined(FDB_CLEAN_BUILD) && !(defined(NDEBUG) && !defined(_DEBUG) && !defined(SQLITE_DEBUG))
#error Clean builds must define NDEBUG, and not define various debug macros
#endif
// DTrace probing
#if defined(DTRACE_PROBES)
#include <sys/sdt.h>
#define FDB_TRACE_PROBE_STRING_EXPAND(x) x
#define FDB_TRACE_PROBE_STRING_CONCAT2(h, t) h##t
#define FDB_TRACE_PROBE_STRING_CONCAT(h, t) FDB_TRACE_PROBE_STRING_CONCAT2(h, t)
#define FDB_TRACE_PROBE_EXPAND_MACRO(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, NAME, ...) NAME
#define FDB_TRACE_PROBE(...) \
FDB_TRACE_PROBE_EXPAND_MACRO(__VA_ARGS__, \
DTRACE_PROBE12, \
DTRACE_PROBE11, \
DTRACE_PROBE10, \
DTRACE_PROBE9, \
DTRACE_PROBE8, \
DTRACE_PROBE7, \
DTRACE_PROBE6, \
DTRACE_PROBE5, \
DTRACE_PROBE4, \
DTRACE_PROBE3, \
DTRACE_PROBE2, \
DTRACE_PROBE1, \
DTRACE_PROBE) \
(foundationdb, __VA_ARGS__)
extern void fdb_probe_actor_create(const char* name, unsigned long id);
extern void fdb_probe_actor_destroy(const char* name, unsigned long id);
extern void fdb_probe_actor_enter(const char* name, unsigned long, int index);
extern void fdb_probe_actor_exit(const char* name, unsigned long, int index);
#else
#define FDB_TRACE_PROBE_STRING_CONCAT(h, t) h##t
#define FDB_TRACE_PROBE(...)
inline void fdb_probe_actor_create(const char* name, unsigned long id) {}
inline void fdb_probe_actor_destroy(const char* name, unsigned long id) {}
inline void fdb_probe_actor_enter(const char* name, unsigned long id, int index) {}
inline void fdb_probe_actor_exit(const char* name, unsigned long id, int index) {}
#endif
// CRC32C
#ifdef __aarch64__
// aarch64
#include <inttypes.h>
static inline uint32_t hwCrc32cU8(unsigned int crc, unsigned char v) {
uint32_t ret;
asm volatile("crc32cb %w[r], %w[c], %w[v]" : [r] "=r"(ret) : [c] "r"(crc), [v] "r"(v));
return ret;
}
static inline uint32_t hwCrc32cU32(unsigned int crc, unsigned int v) {
uint32_t ret;
asm volatile("crc32cw %w[r], %w[c], %w[v]" : [r] "=r"(ret) : [c] "r"(crc), [v] "r"(v));
return ret;
}
static inline uint64_t hwCrc32cU64(uint64_t crc, uint64_t v) {
uint64_t ret;
asm volatile("crc32cx %w[r], %w[c], %x[v]" : [r] "=r"(ret) : [c] "r"(crc), [v] "r"(v));
return ret;
}
#else
#ifndef __powerpc64__
// Intel
#define hwCrc32cU8(c, v) _mm_crc32_u8(c, v)
#define hwCrc32cU32(c, v) _mm_crc32_u32(c, v)
#define hwCrc32cU64(c, v) _mm_crc32_u64(c, v)
#endif
#endif
#if defined(__aarch64__)
#define _MM_HINT_T0 0 /* dummy -- not used */
#endif
#endif /* FLOW_PLATFORM_H */