1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 //
10 // See port_example.h for documentation for the following types/functions.
11 
12 #pragma once
13 
14 #include <thread>
15 
16 #include "rocksdb/options.h"
17 #include "rocksdb/rocksdb_namespace.h"
18 
19 // size_t printf formatting named in the manner of C99 standard formatting
20 // strings such as PRIu64
21 // in fact, we could use that one
22 #define ROCKSDB_PRIszt "zu"
23 
24 #define __declspec(S)
25 
26 #define ROCKSDB_NOEXCEPT noexcept
27 
28 #undef PLATFORM_IS_LITTLE_ENDIAN
29 #if defined(OS_MACOSX)
30   #include <machine/endian.h>
31   #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
32     #define PLATFORM_IS_LITTLE_ENDIAN \
33         (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
34   #endif
35 #elif defined(OS_SOLARIS)
36   #include <sys/isa_defs.h>
37   #ifdef _LITTLE_ENDIAN
38     #define PLATFORM_IS_LITTLE_ENDIAN true
39   #else
40     #define PLATFORM_IS_LITTLE_ENDIAN false
41   #endif
42   #include <alloca.h>
43 #elif defined(OS_AIX)
44   #include <sys/types.h>
45   #include <arpa/nameser_compat.h>
46   #define PLATFORM_IS_LITTLE_ENDIAN (BYTE_ORDER == LITTLE_ENDIAN)
47   #include <alloca.h>
48 #elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) || \
49     defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
50   #include <sys/endian.h>
51   #include <sys/types.h>
52   #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
53 #else
54   #include <endian.h>
55 #endif
56 #include <pthread.h>
57 
58 #include <stdint.h>
59 #include <string.h>
60 #include <limits>
61 #include <string>
62 
63 #ifndef PLATFORM_IS_LITTLE_ENDIAN
64 #define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
65 #endif
66 
67 #if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
68     defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
69     defined(OS_ANDROID) || defined(CYGWIN) || defined(OS_AIX)
70 // Use fread/fwrite/fflush on platforms without _unlocked variants
71 #define fread_unlocked fread
72 #define fwrite_unlocked fwrite
73 #define fflush_unlocked fflush
74 #endif
75 
76 #if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\
77     defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
78 // Use fsync() on platforms without fdatasync()
79 #define fdatasync fsync
80 #endif
81 
82 #if defined(OS_ANDROID) && __ANDROID_API__ < 9
83 // fdatasync() was only introduced in API level 9 on Android. Use fsync()
84 // when targeting older platforms.
85 #define fdatasync fsync
86 #endif
87 
88 namespace ROCKSDB_NAMESPACE {
89 
90 extern const bool kDefaultToAdaptiveMutex;
91 
92 namespace port {
93 
94 // For use at db/file_indexer.h kLevelMaxIndex
95 const uint32_t kMaxUint32 = std::numeric_limits<uint32_t>::max();
96 const int kMaxInt32 = std::numeric_limits<int32_t>::max();
97 const int kMinInt32 = std::numeric_limits<int32_t>::min();
98 const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max();
99 const int64_t kMaxInt64 = std::numeric_limits<int64_t>::max();
100 const int64_t kMinInt64 = std::numeric_limits<int64_t>::min();
101 const size_t kMaxSizet = std::numeric_limits<size_t>::max();
102 
103 constexpr bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
104 #undef PLATFORM_IS_LITTLE_ENDIAN
105 
106 class CondVar;
107 
108 class Mutex {
109  public:
110   explicit Mutex(bool adaptive = kDefaultToAdaptiveMutex);
111   // No copying
112   Mutex(const Mutex&) = delete;
113   void operator=(const Mutex&) = delete;
114 
115   ~Mutex();
116 
117   void Lock();
118   void Unlock();
119 
120   bool TryLock();
121 
122   // this will assert if the mutex is not locked
123   // it does NOT verify that mutex is held by a calling thread
124   void AssertHeld();
125 
126  private:
127   friend class CondVar;
128   pthread_mutex_t mu_;
129 #ifndef NDEBUG
130   bool locked_ = false;
131 #endif
132 };
133 
134 class RWMutex {
135  public:
136   RWMutex();
137   // No copying allowed
138   RWMutex(const RWMutex&) = delete;
139   void operator=(const RWMutex&) = delete;
140 
141   ~RWMutex();
142 
143   void ReadLock();
144   void WriteLock();
145   void ReadUnlock();
146   void WriteUnlock();
AssertHeld()147   void AssertHeld() { }
148 
149  private:
150   pthread_rwlock_t mu_; // the underlying platform mutex
151 };
152 
153 class CondVar {
154  public:
155   explicit CondVar(Mutex* mu);
156   ~CondVar();
157   void Wait();
158   // Timed condition wait.  Returns true if timeout occurred.
159   bool TimedWait(uint64_t abs_time_us);
160   void Signal();
161   void SignalAll();
162  private:
163   pthread_cond_t cv_;
164   Mutex* mu_;
165 };
166 
167 using Thread = std::thread;
168 
AsmVolatilePause()169 static inline void AsmVolatilePause() {
170 #if defined(__i386__) || defined(__x86_64__)
171   asm volatile("pause");
172 #elif defined(__aarch64__)
173   asm volatile("yield");
174 #elif defined(__powerpc64__)
175   asm volatile("or 27,27,27");
176 #endif
177   // it's okay for other platforms to be no-ops
178 }
179 
180 // Returns -1 if not available on this platform
181 extern int PhysicalCoreID();
182 
183 using OnceType = pthread_once_t;
184 #define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
185 extern void InitOnce(OnceType* once, void (*initializer)());
186 
187 #ifndef CACHE_LINE_SIZE
188 // To test behavior with non-native cache line size, e.g. for
189 // Bloom filters, set TEST_CACHE_LINE_SIZE to the desired test size.
190 // This disables ALIGN_AS to keep it from failing compilation.
191 #ifdef TEST_CACHE_LINE_SIZE
192 #define CACHE_LINE_SIZE TEST_CACHE_LINE_SIZE
193 #define ALIGN_AS(n) /*empty*/
194 #else
195 #if defined(__s390__)
196 #define CACHE_LINE_SIZE 256U
197 #elif defined(__powerpc__) || defined(__aarch64__)
198 #define CACHE_LINE_SIZE 128U
199 #else
200 #define CACHE_LINE_SIZE 64U
201 #endif
202 #define ALIGN_AS(n) alignas(n)
203 #endif
204 #endif
205 
206 static_assert((CACHE_LINE_SIZE & (CACHE_LINE_SIZE - 1)) == 0,
207               "Cache line size must be a power of 2 number of bytes");
208 
209 extern void *cacheline_aligned_alloc(size_t size);
210 
211 extern void cacheline_aligned_free(void *memblock);
212 
213 #define PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
214 
215 extern void Crash(const std::string& srcfile, int srcline);
216 
217 extern int GetMaxOpenFiles();
218 
219 extern const size_t kPageSize;
220 
221 using ThreadId = pid_t;
222 
223 extern void SetCpuPriority(ThreadId id, CpuPriority priority);
224 
225 int64_t GetProcessID();
226 
227 // Uses platform APIs to generate a 36-character RFC-4122 UUID. Returns
228 // true on success or false on failure.
229 bool GenerateRfcUuid(std::string* output);
230 
231 } // namespace port
232 }  // namespace ROCKSDB_NAMESPACE
233