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 // Always want minimum headers
15 #ifndef WIN32_LEAN_AND_MEAN
16 #define WIN32_LEAN_AND_MEAN
17 #endif
18 
19 #include <windows.h>
20 #include <string>
21 #include <string.h>
22 #include <mutex>
23 #include <limits>
24 #include <condition_variable>
25 #include <malloc.h>
26 #include <intrin.h>
27 
28 #include <stdint.h>
29 
30 #include "port/win/win_thread.h"
31 
32 #include "rocksdb/options.h"
33 
34 #undef min
35 #undef max
36 #undef DeleteFile
37 #undef GetCurrentTime
38 
39 
40 #ifndef strcasecmp
41 #define strcasecmp _stricmp
42 #endif
43 
44 #undef GetCurrentTime
45 #undef DeleteFile
46 
47 #ifndef _SSIZE_T_DEFINED
48 typedef SSIZE_T ssize_t;
49 #endif
50 
51 // size_t printf formatting named in the manner of C99 standard formatting
52 // strings such as PRIu64
53 // in fact, we could use that one
54 #ifndef ROCKSDB_PRIszt
55 #define ROCKSDB_PRIszt "Iu"
56 #endif
57 
58 #ifdef _MSC_VER
59 #define __attribute__(A)
60 
61 // Thread local storage on Linux
62 // There is thread_local in C++11
63 #ifndef __thread
64 #define __thread __declspec(thread)
65 #endif
66 
67 #endif
68 
69 namespace ROCKSDB_NAMESPACE {
70 
71 #define PREFETCH(addr, rw, locality)
72 
73 extern const bool kDefaultToAdaptiveMutex;
74 
75 namespace port {
76 
77 // VS < 2015
78 #if defined(_MSC_VER) && (_MSC_VER < 1900)
79 
80 // VS 15 has snprintf
81 #define snprintf _snprintf
82 
83 #define ROCKSDB_NOEXCEPT
84 // std::numeric_limits<size_t>::max() is not constexpr just yet
85 // therefore, use the same limits
86 
87 // For use at db/file_indexer.h kLevelMaxIndex
88 const uint32_t kMaxUint32 = UINT32_MAX;
89 const int kMaxInt32 = INT32_MAX;
90 const int kMinInt32 = INT32_MIN;
91 const int64_t kMaxInt64 = INT64_MAX;
92 const int64_t kMinInt64 = INT64_MIN;
93 const uint64_t kMaxUint64 = UINT64_MAX;
94 
95 #ifdef _WIN64
96 const size_t kMaxSizet = UINT64_MAX;
97 #else
98 const size_t kMaxSizet = UINT_MAX;
99 #endif
100 
101 #else // VS >= 2015 or MinGW
102 
103 #define ROCKSDB_NOEXCEPT noexcept
104 
105 // For use at db/file_indexer.h kLevelMaxIndex
106 const uint32_t kMaxUint32 = std::numeric_limits<uint32_t>::max();
107 const int kMaxInt32 = std::numeric_limits<int>::max();
108 const int kMinInt32 = std::numeric_limits<int>::min();
109 const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max();
110 const int64_t kMaxInt64 = std::numeric_limits<int64_t>::max();
111 const int64_t kMinInt64 = std::numeric_limits<int64_t>::min();
112 
113 const size_t kMaxSizet = std::numeric_limits<size_t>::max();
114 
115 #endif //_MSC_VER
116 
117 // "Windows is designed to run on little-endian computer architectures."
118 // https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types
119 constexpr bool kLittleEndian = true;
120 #undef PLATFORM_IS_LITTLE_ENDIAN
121 
122 class CondVar;
123 
124 class Mutex {
125  public:
126 
127    /* implicit */ Mutex(bool adaptive = kDefaultToAdaptiveMutex)
128 #ifndef NDEBUG
locked_(false)129      : locked_(false)
130 #endif
131    { }
132 
133   ~Mutex();
134 
Lock()135   void Lock() {
136     mutex_.lock();
137 #ifndef NDEBUG
138     locked_ = true;
139 #endif
140   }
141 
Unlock()142   void Unlock() {
143 #ifndef NDEBUG
144     locked_ = false;
145 #endif
146     mutex_.unlock();
147   }
148 
149   // this will assert if the mutex is not locked
150   // it does NOT verify that mutex is held by a calling thread
AssertHeld()151   void AssertHeld() {
152 #ifndef NDEBUG
153     assert(locked_);
154 #endif
155   }
156 
157   // Mutex is move only with lock ownership transfer
158   Mutex(const Mutex&) = delete;
159   void operator=(const Mutex&) = delete;
160 
161  private:
162 
163   friend class CondVar;
164 
getLock()165   std::mutex& getLock() {
166     return mutex_;
167   }
168 
169   std::mutex mutex_;
170 #ifndef NDEBUG
171   bool locked_;
172 #endif
173 };
174 
175 class RWMutex {
176  public:
RWMutex()177   RWMutex() { InitializeSRWLock(&srwLock_); }
178   // No copying allowed
179   RWMutex(const RWMutex&) = delete;
180   void operator=(const RWMutex&) = delete;
181 
ReadLock()182   void ReadLock() { AcquireSRWLockShared(&srwLock_); }
183 
WriteLock()184   void WriteLock() { AcquireSRWLockExclusive(&srwLock_); }
185 
ReadUnlock()186   void ReadUnlock() { ReleaseSRWLockShared(&srwLock_); }
187 
WriteUnlock()188   void WriteUnlock() { ReleaseSRWLockExclusive(&srwLock_); }
189 
190   // Empty as in POSIX
AssertHeld()191   void AssertHeld() {}
192 
193  private:
194   SRWLOCK srwLock_;
195 };
196 
197 class CondVar {
198  public:
CondVar(Mutex * mu)199   explicit CondVar(Mutex* mu) : mu_(mu) {
200   }
201 
202   ~CondVar();
203   void Wait();
204   bool TimedWait(uint64_t expiration_time);
205   void Signal();
206   void SignalAll();
207 
208   // Condition var is not copy/move constructible
209   CondVar(const CondVar&) = delete;
210   CondVar& operator=(const CondVar&) = delete;
211 
212   CondVar(CondVar&&) = delete;
213   CondVar& operator=(CondVar&&) = delete;
214 
215  private:
216   std::condition_variable cv_;
217   Mutex* mu_;
218 };
219 
220 // Wrapper around the platform efficient
221 // or otherwise preferrable implementation
222 using Thread = WindowsThread;
223 
224 // OnceInit type helps emulate
225 // Posix semantics with initialization
226 // adopted in the project
227 struct OnceType {
228 
229     struct Init {};
230 
OnceTypeOnceType231     OnceType() {}
OnceTypeOnceType232     OnceType(const Init&) {}
233     OnceType(const OnceType&) = delete;
234     OnceType& operator=(const OnceType&) = delete;
235 
236     std::once_flag flag_;
237 };
238 
239 #define LEVELDB_ONCE_INIT port::OnceType::Init()
240 extern void InitOnce(OnceType* once, void (*initializer)());
241 
242 #ifndef CACHE_LINE_SIZE
243 #define CACHE_LINE_SIZE 64U
244 #endif
245 
246 #ifdef ROCKSDB_JEMALLOC
247 // Separate inlines so they can be replaced if needed
248 void* jemalloc_aligned_alloc(size_t size, size_t alignment) ROCKSDB_NOEXCEPT;
249 void jemalloc_aligned_free(void* p) ROCKSDB_NOEXCEPT;
250 #endif
251 
cacheline_aligned_alloc(size_t size)252 inline void *cacheline_aligned_alloc(size_t size) {
253 #ifdef ROCKSDB_JEMALLOC
254   return jemalloc_aligned_alloc(size, CACHE_LINE_SIZE);
255 #else
256   return _aligned_malloc(size, CACHE_LINE_SIZE);
257 #endif
258 }
259 
cacheline_aligned_free(void * memblock)260 inline void cacheline_aligned_free(void *memblock) {
261 #ifdef ROCKSDB_JEMALLOC
262   jemalloc_aligned_free(memblock);
263 #else
264   _aligned_free(memblock);
265 #endif
266 }
267 
268 extern const size_t kPageSize;
269 
270 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 for MINGW32
271 // could not be worked around with by -mno-ms-bitfields
272 #ifndef __MINGW32__
273 #define ALIGN_AS(n) __declspec(align(n))
274 #else
275 #define ALIGN_AS(n)
276 #endif
277 
AsmVolatilePause()278 static inline void AsmVolatilePause() {
279 #if defined(_M_IX86) || defined(_M_X64)
280   YieldProcessor();
281 #endif
282   // it would be nice to get "wfe" on ARM here
283 }
284 
285 extern int PhysicalCoreID();
286 
287 // For Thread Local Storage abstraction
288 typedef DWORD pthread_key_t;
289 
pthread_key_create(pthread_key_t * key,void (* destructor)(void *))290 inline int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {
291   // Not used
292   (void)destructor;
293 
294   pthread_key_t k = TlsAlloc();
295   if (TLS_OUT_OF_INDEXES == k) {
296     return ENOMEM;
297   }
298 
299   *key = k;
300   return 0;
301 }
302 
pthread_key_delete(pthread_key_t key)303 inline int pthread_key_delete(pthread_key_t key) {
304   if (!TlsFree(key)) {
305     return EINVAL;
306   }
307   return 0;
308 }
309 
pthread_setspecific(pthread_key_t key,const void * value)310 inline int pthread_setspecific(pthread_key_t key, const void* value) {
311   if (!TlsSetValue(key, const_cast<void*>(value))) {
312     return ENOMEM;
313   }
314   return 0;
315 }
316 
pthread_getspecific(pthread_key_t key)317 inline void* pthread_getspecific(pthread_key_t key) {
318   void* result = TlsGetValue(key);
319   if (!result) {
320     if (GetLastError() != ERROR_SUCCESS) {
321       errno = EINVAL;
322     } else {
323       errno = NOERROR;
324     }
325   }
326   return result;
327 }
328 
329 // UNIX equiv although errno numbers will be off
330 // using C-runtime to implement. Note, this does not
331 // feel space with zeros in case the file is extended.
332 int truncate(const char* path, int64_t length);
333 int Truncate(std::string path, int64_t length);
334 void Crash(const std::string& srcfile, int srcline);
335 extern int GetMaxOpenFiles();
336 std::string utf16_to_utf8(const std::wstring& utf16);
337 std::wstring utf8_to_utf16(const std::string& utf8);
338 
339 using ThreadId = int;
340 
341 extern void SetCpuPriority(ThreadId id, CpuPriority priority);
342 
343 }  // namespace port
344 
345 
346 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
347 
348 #define RX_FILESTRING std::wstring
349 #define RX_FN(a) ROCKSDB_NAMESPACE::port::utf8_to_utf16(a)
350 #define FN_TO_RX(a) ROCKSDB_NAMESPACE::port::utf16_to_utf8(a)
351 #define RX_FNLEN(a) ::wcslen(a)
352 
353 #define RX_DeleteFile DeleteFileW
354 #define RX_CreateFile CreateFileW
355 #define RX_CreateFileMapping CreateFileMappingW
356 #define RX_GetFileAttributesEx GetFileAttributesExW
357 #define RX_FindFirstFileEx FindFirstFileExW
358 #define RX_FindNextFile FindNextFileW
359 #define RX_WIN32_FIND_DATA WIN32_FIND_DATAW
360 #define RX_CreateDirectory CreateDirectoryW
361 #define RX_RemoveDirectory RemoveDirectoryW
362 #define RX_GetFileAttributesEx GetFileAttributesExW
363 #define RX_MoveFileEx MoveFileExW
364 #define RX_CreateHardLink CreateHardLinkW
365 #define RX_PathIsRelative PathIsRelativeW
366 #define RX_GetCurrentDirectory GetCurrentDirectoryW
367 #define RX_GetDiskFreeSpaceEx GetDiskFreeSpaceExW
368 
369 #else
370 
371 #define RX_FILESTRING std::string
372 #define RX_FN(a) a
373 #define FN_TO_RX(a) a
374 #define RX_FNLEN(a) strlen(a)
375 
376 #define RX_DeleteFile DeleteFileA
377 #define RX_CreateFile CreateFileA
378 #define RX_CreateFileMapping CreateFileMappingA
379 #define RX_GetFileAttributesEx GetFileAttributesExA
380 #define RX_FindFirstFileEx FindFirstFileExA
381 #define RX_CreateDirectory CreateDirectoryA
382 #define RX_FindNextFile FindNextFileA
383 #define RX_WIN32_FIND_DATA WIN32_FIND_DATA
384 #define RX_CreateDirectory CreateDirectoryA
385 #define RX_RemoveDirectory RemoveDirectoryA
386 #define RX_GetFileAttributesEx GetFileAttributesExA
387 #define RX_MoveFileEx MoveFileExA
388 #define RX_CreateHardLink CreateHardLinkA
389 #define RX_PathIsRelative PathIsRelativeA
390 #define RX_GetCurrentDirectory GetCurrentDirectoryA
391 #define RX_GetDiskFreeSpaceEx GetDiskFreeSpaceExA
392 
393 #endif
394 
395 using port::pthread_key_t;
396 using port::pthread_key_create;
397 using port::pthread_key_delete;
398 using port::pthread_setspecific;
399 using port::pthread_getspecific;
400 using port::truncate;
401 
402 }  // namespace ROCKSDB_NAMESPACE
403