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