port_win.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. #if defined(OS_WIN)
  10. #include "port/win/port_win.h"
  11. #include <assert.h>
  12. #include <io.h>
  13. #include <rpc.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <chrono>
  17. #include <cstdlib>
  18. #include <exception>
  19. #include <memory>
  20. #include "port/port_dirent.h"
  21. #include "port/sys_time.h"
  22. #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
  23. // utf8 <-> utf16
  24. #include <codecvt>
  25. #include <locale>
  26. #include <string>
  27. #endif
  28. #include "logging/logging.h"
  29. namespace ROCKSDB_NAMESPACE {
  30. const bool kDefaultToAdaptiveMutex = false;
  31. namespace port {
  32. #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
  33. std::string utf16_to_utf8(const std::wstring& utf16) {
  34. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
  35. return convert.to_bytes(utf16);
  36. }
  37. std::wstring utf8_to_utf16(const std::string& utf8) {
  38. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
  39. return converter.from_bytes(utf8);
  40. }
  41. #endif
  42. void GetTimeOfDay(TimeVal* tv, struct timezone* /* tz */) {
  43. std::chrono::microseconds usNow(
  44. std::chrono::duration_cast<std::chrono::microseconds>(
  45. std::chrono::system_clock::now().time_since_epoch()));
  46. std::chrono::seconds secNow(
  47. std::chrono::duration_cast<std::chrono::seconds>(usNow));
  48. tv->tv_sec = static_cast<long>(secNow.count());
  49. tv->tv_usec = static_cast<long>(
  50. usNow.count() -
  51. std::chrono::duration_cast<std::chrono::microseconds>(secNow).count());
  52. }
  53. Mutex::~Mutex() {}
  54. CondVar::~CondVar() {}
  55. void CondVar::Wait() {
  56. // Caller must ensure that mutex is held prior to calling this method
  57. std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
  58. #ifndef NDEBUG
  59. mu_->locked_ = false;
  60. #endif
  61. cv_.wait(lk);
  62. #ifndef NDEBUG
  63. mu_->locked_ = true;
  64. #endif
  65. // Release ownership of the lock as we don't want it to be unlocked when
  66. // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
  67. lk.release();
  68. }
  69. bool CondVar::TimedWait(uint64_t abs_time_us) {
  70. // MSVC++ library implements wait_until in terms of wait_for so
  71. // we need to convert absolute wait into relative wait.
  72. std::chrono::microseconds usAbsTime(abs_time_us);
  73. std::chrono::microseconds usNow(
  74. std::chrono::duration_cast<std::chrono::microseconds>(
  75. std::chrono::system_clock::now().time_since_epoch()));
  76. std::chrono::microseconds relTimeUs = (usAbsTime > usNow)
  77. ? (usAbsTime - usNow)
  78. : std::chrono::microseconds::zero();
  79. // Caller must ensure that mutex is held prior to calling this method
  80. std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
  81. // Work around https://github.com/microsoft/STL/issues/369
  82. // std::condition_variable_any::wait_for had a fix, but
  83. // std::condition_variable still doesn't have a fix in STL yet
  84. #if defined(_MSC_VER)
  85. if (relTimeUs == std::chrono::microseconds::zero()) {
  86. lk.unlock();
  87. lk.lock();
  88. }
  89. #endif
  90. #ifndef NDEBUG
  91. mu_->locked_ = false;
  92. #endif
  93. std::cv_status cvStatus = cv_.wait_for(lk, relTimeUs);
  94. #ifndef NDEBUG
  95. mu_->locked_ = true;
  96. #endif
  97. // Release ownership of the lock as we don't want it to be unlocked when
  98. // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
  99. lk.release();
  100. if (cvStatus == std::cv_status::timeout) {
  101. return true;
  102. }
  103. return false;
  104. }
  105. void CondVar::Signal() { cv_.notify_one(); }
  106. void CondVar::SignalAll() { cv_.notify_all(); }
  107. int PhysicalCoreID() { return GetCurrentProcessorNumber(); }
  108. void InitOnce(OnceType* once, void (*initializer)()) {
  109. std::call_once(once->flag_, initializer);
  110. }
  111. // Private structure, exposed only by pointer
  112. struct DIR {
  113. HANDLE handle_;
  114. bool firstread_;
  115. RX_WIN32_FIND_DATA data_;
  116. dirent entry_;
  117. DIR() : handle_(INVALID_HANDLE_VALUE), firstread_(true) {}
  118. DIR(const DIR&) = delete;
  119. DIR& operator=(const DIR&) = delete;
  120. ~DIR() {
  121. if (INVALID_HANDLE_VALUE != handle_) {
  122. ::FindClose(handle_);
  123. }
  124. }
  125. };
  126. DIR* opendir(const char* name) {
  127. if (!name || *name == 0) {
  128. errno = ENOENT;
  129. return nullptr;
  130. }
  131. std::string pattern(name);
  132. pattern.append("\\").append("*");
  133. std::unique_ptr<DIR> dir(new DIR);
  134. dir->handle_ =
  135. RX_FindFirstFileEx(RX_FN(pattern).c_str(),
  136. FindExInfoBasic, // Do not want alternative name
  137. &dir->data_, FindExSearchNameMatch,
  138. NULL, // lpSearchFilter
  139. 0);
  140. if (dir->handle_ == INVALID_HANDLE_VALUE) {
  141. return nullptr;
  142. }
  143. RX_FILESTRING x(dir->data_.cFileName, RX_FNLEN(dir->data_.cFileName));
  144. strcpy_s(dir->entry_.d_name, sizeof(dir->entry_.d_name), FN_TO_RX(x).c_str());
  145. return dir.release();
  146. }
  147. struct dirent* readdir(DIR* dirp) {
  148. if (!dirp || dirp->handle_ == INVALID_HANDLE_VALUE) {
  149. errno = EBADF;
  150. return nullptr;
  151. }
  152. if (dirp->firstread_) {
  153. dirp->firstread_ = false;
  154. return &dirp->entry_;
  155. }
  156. auto ret = RX_FindNextFile(dirp->handle_, &dirp->data_);
  157. if (ret == 0) {
  158. return nullptr;
  159. }
  160. RX_FILESTRING x(dirp->data_.cFileName, RX_FNLEN(dirp->data_.cFileName));
  161. strcpy_s(dirp->entry_.d_name, sizeof(dirp->entry_.d_name),
  162. FN_TO_RX(x).c_str());
  163. return &dirp->entry_;
  164. }
  165. int closedir(DIR* dirp) {
  166. delete dirp;
  167. return 0;
  168. }
  169. int truncate(const char* path, int64_t length) {
  170. if (path == nullptr) {
  171. errno = EFAULT;
  172. return -1;
  173. }
  174. return ROCKSDB_NAMESPACE::port::Truncate(path, length);
  175. }
  176. int Truncate(std::string path, int64_t len) {
  177. if (len < 0) {
  178. errno = EINVAL;
  179. return -1;
  180. }
  181. HANDLE hFile =
  182. RX_CreateFile(RX_FN(path).c_str(), GENERIC_READ | GENERIC_WRITE,
  183. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  184. NULL, // Security attrs
  185. OPEN_EXISTING, // Truncate existing file only
  186. FILE_ATTRIBUTE_NORMAL, NULL);
  187. if (INVALID_HANDLE_VALUE == hFile) {
  188. auto lastError = GetLastError();
  189. if (lastError == ERROR_FILE_NOT_FOUND) {
  190. errno = ENOENT;
  191. } else if (lastError == ERROR_ACCESS_DENIED) {
  192. errno = EACCES;
  193. } else {
  194. errno = EIO;
  195. }
  196. return -1;
  197. }
  198. int result = 0;
  199. FILE_END_OF_FILE_INFO end_of_file;
  200. end_of_file.EndOfFile.QuadPart = len;
  201. if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file,
  202. sizeof(FILE_END_OF_FILE_INFO))) {
  203. errno = EIO;
  204. result = -1;
  205. }
  206. CloseHandle(hFile);
  207. return result;
  208. }
  209. void Crash(const std::string& srcfile, int srcline) {
  210. fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline);
  211. fflush(stdout);
  212. abort();
  213. }
  214. int GetMaxOpenFiles() { return -1; }
  215. // Assume 4KB page size
  216. const size_t kPageSize = 4U * 1024U;
  217. void SetCpuPriority(ThreadId id, CpuPriority priority) {
  218. // Not supported
  219. (void)id;
  220. (void)priority;
  221. }
  222. int64_t GetProcessID() { return GetCurrentProcessId(); }
  223. bool GenerateRfcUuid(std::string* output) {
  224. UUID uuid;
  225. UuidCreateSequential(&uuid);
  226. RPC_CSTR rpc_str;
  227. auto status = UuidToStringA(&uuid, &rpc_str);
  228. if (status != RPC_S_OK) {
  229. return false;
  230. }
  231. // rpc_str is nul-terminated.
  232. // reinterpret_cast for possible change between signed/unsigned char.
  233. *output = reinterpret_cast<char*>(rpc_str);
  234. status = RpcStringFreeA(&rpc_str);
  235. assert(status == RPC_S_OK);
  236. return true;
  237. }
  238. } // namespace port
  239. } // namespace ROCKSDB_NAMESPACE
  240. #endif