// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). // // Copyright (c) 2011 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. // // See port_example.h for documentation for the following types/functions. #pragma once // Always want minimum headers #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include //^^ should be included first before other system lib #include #include #include #include #include #include #include #include #include #include #include #include "port/win/win_thread.h" #include "rocksdb/port_defs.h" #undef min #undef max #undef DeleteFile #undef GetCurrentTime #ifndef strcasecmp #define strcasecmp _stricmp #endif #undef GetCurrentTime #undef DeleteFile #ifndef _SSIZE_T_DEFINED using ssize_t = SSIZE_T; #endif // size_t printf formatting named in the manner of C99 standard formatting // strings such as PRIu64 // in fact, we could use that one #ifndef ROCKSDB_PRIszt #define ROCKSDB_PRIszt "Iu" #endif #ifdef _MSC_VER #define __attribute__(A) #endif namespace ROCKSDB_NAMESPACE { #define PREFETCH(addr, rw, locality) extern const bool kDefaultToAdaptiveMutex; namespace port { // "Windows is designed to run on little-endian computer architectures." // https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types constexpr bool kLittleEndian = true; #undef PLATFORM_IS_LITTLE_ENDIAN class CondVar; class Mutex { public: static const char* kName() { return "std::mutex"; } explicit Mutex(bool IGNORED_adaptive = kDefaultToAdaptiveMutex) #ifndef NDEBUG : locked_(false) #endif { (void)IGNORED_adaptive; } ~Mutex(); void Lock() { mutex_.lock(); #ifndef NDEBUG locked_ = true; #endif } void Unlock() { #ifndef NDEBUG locked_ = false; #endif mutex_.unlock(); } bool TryLock() { bool ret = mutex_.try_lock(); #ifndef NDEBUG if (ret) { locked_ = true; } #endif return ret; } // this will assert if the mutex is not locked // it does NOT verify that mutex is held by a calling thread void AssertHeld() const { #ifndef NDEBUG assert(locked_); #endif } // Also implement std Lockable inline void lock() { Lock(); } inline void unlock() { Unlock(); } inline bool try_lock() { return TryLock(); } // Mutex is move only with lock ownership transfer Mutex(const Mutex&) = delete; void operator=(const Mutex&) = delete; private: friend class CondVar; std::mutex& getLock() { return mutex_; } std::mutex mutex_; #ifndef NDEBUG bool locked_; #endif }; class RWMutex { public: RWMutex() { InitializeSRWLock(&srwLock_); } // No copying allowed RWMutex(const RWMutex&) = delete; void operator=(const RWMutex&) = delete; void ReadLock() { AcquireSRWLockShared(&srwLock_); } void WriteLock() { AcquireSRWLockExclusive(&srwLock_); } void ReadUnlock() { ReleaseSRWLockShared(&srwLock_); } void WriteUnlock() { ReleaseSRWLockExclusive(&srwLock_); } // Empty as in POSIX void AssertHeld() const {} private: SRWLOCK srwLock_; }; class CondVar { public: explicit CondVar(Mutex* mu) : mu_(mu) {} ~CondVar(); Mutex* GetMutex() const { return mu_; } void Wait(); bool TimedWait(uint64_t expiration_time); void Signal(); void SignalAll(); // Condition var is not copy/move constructible CondVar(const CondVar&) = delete; CondVar& operator=(const CondVar&) = delete; CondVar(CondVar&&) = delete; CondVar& operator=(CondVar&&) = delete; private: std::condition_variable cv_; Mutex* mu_; }; #ifdef _POSIX_THREADS using Thread = std::thread; #else // Wrapper around the platform efficient // or otherwise preferrable implementation using Thread = WindowsThread; #endif // OnceInit type helps emulate // Posix semantics with initialization // adopted in the project struct OnceType { struct Init {}; OnceType() {} OnceType(const Init&) {} OnceType(const OnceType&) = delete; OnceType& operator=(const OnceType&) = delete; std::once_flag flag_; }; #define LEVELDB_ONCE_INIT port::OnceType::Init() void InitOnce(OnceType* once, void (*initializer)()); #ifndef CACHE_LINE_SIZE #define CACHE_LINE_SIZE 64U #endif #ifdef ROCKSDB_JEMALLOC // Separate inlines so they can be replaced if needed void* jemalloc_aligned_alloc(size_t size, size_t alignment) noexcept; void jemalloc_aligned_free(void* p) noexcept; #endif inline void* cacheline_aligned_alloc(size_t size) { #ifdef ROCKSDB_JEMALLOC return jemalloc_aligned_alloc(size, CACHE_LINE_SIZE); #else return _aligned_malloc(size, CACHE_LINE_SIZE); #endif } inline void cacheline_aligned_free(void* memblock) { #ifdef ROCKSDB_JEMALLOC jemalloc_aligned_free(memblock); #else _aligned_free(memblock); #endif } extern const size_t kPageSize; // Part of C++11 #define ALIGN_AS(n) alignas(n) static inline void AsmVolatilePause() { #if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) YieldProcessor(); #endif // it would be nice to get "wfe" on ARM here } int PhysicalCoreID(); // For Thread Local Storage abstraction using pthread_key_t = DWORD; inline int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) { // Not used (void)destructor; pthread_key_t k = TlsAlloc(); if (TLS_OUT_OF_INDEXES == k) { return ENOMEM; } *key = k; return 0; } inline int pthread_key_delete(pthread_key_t key) { if (!TlsFree(key)) { return EINVAL; } return 0; } inline int pthread_setspecific(pthread_key_t key, const void* value) { if (!TlsSetValue(key, const_cast(value))) { return ENOMEM; } return 0; } inline void* pthread_getspecific(pthread_key_t key) { void* result = TlsGetValue(key); if (!result) { if (GetLastError() != ERROR_SUCCESS) { errno = EINVAL; } else { errno = NOERROR; } } return result; } // UNIX equiv although errno numbers will be off // using C-runtime to implement. Note, this does not // feel space with zeros in case the file is extended. int truncate(const char* path, int64_t length); int Truncate(std::string path, int64_t length); void Crash(const std::string& srcfile, int srcline); int GetMaxOpenFiles(); std::string utf16_to_utf8(const std::wstring& utf16); std::wstring utf8_to_utf16(const std::string& utf8); using ThreadId = int; void SetCpuPriority(ThreadId id, CpuPriority priority); int64_t GetProcessID(); // Uses platform APIs to generate a 36-character RFC-4122 UUID. Returns // true on success or false on failure. bool GenerateRfcUuid(std::string* output); } // namespace port #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES #define RX_FILESTRING std::wstring #define RX_FN(a) ROCKSDB_NAMESPACE::port::utf8_to_utf16(a) #define FN_TO_RX(a) ROCKSDB_NAMESPACE::port::utf16_to_utf8(a) #define RX_FNCMP(a, b) ::wcscmp(a, RX_FN(b).c_str()) #define RX_FNLEN(a) ::wcslen(a) #define RX_DeleteFile DeleteFileW #define RX_CreateFile CreateFileW #define RX_CreateFileMapping CreateFileMappingW #define RX_GetFileAttributesEx GetFileAttributesExW #define RX_FindFirstFileEx FindFirstFileExW #define RX_FindNextFile FindNextFileW #define RX_WIN32_FIND_DATA WIN32_FIND_DATAW #define RX_CreateDirectory CreateDirectoryW #define RX_RemoveDirectory RemoveDirectoryW #define RX_GetFileAttributesEx GetFileAttributesExW #define RX_MoveFileEx MoveFileExW #define RX_CreateHardLink CreateHardLinkW #define RX_PathIsRelative PathIsRelativeW #define RX_GetCurrentDirectory GetCurrentDirectoryW #define RX_GetDiskFreeSpaceEx GetDiskFreeSpaceExW #define RX_PathIsDirectory PathIsDirectoryW #else #define RX_FILESTRING std::string #define RX_FN(a) a #define FN_TO_RX(a) a #define RX_FNCMP(a, b) strcmp(a, b) #define RX_FNLEN(a) strlen(a) #define RX_DeleteFile DeleteFileA #define RX_CreateFile CreateFileA #define RX_CreateFileMapping CreateFileMappingA #define RX_GetFileAttributesEx GetFileAttributesExA #define RX_FindFirstFileEx FindFirstFileExA #define RX_CreateDirectory CreateDirectoryA #define RX_FindNextFile FindNextFileA #define RX_WIN32_FIND_DATA WIN32_FIND_DATAA #define RX_CreateDirectory CreateDirectoryA #define RX_RemoveDirectory RemoveDirectoryA #define RX_GetFileAttributesEx GetFileAttributesExA #define RX_MoveFileEx MoveFileExA #define RX_CreateHardLink CreateHardLinkA #define RX_PathIsRelative PathIsRelativeA #define RX_GetCurrentDirectory GetCurrentDirectoryA #define RX_GetDiskFreeSpaceEx GetDiskFreeSpaceExA #define RX_PathIsDirectory PathIsDirectoryA #endif using port::pthread_getspecific; using port::pthread_key_create; using port::pthread_key_delete; using port::pthread_key_t; using port::pthread_setspecific; using port::truncate; } // namespace ROCKSDB_NAMESPACE