]>
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 | |
20effc67 | 9 | |
1e59de90 | 10 | #include "port/lang.h" |
20effc67 TL |
11 | #if !defined(OS_WIN) |
12 | ||
7c673cae | 13 | #include <dirent.h> |
f67539c2 TL |
14 | #ifndef ROCKSDB_NO_DYNAMIC_EXTENSION |
15 | #include <dlfcn.h> | |
16 | #endif | |
7c673cae FG |
17 | #include <errno.h> |
18 | #include <fcntl.h> | |
f67539c2 | 19 | |
f67539c2 TL |
20 | #if defined(ROCKSDB_IOURING_PRESENT) |
21 | #include <liburing.h> | |
22 | #endif | |
7c673cae FG |
23 | #include <pthread.h> |
24 | #include <signal.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
7c673cae FG |
28 | #include <sys/mman.h> |
29 | #include <sys/stat.h> | |
11fdf7f2 | 30 | #if defined(OS_LINUX) || defined(OS_SOLARIS) || defined(OS_ANDROID) |
7c673cae | 31 | #include <sys/statfs.h> |
7c673cae | 32 | #endif |
11fdf7f2 | 33 | #include <sys/statvfs.h> |
7c673cae FG |
34 | #include <sys/time.h> |
35 | #include <sys/types.h> | |
f67539c2 TL |
36 | #if defined(ROCKSDB_IOURING_PRESENT) |
37 | #include <sys/uio.h> | |
38 | #endif | |
7c673cae | 39 | #include <time.h> |
1e59de90 TL |
40 | #include <unistd.h> |
41 | ||
7c673cae FG |
42 | #include <algorithm> |
43 | // Get nano time includes | |
20effc67 | 44 | #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) |
7c673cae | 45 | #elif defined(__MACH__) |
f67539c2 | 46 | #include <Availability.h> |
7c673cae FG |
47 | #include <mach/clock.h> |
48 | #include <mach/mach.h> | |
49 | #else | |
50 | #include <chrono> | |
51 | #endif | |
52 | #include <deque> | |
53 | #include <set> | |
54 | #include <vector> | |
55 | ||
f67539c2 | 56 | #include "env/composite_env_wrapper.h" |
7c673cae | 57 | #include "env/io_posix.h" |
7c673cae FG |
58 | #include "monitoring/iostats_context_imp.h" |
59 | #include "monitoring/thread_status_updater.h" | |
60 | #include "port/port.h" | |
1e59de90 TL |
61 | #include "port/sys_time.h" |
62 | #include "rocksdb/env.h" | |
7c673cae FG |
63 | #include "rocksdb/options.h" |
64 | #include "rocksdb/slice.h" | |
1e59de90 | 65 | #include "rocksdb/system_clock.h" |
f67539c2 | 66 | #include "test_util/sync_point.h" |
7c673cae | 67 | #include "util/coding.h" |
11fdf7f2 | 68 | #include "util/compression_context_cache.h" |
7c673cae FG |
69 | #include "util/random.h" |
70 | #include "util/string_util.h" | |
7c673cae FG |
71 | #include "util/thread_local.h" |
72 | #include "util/threadpool_imp.h" | |
73 | ||
74 | #if !defined(TMPFS_MAGIC) | |
75 | #define TMPFS_MAGIC 0x01021994 | |
76 | #endif | |
77 | #if !defined(XFS_SUPER_MAGIC) | |
78 | #define XFS_SUPER_MAGIC 0x58465342 | |
79 | #endif | |
80 | #if !defined(EXT4_SUPER_MAGIC) | |
81 | #define EXT4_SUPER_MAGIC 0xEF53 | |
82 | #endif | |
83 | ||
f67539c2 TL |
84 | namespace ROCKSDB_NAMESPACE { |
85 | #if defined(OS_WIN) | |
86 | static const std::string kSharedLibExt = ".dll"; | |
87 | static const char kPathSeparator = ';'; | |
88 | #else | |
89 | static const char kPathSeparator = ':'; | |
90 | #if defined(OS_MACOSX) | |
91 | static const std::string kSharedLibExt = ".dylib"; | |
92 | #else | |
93 | static const std::string kSharedLibExt = ".so"; | |
94 | #endif | |
95 | #endif | |
7c673cae FG |
96 | |
97 | namespace { | |
98 | ||
99 | ThreadStatusUpdater* CreateThreadStatusUpdater() { | |
100 | return new ThreadStatusUpdater(); | |
101 | } | |
102 | ||
f67539c2 TL |
103 | #ifndef ROCKSDB_NO_DYNAMIC_EXTENSION |
104 | class PosixDynamicLibrary : public DynamicLibrary { | |
105 | public: | |
106 | PosixDynamicLibrary(const std::string& name, void* handle) | |
107 | : name_(name), handle_(handle) {} | |
108 | ~PosixDynamicLibrary() override { dlclose(handle_); } | |
109 | ||
110 | Status LoadSymbol(const std::string& sym_name, void** func) override { | |
111 | assert(nullptr != func); | |
112 | dlerror(); // Clear any old error | |
113 | *func = dlsym(handle_, sym_name.c_str()); | |
114 | if (*func != nullptr) { | |
115 | return Status::OK(); | |
116 | } else { | |
117 | char* err = dlerror(); | |
118 | return Status::NotFound("Error finding symbol: " + sym_name, err); | |
119 | } | |
120 | } | |
11fdf7f2 | 121 | |
f67539c2 | 122 | const char* Name() const override { return name_.c_str(); } |
7c673cae | 123 | |
f67539c2 TL |
124 | private: |
125 | std::string name_; | |
126 | void* handle_; | |
7c673cae | 127 | }; |
f67539c2 | 128 | #endif // !ROCKSDB_NO_DYNAMIC_EXTENSION |
7c673cae | 129 | |
1e59de90 TL |
130 | class PosixClock : public SystemClock { |
131 | public: | |
132 | static const char* kClassName() { return "PosixClock"; } | |
133 | const char* Name() const override { return kDefaultName(); } | |
134 | const char* NickName() const override { return kClassName(); } | |
135 | ||
136 | uint64_t NowMicros() override { | |
137 | port::TimeVal tv; | |
138 | port::GetTimeOfDay(&tv, nullptr); | |
139 | return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec; | |
140 | } | |
141 | ||
142 | uint64_t NowNanos() override { | |
143 | #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \ | |
144 | defined(OS_AIX) | |
145 | struct timespec ts; | |
146 | clock_gettime(CLOCK_MONOTONIC, &ts); | |
147 | return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec; | |
148 | #elif defined(OS_SOLARIS) | |
149 | return gethrtime(); | |
150 | #elif defined(__MACH__) | |
151 | clock_serv_t cclock; | |
152 | mach_timespec_t ts; | |
153 | host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); | |
154 | clock_get_time(cclock, &ts); | |
155 | mach_port_deallocate(mach_task_self(), cclock); | |
156 | return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec; | |
157 | #else | |
158 | return std::chrono::duration_cast<std::chrono::nanoseconds>( | |
159 | std::chrono::steady_clock::now().time_since_epoch()) | |
160 | .count(); | |
161 | #endif | |
162 | } | |
163 | ||
164 | uint64_t CPUMicros() override { | |
165 | #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \ | |
166 | defined(OS_AIX) || (defined(__MACH__) && defined(__MAC_10_12)) | |
167 | struct timespec ts; | |
168 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); | |
169 | return (static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec) / 1000; | |
170 | #endif | |
171 | return 0; | |
172 | } | |
173 | ||
174 | uint64_t CPUNanos() override { | |
175 | #if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \ | |
176 | defined(OS_AIX) || (defined(__MACH__) && defined(__MAC_10_12)) | |
177 | struct timespec ts; | |
178 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); | |
179 | return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec; | |
180 | #endif | |
181 | return 0; | |
182 | } | |
183 | ||
184 | void SleepForMicroseconds(int micros) override { usleep(micros); } | |
185 | ||
186 | Status GetCurrentTime(int64_t* unix_time) override { | |
187 | time_t ret = time(nullptr); | |
188 | if (ret == (time_t)-1) { | |
189 | return IOError("GetCurrentTime", "", errno); | |
190 | } | |
191 | *unix_time = (int64_t)ret; | |
192 | return Status::OK(); | |
193 | } | |
194 | ||
195 | std::string TimeToString(uint64_t secondsSince1970) override { | |
196 | const time_t seconds = (time_t)secondsSince1970; | |
197 | struct tm t; | |
198 | int maxsize = 64; | |
199 | std::string dummy; | |
200 | dummy.reserve(maxsize); | |
201 | dummy.resize(maxsize); | |
202 | char* p = &dummy[0]; | |
203 | port::LocalTimeR(&seconds, &t); | |
204 | snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900, | |
205 | t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); | |
206 | return dummy; | |
207 | } | |
208 | }; | |
209 | ||
210 | class PosixEnv : public CompositeEnv { | |
7c673cae | 211 | public: |
1e59de90 TL |
212 | static const char* kClassName() { return "PosixEnv"; } |
213 | const char* Name() const override { return kClassName(); } | |
214 | const char* NickName() const override { return kDefaultName(); } | |
7c673cae | 215 | |
494da23a | 216 | ~PosixEnv() override { |
20effc67 TL |
217 | if (this == Env::Default()) { |
218 | for (const auto tid : threads_to_join_) { | |
219 | pthread_join(tid, nullptr); | |
220 | } | |
221 | for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) { | |
222 | thread_pools_[pool_id].JoinAllThreads(); | |
223 | } | |
224 | // Do not delete the thread_status_updater_ in order to avoid the | |
225 | // free after use when Env::Default() is destructed while some other | |
226 | // child threads are still trying to update thread status. All | |
227 | // PosixEnv instances use the same thread_status_updater_, so never | |
228 | // explicitly delete it. | |
7c673cae FG |
229 | } |
230 | } | |
231 | ||
232 | void SetFD_CLOEXEC(int fd, const EnvOptions* options) { | |
233 | if ((options == nullptr || options->set_fd_cloexec) && fd > 0) { | |
234 | fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); | |
235 | } | |
236 | } | |
237 | ||
f67539c2 TL |
238 | #ifndef ROCKSDB_NO_DYNAMIC_EXTENSION |
239 | // Loads the named library into the result. | |
240 | // If the input name is empty, the current executable is loaded | |
241 | // On *nix systems, a "lib" prefix is added to the name if one is not supplied | |
242 | // Comparably, the appropriate shared library extension is added to the name | |
243 | // if not supplied. If search_path is not specified, the shared library will | |
244 | // be loaded using the default path (LD_LIBRARY_PATH) If search_path is | |
245 | // specified, the shared library will be searched for in the directories | |
246 | // provided by the search path | |
247 | Status LoadLibrary(const std::string& name, const std::string& path, | |
248 | std::shared_ptr<DynamicLibrary>* result) override { | |
f67539c2 TL |
249 | assert(result != nullptr); |
250 | if (name.empty()) { | |
251 | void* hndl = dlopen(NULL, RTLD_NOW); | |
252 | if (hndl != nullptr) { | |
253 | result->reset(new PosixDynamicLibrary(name, hndl)); | |
254 | return Status::OK(); | |
7c673cae | 255 | } |
7c673cae | 256 | } else { |
f67539c2 TL |
257 | std::string library_name = name; |
258 | if (library_name.find(kSharedLibExt) == std::string::npos) { | |
259 | library_name = library_name + kSharedLibExt; | |
7c673cae | 260 | } |
f67539c2 TL |
261 | #if !defined(OS_WIN) |
262 | if (library_name.find('/') == std::string::npos && | |
263 | library_name.compare(0, 3, "lib") != 0) { | |
264 | library_name = "lib" + library_name; | |
7c673cae FG |
265 | } |
266 | #endif | |
f67539c2 TL |
267 | if (path.empty()) { |
268 | void* hndl = dlopen(library_name.c_str(), RTLD_NOW); | |
269 | if (hndl != nullptr) { | |
270 | result->reset(new PosixDynamicLibrary(library_name, hndl)); | |
271 | return Status::OK(); | |
7c673cae | 272 | } |
f67539c2 TL |
273 | } else { |
274 | std::string local_path; | |
275 | std::stringstream ss(path); | |
276 | while (getline(ss, local_path, kPathSeparator)) { | |
277 | if (!path.empty()) { | |
278 | std::string full_name = local_path + "/" + library_name; | |
279 | void* hndl = dlopen(full_name.c_str(), RTLD_NOW); | |
280 | if (hndl != nullptr) { | |
281 | result->reset(new PosixDynamicLibrary(full_name, hndl)); | |
282 | return Status::OK(); | |
283 | } | |
284 | } | |
11fdf7f2 | 285 | } |
7c673cae FG |
286 | } |
287 | } | |
f67539c2 TL |
288 | return Status::IOError( |
289 | IOErrorMsg("Failed to open shared library: xs", name), dlerror()); | |
7c673cae | 290 | } |
f67539c2 | 291 | #endif // !ROCKSDB_NO_DYNAMIC_EXTENSION |
7c673cae | 292 | |
494da23a TL |
293 | void Schedule(void (*function)(void* arg1), void* arg, Priority pri = LOW, |
294 | void* tag = nullptr, | |
295 | void (*unschedFunction)(void* arg) = nullptr) override; | |
7c673cae | 296 | |
494da23a | 297 | int UnSchedule(void* arg, Priority pri) override; |
7c673cae | 298 | |
494da23a | 299 | void StartThread(void (*function)(void* arg), void* arg) override; |
7c673cae | 300 | |
494da23a | 301 | void WaitForJoin() override; |
7c673cae | 302 | |
494da23a | 303 | unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override; |
7c673cae | 304 | |
1e59de90 TL |
305 | int ReserveThreads(int threads_to_be_reserved, Priority pri) override; |
306 | ||
307 | int ReleaseThreads(int threads_to_be_released, Priority pri) override; | |
308 | ||
494da23a | 309 | Status GetThreadList(std::vector<ThreadStatus>* thread_list) override { |
7c673cae FG |
310 | assert(thread_status_updater_); |
311 | return thread_status_updater_->GetThreadList(thread_list); | |
312 | } | |
313 | ||
1e59de90 | 314 | uint64_t GetThreadID() const override { |
7c673cae | 315 | uint64_t thread_id = 0; |
1e59de90 TL |
316 | #if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ) |
317 | #if __GLIBC_PREREQ(2, 30) | |
318 | thread_id = ::gettid(); | |
319 | #else // __GLIBC_PREREQ(2, 30) | |
320 | pthread_t tid = pthread_self(); | |
7c673cae | 321 | memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); |
1e59de90 TL |
322 | #endif // __GLIBC_PREREQ(2, 30) |
323 | #else // defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ) | |
7c673cae | 324 | pthread_t tid = pthread_self(); |
1e59de90 TL |
325 | memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); |
326 | #endif // defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ) | |
327 | return thread_id; | |
494da23a TL |
328 | } |
329 | ||
494da23a | 330 | Status GetHostName(char* name, uint64_t len) override { |
7c673cae FG |
331 | int ret = gethostname(name, static_cast<size_t>(len)); |
332 | if (ret < 0) { | |
f67539c2 | 333 | if (errno == EFAULT || errno == EINVAL) { |
1e59de90 | 334 | return Status::InvalidArgument(errnoStr(errno).c_str()); |
f67539c2 | 335 | } else { |
11fdf7f2 | 336 | return IOError("GetHostName", name, errno); |
f67539c2 | 337 | } |
7c673cae FG |
338 | } |
339 | return Status::OK(); | |
340 | } | |
341 | ||
f67539c2 TL |
342 | ThreadStatusUpdater* GetThreadStatusUpdater() const override { |
343 | return Env::GetThreadStatusUpdater(); | |
7c673cae FG |
344 | } |
345 | ||
f67539c2 TL |
346 | std::string GenerateUniqueId() override { return Env::GenerateUniqueId(); } |
347 | ||
7c673cae | 348 | // Allow increasing the number of worker threads. |
494da23a | 349 | void SetBackgroundThreads(int num, Priority pri) override { |
11fdf7f2 | 350 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); |
7c673cae FG |
351 | thread_pools_[pri].SetBackgroundThreads(num); |
352 | } | |
353 | ||
494da23a | 354 | int GetBackgroundThreads(Priority pri) override { |
11fdf7f2 TL |
355 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); |
356 | return thread_pools_[pri].GetBackgroundThreads(); | |
357 | } | |
358 | ||
494da23a | 359 | Status SetAllowNonOwnerAccess(bool allow_non_owner_access) override { |
11fdf7f2 TL |
360 | allow_non_owner_access_ = allow_non_owner_access; |
361 | return Status::OK(); | |
362 | } | |
363 | ||
7c673cae | 364 | // Allow increasing the number of worker threads. |
494da23a | 365 | void IncBackgroundThreadsIfNeeded(int num, Priority pri) override { |
11fdf7f2 | 366 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); |
7c673cae FG |
367 | thread_pools_[pri].IncBackgroundThreadsIfNeeded(num); |
368 | } | |
369 | ||
20effc67 | 370 | void LowerThreadPoolIOPriority(Priority pool) override { |
11fdf7f2 | 371 | assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH); |
7c673cae FG |
372 | #ifdef OS_LINUX |
373 | thread_pools_[pool].LowerIOPriority(); | |
11fdf7f2 TL |
374 | #else |
375 | (void)pool; | |
376 | #endif | |
377 | } | |
378 | ||
20effc67 | 379 | void LowerThreadPoolCPUPriority(Priority pool) override { |
11fdf7f2 | 380 | assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH); |
20effc67 TL |
381 | thread_pools_[pool].LowerCPUPriority(CpuPriority::kLow); |
382 | } | |
383 | ||
384 | Status LowerThreadPoolCPUPriority(Priority pool, CpuPriority pri) override { | |
385 | assert(pool >= Priority::BOTTOM && pool <= Priority::HIGH); | |
386 | thread_pools_[pool].LowerCPUPriority(pri); | |
387 | return Status::OK(); | |
7c673cae FG |
388 | } |
389 | ||
7c673cae | 390 | private: |
20effc67 TL |
391 | friend Env* Env::Default(); |
392 | // Constructs the default Env, a singleton | |
393 | PosixEnv(); | |
394 | ||
395 | // The below 4 members are only used by the default PosixEnv instance. | |
396 | // Non-default instances simply maintain references to the backing | |
397 | // members in te default instance | |
398 | std::vector<ThreadPoolImpl> thread_pools_storage_; | |
399 | pthread_mutex_t mu_storage_; | |
400 | std::vector<pthread_t> threads_to_join_storage_; | |
401 | bool allow_non_owner_access_storage_; | |
402 | ||
403 | std::vector<ThreadPoolImpl>& thread_pools_; | |
404 | pthread_mutex_t& mu_; | |
405 | std::vector<pthread_t>& threads_to_join_; | |
11fdf7f2 TL |
406 | // If true, allow non owner read access for db files. Otherwise, non-owner |
407 | // has no access to db files. | |
20effc67 | 408 | bool& allow_non_owner_access_; |
7c673cae FG |
409 | }; |
410 | ||
411 | PosixEnv::PosixEnv() | |
1e59de90 | 412 | : CompositeEnv(FileSystem::Default(), SystemClock::Default()), |
20effc67 TL |
413 | thread_pools_storage_(Priority::TOTAL), |
414 | allow_non_owner_access_storage_(true), | |
415 | thread_pools_(thread_pools_storage_), | |
416 | mu_(mu_storage_), | |
417 | threads_to_join_(threads_to_join_storage_), | |
418 | allow_non_owner_access_(allow_non_owner_access_storage_) { | |
7c673cae FG |
419 | ThreadPoolImpl::PthreadCall("mutex_init", pthread_mutex_init(&mu_, nullptr)); |
420 | for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) { | |
421 | thread_pools_[pool_id].SetThreadPriority( | |
422 | static_cast<Env::Priority>(pool_id)); | |
423 | // This allows later initializing the thread-local-env of each thread. | |
424 | thread_pools_[pool_id].SetHostEnv(this); | |
425 | } | |
426 | thread_status_updater_ = CreateThreadStatusUpdater(); | |
427 | } | |
428 | ||
429 | void PosixEnv::Schedule(void (*function)(void* arg1), void* arg, Priority pri, | |
430 | void* tag, void (*unschedFunction)(void* arg)) { | |
11fdf7f2 | 431 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); |
7c673cae FG |
432 | thread_pools_[pri].Schedule(function, arg, tag, unschedFunction); |
433 | } | |
434 | ||
435 | int PosixEnv::UnSchedule(void* arg, Priority pri) { | |
436 | return thread_pools_[pri].UnSchedule(arg); | |
437 | } | |
438 | ||
439 | unsigned int PosixEnv::GetThreadPoolQueueLen(Priority pri) const { | |
11fdf7f2 | 440 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); |
7c673cae FG |
441 | return thread_pools_[pri].GetQueueLen(); |
442 | } | |
443 | ||
1e59de90 TL |
444 | int PosixEnv::ReserveThreads(int threads_to_reserved, Priority pri) { |
445 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); | |
446 | return thread_pools_[pri].ReserveThreads(threads_to_reserved); | |
447 | } | |
448 | ||
449 | int PosixEnv::ReleaseThreads(int threads_to_released, Priority pri) { | |
450 | assert(pri >= Priority::BOTTOM && pri <= Priority::HIGH); | |
451 | return thread_pools_[pri].ReleaseThreads(threads_to_released); | |
452 | } | |
453 | ||
7c673cae FG |
454 | struct StartThreadState { |
455 | void (*user_function)(void*); | |
456 | void* arg; | |
457 | }; | |
458 | ||
459 | static void* StartThreadWrapper(void* arg) { | |
460 | StartThreadState* state = reinterpret_cast<StartThreadState*>(arg); | |
461 | state->user_function(state->arg); | |
462 | delete state; | |
463 | return nullptr; | |
464 | } | |
465 | ||
466 | void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { | |
467 | pthread_t t; | |
468 | StartThreadState* state = new StartThreadState; | |
469 | state->user_function = function; | |
470 | state->arg = arg; | |
471 | ThreadPoolImpl::PthreadCall( | |
472 | "start thread", pthread_create(&t, nullptr, &StartThreadWrapper, state)); | |
473 | ThreadPoolImpl::PthreadCall("lock", pthread_mutex_lock(&mu_)); | |
474 | threads_to_join_.push_back(t); | |
475 | ThreadPoolImpl::PthreadCall("unlock", pthread_mutex_unlock(&mu_)); | |
476 | } | |
477 | ||
478 | void PosixEnv::WaitForJoin() { | |
479 | for (const auto tid : threads_to_join_) { | |
480 | pthread_join(tid, nullptr); | |
481 | } | |
482 | threads_to_join_.clear(); | |
483 | } | |
484 | ||
485 | } // namespace | |
486 | ||
7c673cae FG |
487 | // |
488 | // Default Posix Env | |
489 | // | |
490 | Env* Env::Default() { | |
491 | // The following function call initializes the singletons of ThreadLocalPtr | |
492 | // right before the static default_env. This guarantees default_env will | |
493 | // always being destructed before the ThreadLocalPtr singletons get | |
494 | // destructed as C++ guarantees that the destructions of static variables | |
495 | // is in the reverse order of their constructions. | |
496 | // | |
497 | // Since static members are destructed in the reverse order | |
498 | // of their construction, having this call here guarantees that | |
499 | // the destructor of static PosixEnv will go first, then the | |
500 | // the singletons of ThreadLocalPtr. | |
501 | ThreadLocalPtr::InitSingletons(); | |
11fdf7f2 TL |
502 | CompressionContextCache::InitSingleton(); |
503 | INIT_SYNC_POINT_SINGLETONS(); | |
1e59de90 TL |
504 | // ~PosixEnv must be called on exit |
505 | //**TODO: Can we make this a STATIC_AVOID_DESTRUCTION? | |
7c673cae | 506 | static PosixEnv default_env; |
20effc67 TL |
507 | return &default_env; |
508 | } | |
509 | ||
1e59de90 TL |
510 | // |
511 | // Default Posix SystemClock | |
512 | // | |
513 | const std::shared_ptr<SystemClock>& SystemClock::Default() { | |
514 | STATIC_AVOID_DESTRUCTION(std::shared_ptr<SystemClock>, instance) | |
515 | (std::make_shared<PosixClock>()); | |
516 | return instance; | |
7c673cae | 517 | } |
f67539c2 | 518 | } // namespace ROCKSDB_NAMESPACE |
20effc67 TL |
519 | |
520 | #endif |