1 /*
2  * Platform.h
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef FLOW_PLATFORM_H
22 #define FLOW_PLATFORM_H
23 #pragma once
24 
25 #if (defined(__linux__) || defined(__APPLE__))
26 #define __unixish__ 1
27 #endif
28 
29 #define FLOW_THREAD_SAFE 0
30 
31 #include <stdlib.h>
32 
33 #define FDB_EXIT_SUCCESS 0
34 #define FDB_EXIT_ERROR 1
35 #define FDB_EXIT_ABORT 3
36 #define FDB_EXIT_MAIN_ERROR 10
37 #define FDB_EXIT_MAIN_EXCEPTION 11
38 #define FDB_EXIT_NO_MEM 20
39 #define FDB_EXIT_INIT_SEMAPHORE 21
40 
41 #ifdef __cplusplus
42 #define EXTERNC extern "C"
43 
44 #include <cstdlib>
45 #include <cstdint>
46 #include <stdio.h>
47 
48 #ifdef __unixish__
49 #include <unistd.h>
50 #endif
51 
52 #if !(defined(_WIN32) || defined(__unixish__))
53 #error Compiling on unknown platform
54 #endif
55 
56 #if defined(__linux__)
57 #  if defined(__clang__)
58 #    if ((__clang_major__ * 100 + __clang_minor__) < 303)
59 #      error Clang 3.3 or later is required on this platform
60 #    endif
61 #  elif ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40500)
62 #    error GCC 4.5.0 or later required on this platform
63 #  endif
64 #endif
65 
66 #if defined(_WIN32) && (_MSC_VER < 1600)
67 #error Visual Studio 2010 required on this platform
68 #endif
69 
70 #if defined(__APPLE__) && (!((__clang__ == 1) || ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40800)))
71 #error Either Clang or GCC 4.8.0 or later required on this platform
72 #endif
73 
74 #if (__clang__ == 1)
75 #define DISABLE_ZERO_DIVISION_FLAG _Pragma("GCC diagnostic ignored \"-Wdivision-by-zero\"")
76 #elif defined(_MSC_VER)
77 #define DISABLE_ZERO_DIVISION_FLAG __pragma("GCC diagnostic ignored \"-Wdiv-by-zero\"")
78 #else
79 #define DISABLE_ZERO_DIVISION_FLAG _Pragma("GCC diagnostic ignored \"-Wdiv-by-zero\"")
80 #endif
81 
82 /*
83  * Thread-local storage (but keep in mind any platform-specific
84  * restrictions on where this is valid and/or ignored).
85  *
86  * http://en.wikipedia.org/wiki/Thread-local_storage
87  *
88  * SOMEDAY: Intel C++ compiler uses g++ syntax on Linux and MSC syntax
89  * on Windows.
90  */
91 #if defined(__GNUG__)
92 #define thread_local __thread
93 #elif defined(_MSC_VER)
94 #define thread_local __declspec(thread)
95 #else
96 #error Missing thread local storage
97 #endif
98 
99 #if defined(__GNUG__)
100 #define force_inline inline __attribute__((__always_inline__))
101 #elif defined(_MSC_VER)
102 #define force_inline __forceinline
103 #else
104 #error Missing force inline
105 #endif
106 
107 /*
108  * Visual Studio 2005 and beyond allow virtual and sealed while
109  * targetting native code, and we get better error messages at compile
110  * time with it where appropriate. Not supported with any other
111  * compiler.
112  */
113 #if _MSC_VER < 1400
114 #define sealed
115 #define override
116 #endif
117 
118 /*
119  * Visual Studio (.NET 2003 and beyond) has an __assume compiler
120  * intrinsic to hint to the compiler that a given condition is true
121  * and will remain true until the expression is altered. This can be
122  * emulated on GCC and ignored elsewhere.
123  *
124  * http://en.chys.info/2010/07/counterpart-of-assume-in-gcc/
125  */
126 #ifndef _MSC_VER
127 #if defined(__GNUG__)
128 #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
129 #else
130 #define __assume(cond)
131 #endif
132 #endif
133 
134 #ifdef __unixish__
135 #include <pthread.h>
136 #define CRITICAL_SECTION pthread_mutex_t
137 #define InitializeCriticalSection(m) \
138 do { \
139 	pthread_mutexattr_t mta; \
140 	pthread_mutexattr_init(&mta); \
141 	pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); \
142 	pthread_mutex_init(m, &mta); \
143 	pthread_mutexattr_destroy(&mta); \
144 	} while (0)
145 #define DeleteCriticalSection(m) pthread_mutex_destroy(m)
146 #define EnterCriticalSection(m) pthread_mutex_lock(m)
147 #define LeaveCriticalSection(m) pthread_mutex_unlock(m)
148 #endif
149 
150 #if (defined(__GNUG__))
151 #include <memory>
152 #include <functional>
153 #endif
154 
155 // fake<T>() is for use in decltype expressions only - there is no implementation
156 template <class T> T fake();
157 
158 // g++ requires that non-dependent names have to be looked up at
159 // template definition, which makes circular dependencies a royal
160 // pain. (For whatever it's worth, g++ appears to be adhering to spec
161 // here.) Fixing this properly requires quite a bit of reordering
162 // and/or splitting things into multiple files, but Scherer pointed
163 // out that it's simple to force a name to be dependent, which is what
164 // we'll do for now.
165 template <class Ignore, class T>
makeDependent(T & value)166 inline static T& makeDependent(T& value) { return value; }
167 
168 #include <string>
169 #include <vector>
170 
171 #if defined(_WIN32)
172 #include <process.h>
173 #define THREAD_FUNC static void __cdecl
174 #define THREAD_FUNC_RETURN void
175 #define THREAD_HANDLE void *
176 THREAD_HANDLE startThread(void (func) (void *), void *arg);
177 #define THREAD_RETURN return
178 #elif defined(__unixish__)
179 #define THREAD_FUNC static void *
180 #define THREAD_FUNC_RETURN void *
181 #define THREAD_HANDLE pthread_t
182 THREAD_HANDLE startThread(void *(func) (void *), void *arg);
183 #define THREAD_RETURN return NULL
184 #else
185 #error How do I start a new thread on this platform?
186 #endif
187 
188 #if defined(_WIN32)
189 #define DYNAMIC_LIB_EXT ".dll"
190 #elif defined(__linux)
191 #define DYNAMIC_LIB_EXT ".so"
192 #elif defined(__APPLE__)
193 #define DYNAMIC_LIB_EXT ".dylib"
194 #else
195 #error Port me
196 #endif
197 
198 #if defined(_WIN32)
199 #define ENV_VAR_PATH_SEPARATOR ';'
200 #elif defined(__unixish__)
201 #define ENV_VAR_PATH_SEPARATOR ':'
202 #else
203 #error Port me
204 #endif
205 
206 void waitThread(THREAD_HANDLE thread);
207 
208 // Linux-only for now.  Set thread priority "low"
209 void deprioritizeThread();
210 
211 #define DEBUG_DETERMINISM 0
212 
213 std::string removeWhitespace(const std::string &t);
214 
215 struct SystemStatistics {
216 	bool initialized;
217 	double elapsed;
218 	double processCPUSeconds, mainThreadCPUSeconds;
219 	uint64_t processMemory;
220 	uint64_t processResidentMemory;
221 	uint64_t processDiskTotalBytes;
222 	uint64_t processDiskFreeBytes;
223 	double processDiskQueueDepth;
224 	double processDiskIdleSeconds;
225 	double processDiskRead;
226 	double processDiskWrite;
227 	uint64_t processDiskReadCount;
228 	uint64_t processDiskWriteCount;
229 	double processDiskWriteSectors;
230 	double processDiskReadSectors;
231 	double machineMegabitsSent;
232 	double machineMegabitsReceived;
233 	uint64_t machineOutSegs;
234 	uint64_t machineRetransSegs;
235 	double machineCPUSeconds;
236 	int64_t machineTotalRAM;
237 	int64_t machineCommittedRAM;
238 	int64_t machineAvailableRAM;
239 
SystemStatisticsSystemStatistics240 	SystemStatistics() : initialized(false), elapsed(0), processCPUSeconds(0), mainThreadCPUSeconds(0), processMemory(0),
241 		processResidentMemory(0), processDiskTotalBytes(0), processDiskFreeBytes(0), processDiskQueueDepth(0), processDiskIdleSeconds(0), processDiskRead(0), processDiskWrite(0),
242 		processDiskReadCount(0), processDiskWriteCount(0), processDiskWriteSectors(0), processDiskReadSectors(0), machineMegabitsSent(0), machineMegabitsReceived(0), machineOutSegs(0),
243 		machineRetransSegs(0), machineCPUSeconds(0), machineTotalRAM(0), machineCommittedRAM(0), machineAvailableRAM(0) {}
244 };
245 
246 struct SystemStatisticsState;
247 
248 struct IPAddress;
249 
250 SystemStatistics getSystemStatistics(std::string dataFolder, const IPAddress* ip, SystemStatisticsState **statState, bool logDetails);
251 
252 double getProcessorTimeThread();
253 
254 double getProcessorTimeProcess();
255 
256 uint64_t getMemoryUsage();
257 
258 uint64_t getResidentMemoryUsage();
259 
260 struct MachineRAMInfo {
261 	int64_t total;
262 	int64_t committed;
263 	int64_t available;
264 };
265 
266 void getMachineRAMInfo(MachineRAMInfo& memInfo);
267 
268 void getDiskBytes(std::string const& directory, int64_t& free, int64_t& total);
269 
270 void getNetworkTraffic(uint64_t& bytesSent, uint64_t& bytesReceived, uint64_t& outSegs,
271 					   uint64_t& retransSegs);
272 
273 void getDiskStatistics(std::string const& directory, uint64_t& currentIOs, uint64_t& busyTicks, uint64_t& reads, uint64_t& writes, uint64_t& writeSectors);
274 
275 void getMachineLoad(uint64_t& idleTime, uint64_t& totalTime, bool logDetails);
276 
277 double timer();  // Returns the system real time clock with high precision.  May jump around when system time is adjusted!
278 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.
279 uint64_t timer_int(); // Return timer as uint64_t
280 
281 void getLocalTime(const time_t *timep, struct tm *result);
282 
283 void setMemoryQuota(size_t limit);
284 
285 void *allocate(size_t length, bool allowLargePages);
286 
287 void setAffinity(int proc);
288 
289 void threadSleep( double seconds );
290 
291 void threadYield();  // Attempt to yield to other processes or threads
292 
293 // Returns true iff the file exists
294 bool fileExists(std::string const& filename);
295 
296 // Returns true iff the directory exists
297 bool directoryExists(std::string const& path);
298 
299 // Returns size of file in bytes
300 int64_t fileSize(std::string const& filename);
301 
302 // Returns true if file is deleted, false if it was not found, throws platform_error() otherwise
303 // Consider using IAsyncFileSystem::filesystem()->deleteFile() instead, especially if you need durability!
304 bool deleteFile( std::string const& filename );
305 
306 // Renames the given file.  Does not fsync the directory.
307 void renameFile( std::string const& fromPath, std::string const& toPath );
308 
309 // Atomically replaces the contents of the specified file.
310 void atomicReplace( std::string const& path, std::string const& content, bool textmode = true );
311 
312 // Read a file into memory
313 std::string readFileBytes( std::string const& filename, int maxSize );
314 
315 // Write data buffer into file
316 void writeFileBytes(std::string const& filename, const char* data, size_t count);
317 
318 // Write text into file
319 void writeFile(std::string const& filename, std::string const& content);
320 
321 std::string joinPath( std::string const& directory, std::string const& filename );
322 
323 // cleanPath() does a 'logical' resolution of the given path string to a canonical form *without*
324 // following symbolic links or verifying the existence of any path components.  It removes redundant
325 // "." references and duplicate separators, and resolves any ".." references that can be resolved
326 // using the preceding path components.
327 // Relative paths remain relative and are NOT rebased on the current working directory.
328 std::string cleanPath( std::string const& path );
329 
330 // abspath() resolves the given path to a canonical form.
331 // If path is relative, the result will be based on the current working directory.
332 // If resolveLinks is true then symbolic links will be expanded BEFORE resolving '..' references.
333 // An empty path or a non-existent path when mustExist is true will result in a platform_error() exception.
334 // Upon success, all '..' references will be resolved with the assumption that non-existent components
335 // are NOT symbolic links.
336 // User directory references such as '~' or '~user' are effectively treated as symbolic links which
337 // are impossible to resolve, so resolveLinks=true results in failure and resolveLinks=false results
338 // in the reference being left in-tact prior to resolving '..' references.
339 std::string abspath( std::string const& path, bool resolveLinks = true, bool mustExist = false );
340 
341 // parentDirectory() returns the parent directory of the given file or directory in a canonical form,
342 // with a single trailing path separator.
343 // It uses absPath() with the same bool options to initially obtain a canonical form, and upon success
344 // removes the final path component, if present.
345 std::string parentDirectory( std::string const& path, bool resolveLinks = true, bool mustExist = false);
346 
347 // Returns the portion of the path following the last path separator (e.g. the filename or directory name)
348 std::string basename( std::string const& filename );
349 
350 // Returns the home directory of the current user
351 std::string getUserHomeDirectory();
352 
353 namespace platform {
354 
355 // Returns true if directory was created, false if it existed, throws platform_error() otherwise
356 bool createDirectory( std::string const& directory );
357 
358 // e.g. extension==".fdb", returns filenames relative to directory
359 std::vector<std::string> listFiles( std::string const& directory, std::string const& extension = "");
360 
361 // returns directory names relative to directory
362 std::vector<std::string> listDirectories( std::string const& directory );
363 
364 void findFilesRecursively(std::string path, std::vector<std::string> &out);
365 
366 // Tag the given file as "temporary", i.e. not really needing commits to disk
367 void makeTemporary( const char* filename );
368 
369 // Logs an out of memory error and exits the program
370 void outOfMemory();
371 
372 int getRandomSeed();
373 
374 bool getEnvironmentVar(const char* name, std::string& value);
375 int setEnvironmentVar(const char *name, const char *value, int overwrite);
376 
377 std::string getWorkingDirectory();
378 
379 // Returns the ... something something figure out plugin locations
380 std::string getDefaultPluginPath( const char* plugin_name );
381 
382 void *getImageOffset();
383 
384 // Places the frame pointers in a string formatted as parameters for addr2line.
385 size_t raw_backtrace(void** addresses, int maxStackDepth);
386 std::string get_backtrace();
387 std::string format_backtrace(void **addresses, int numAddresses);
388 
389 } // namespace platform
390 
391 #ifdef __linux__
392 typedef struct {
393 	double timestamp;
394 	size_t length;
395 	void* frames[];
396 } ProfilingSample;
397 
398 dev_t getDeviceId(std::string path);
399 #endif
400 
401 #ifdef __linux__
402 #include <x86intrin.h>
403 #include <features.h>
404 #include <sys/stat.h>
405 #endif
406 
407 // Version of CLang bundled with XCode doesn't yet include ia32intrin.h.
408 #ifdef __APPLE__
409 #if !(__has_builtin(__rdtsc))
__rdtsc()410 inline static uint64_t __rdtsc() {
411 	uint64_t lo, hi;
412 	asm( "rdtsc" : "=a" (lo), "=d" (hi) );
413 	return( lo | (hi << 32) );
414 }
415 #endif
416 #endif
417 
418 #ifdef _WIN32
419 #include <intrin.h>
interlockedIncrement(volatile int32_t * a)420 inline static int32_t interlockedIncrement(volatile int32_t *a) { return _InterlockedIncrement((long*)a); }
interlockedIncrement64(volatile int64_t * a)421 inline static int64_t interlockedIncrement64(volatile int64_t *a) { return _InterlockedIncrement64(a); }
interlockedDecrement(volatile int32_t * a)422 inline static int32_t interlockedDecrement(volatile int32_t *a) { return _InterlockedDecrement((long*)a); }
interlockedDecrement64(volatile int64_t * a)423 inline static int64_t interlockedDecrement64(volatile int64_t *a) { return _InterlockedDecrement64(a); }
interlockedCompareExchange(volatile int32_t * a,int32_t b,int32_t c)424 inline static int32_t interlockedCompareExchange(volatile int32_t *a, int32_t b, int32_t c) { return _InterlockedCompareExchange((long*)a, (long)b, (long)c); }
interlockedExchangeAdd64(volatile int64_t * a,int64_t b)425 inline static int64_t interlockedExchangeAdd64(volatile int64_t *a, int64_t b) { return _InterlockedExchangeAdd64(a, b); }
interlockedExchange64(volatile int64_t * a,int64_t b)426 inline static int64_t interlockedExchange64(volatile int64_t *a, int64_t b) { return _InterlockedExchange64(a, b); }
interlockedOr64(volatile int64_t * a,int64_t b)427 inline static int64_t interlockedOr64(volatile int64_t *a, int64_t b) { return _InterlockedOr64(a, b); }
428 #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
429 #include <xmmintrin.h>
interlockedIncrement(volatile int32_t * a)430 inline static int32_t interlockedIncrement(volatile int32_t *a) { return __sync_add_and_fetch(a, 1); }
interlockedIncrement64(volatile int64_t * a)431 inline static int64_t interlockedIncrement64(volatile int64_t *a) { return __sync_add_and_fetch(a, 1); }
interlockedDecrement(volatile int32_t * a)432 inline static int32_t interlockedDecrement(volatile int32_t *a) { return __sync_add_and_fetch(a, -1); }
interlockedDecrement64(volatile int64_t * a)433 inline static int64_t interlockedDecrement64(volatile int64_t *a) { return __sync_add_and_fetch(a, -1); }
interlockedCompareExchange(volatile int32_t * a,int32_t b,int32_t c)434 inline static int32_t interlockedCompareExchange(volatile int32_t *a, int32_t b, int32_t c) { return __sync_val_compare_and_swap(a, c, b); }
interlockedExchangeAdd64(volatile int64_t * a,int64_t b)435 inline static int64_t interlockedExchangeAdd64(volatile int64_t *a, int64_t b) { return __sync_fetch_and_add(a, b); }
interlockedExchange64(volatile int64_t * a,int64_t b)436 inline static int64_t interlockedExchange64(volatile int64_t *a, int64_t b) {
437 	__sync_synchronize();
438 	return __sync_lock_test_and_set(a, b);
439 }
interlockedOr64(volatile int64_t * a,int64_t b)440 inline static int64_t interlockedOr64(volatile int64_t *a, int64_t b) { return __sync_fetch_and_or(a, b); }
441 #else
442 #error No implementation of atomic instructions
443 #endif
444 
interlockedExchangePtr(T * volatile * a,T * b)445 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); }
446 
447 #if FLOW_THREAD_SAFE
448 #define thread_volatile volatile
flowInterlockedExchangeAdd64(volatile int64_t * p,int64_t a)449 inline static int64_t flowInterlockedExchangeAdd64( volatile int64_t* p, int64_t a ) { return interlockedExchangeAdd64(p, a); }
flowInterlockedIncrement64(volatile int64_t * p)450 inline static int64_t flowInterlockedIncrement64( volatile int64_t* p ) { return interlockedIncrement64(p); }
flowInterlockedDecrement64(volatile int64_t * p)451 inline static int64_t flowInterlockedDecrement64( volatile int64_t* p ) { return interlockedDecrement64(p); }
flowInterlockedExchange64(volatile int64_t * p,int64_t a)452 inline static int64_t flowInterlockedExchange64( volatile int64_t* p, int64_t a ) { return interlockedExchange64(p, a); }
flowInterlockedOr64(volatile int64_t * p,int64_t a)453 inline static int64_t flowInterlockedOr64( volatile int64_t* p, int64_t a ) { return interlockedOr64(p, a); }
flowInterlockedAnd64(volatile int64_t * p,int64_t a)454 inline static int64_t flowInterlockedAnd64( volatile int64_t* p, int64_t a ) { return interlockedAnd64(p, a); }
455 #else
456 #define thread_volatile
flowInterlockedExchangeAdd64(int64_t * p,int64_t a)457 inline static int64_t flowInterlockedExchangeAdd64( int64_t* p, int64_t a ) { auto old=*p; *p+=a; return old; }
flowInterlockedIncrement64(int64_t * p)458 inline static int64_t flowInterlockedIncrement64( int64_t* p ) { return ++*p; }
flowInterlockedDecrement64(int64_t * p)459 inline static int64_t flowInterlockedDecrement64( int64_t* p ) { return --*p; }
flowInterlockedExchange64(int64_t * p,int64_t a)460 inline static int64_t flowInterlockedExchange64( int64_t* p, int64_t a ) { auto old=*p; *p=a; return old; }
flowInterlockedOr64(int64_t * p,int64_t a)461 inline static int64_t flowInterlockedOr64( int64_t* p, int64_t a ) { auto old=*p; *p |= a; return old; }
flowInterlockedAnd64(int64_t * p,int64_t a)462 inline static int64_t flowInterlockedAnd64( int64_t* p, int64_t a ) { auto old=*p; *p &= a; return old; }
463 #endif
464 
465 // We only run on little-endian system, so conversion to/from bigEndian64 is always a byte swap
466 #ifdef _MSC_VER
467 #define bigEndian16(value) uint16_t(_byteswap_ushort(value))
468 #define bigEndian32(value) uint32_t(_byteswap_ulong(value))
469 #define bigEndian64(value) uint64_t(_byteswap_uint64(value))
470 #elif __GNUG__
471 #define bigEndian16(value) uint16_t((value>>8)|(value<<8))
472 #define bigEndian32(value) uint32_t(__builtin_bswap32(value))
473 #define bigEndian64(value) uint64_t(__builtin_bswap64(value))
474 #else
475 #error Missing byte swap methods
476 #endif
477 
478 #define littleEndian16(value) value
479 #define littleEndian32(value) value
480 #define littleEndian64(value) value
481 
482 #if defined(_WIN32)
flushOutputStreams()483 inline static void flushOutputStreams() { _flushall(); }
484 #elif defined(__unixish__)
flushOutputStreams()485 inline static void flushOutputStreams() { fflush(NULL); }
486 #else
487 #error Missing flush output stream
488 #endif
489 
490 
491 #if defined(_MSC_VER)
492 #define DLLEXPORT __declspec(dllexport)
493 #elif defined(__GNUG__)
494 #define DLLEXPORT __attribute__ ((visibility ("default")))
495 #else
496 #error Missing symbol export
497 #endif
498 
499 #define crashAndDie() (*(volatile int*)0 = 0)
500 
501 #ifdef _WIN32
502 #define strcasecmp stricmp
503 #endif
504 
505 #if defined(__GNUG__)
506 #define DEFAULT_CONSTRUCTORS(X) \
507 	X( X const& rhs ) = default; \
508 	X& operator=( X const& rhs ) = default;
509 #else
510 #define DEFAULT_CONSTRUCTORS(X)
511 #endif
512 
513 
514 #if defined(_WIN32)
515 #define strtoull(nptr, endptr, base) _strtoui64(nptr, endptr, base)
516 #endif
517 
518 #if defined(_MSC_VER)
aligned_alloc(size_t alignment,size_t size)519 inline static void* aligned_alloc(size_t alignment, size_t size) { return _aligned_malloc(size, alignment); }
aligned_free(void * ptr)520 inline static void aligned_free(void* ptr) { _aligned_free(ptr); }
521 #elif defined(__linux__)
522 #include <malloc.h>
aligned_free(void * ptr)523 inline static void aligned_free(void* ptr) { free(ptr); }
524 #if (!defined(_ISOC11_SOURCE)) // old libc versions
aligned_alloc(size_t alignment,size_t size)525 inline static void* aligned_alloc(size_t alignment, size_t size) { return memalign(alignment, size); }
526 #endif
527 #elif defined(__APPLE__)
528 #include <cstdlib>
aligned_alloc(size_t alignment,size_t size)529 inline static void* aligned_alloc(size_t alignment, size_t size) {
530 	// Linux's aligned_alloc() requires alignment to be a power of 2.  While posix_memalign()
531 	// also requires this, in addition it requires alignment to be a multiple of sizeof(void *).
532 	// Rather than add this requirement to the platform::aligned_alloc() interface we will simply
533 	// upgrade powers of 2 which are less than sizeof(void *) to be exactly sizeof(void *).  Non
534 	// powers of 2 of any size will fail as they would on other platforms.  This change does not
535 	// break the platform::aligned_alloc() contract as all addresses which are aligned to
536 	// sizeof(void *) are also aligned to any power of 2 less than sizeof(void *).
537 	if(alignment != 0 && alignment < sizeof(void *) && (alignment & (alignment - 1)) == 0) {
538 		alignment = sizeof(void *);
539 	}
540 	void* ptr = nullptr;
541 	posix_memalign(&ptr, alignment, size);
542 	return ptr;
543 }
aligned_free(void * ptr)544 inline static void aligned_free(void* ptr) { free(ptr); }
545 #endif
546 
547 // lib_path may be a relative or absolute path or a name to be
548 // resolved by whatever linker is hanging around on this system
549 bool isLibraryLoaded(const char* lib_path);
550 void* loadLibrary(const char* lib_path);
551 void* loadFunction(void* lib, const char* func_name);
552 
553 #ifdef _WIN32
ctzll(uint64_t value)554 inline static int ctzll( uint64_t value ) {
555     unsigned long count = 0;
556     if( _BitScanForward64( &count, value ) ) {
557         return count;
558     }
559     return 64;
560 }
561 #else
562 #define ctzll __builtin_ctzll
563 #endif
564 
565 #include <boost/config.hpp>
566 // The formerly existing BOOST_NOEXCEPT is now BOOST_NOEXCEPT
567 
568 #else
569 #define EXTERNC
570 #endif // __cplusplus
571 
572 /*
573  * Multiply Defined Symbol (support for weak function declaration).
574  */
575 #ifndef MULTIPLY_DEFINED_SYMBOL
576 #if defined(_MSC_VER)
577 #define MULTIPLY_DEFINED_SYMBOL
578 #else
579 #define MULTIPLY_DEFINED_SYMBOL __attribute__((weak))
580 #endif
581 #endif
582 
583 // Logs a critical error message and exits the program
584 EXTERNC void criticalError(int exitCode, const char *type, const char *message);
585 EXTERNC void flushAndExit(int exitCode);
586 
587 // Initilization code that's run at the beginning of every entry point (except fdbmonitor)
588 void platformInit();
589 
590 void registerCrashHandler();
591 void setupSlowTaskProfiler();
592 EXTERNC void setProfilingEnabled(int enabled);
593 
594 // Use _exit() or criticalError(), not exit()
595 #define CALLS_TO_EXIT_ARE_FORBIDDEN_BY_POLICY() [====]
596 #define exit CALLS_TO_EXIT_ARE_FORBIDDEN_BY_POLICY(0)
597 
598 #if defined(FDB_CLEAN_BUILD) && !( defined(NDEBUG) && !defined(_DEBUG) && !defined(SQLITE_DEBUG) )
599 #error Clean builds must define NDEBUG, and not define various debug macros
600 #endif
601 
602 #endif /* FLOW_PLATFORM_H */
603