]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/port/port_posix.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / port / port_posix.cc
CommitLineData
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
TL
10#if !defined(OS_WIN)
11
7c673cae
FG
12#include "port/port_posix.h"
13
14#include <assert.h>
15#if defined(__i386__) || defined(__x86_64__)
16#include <cpuid.h>
17#endif
18#include <errno.h>
11fdf7f2 19#include <sched.h>
7c673cae
FG
20#include <signal.h>
21#include <stdio.h>
22#include <string.h>
7c673cae 23#include <sys/resource.h>
f67539c2 24#include <sys/time.h>
7c673cae
FG
25#include <unistd.h>
26#include <cstdlib>
7c673cae 27
f67539c2 28namespace ROCKSDB_NAMESPACE {
494da23a
TL
29
30// We want to give users opportunity to default all the mutexes to adaptive if
31// not specified otherwise. This enables a quick way to conduct various
32// performance related experiements.
33//
34// NB! Support for adaptive mutexes is turned on by definining
35// ROCKSDB_PTHREAD_ADAPTIVE_MUTEX during the compilation. If you use RocksDB
36// build environment then this happens automatically; otherwise it's up to the
37// consumer to define the identifier.
38#ifdef ROCKSDB_DEFAULT_TO_ADAPTIVE_MUTEX
39extern const bool kDefaultToAdaptiveMutex = true;
40#else
41extern const bool kDefaultToAdaptiveMutex = false;
42#endif
43
7c673cae
FG
44namespace port {
45
46static int PthreadCall(const char* label, int result) {
47 if (result != 0 && result != ETIMEDOUT) {
48 fprintf(stderr, "pthread %s: %s\n", label, strerror(result));
49 abort();
50 }
51 return result;
52}
53
54Mutex::Mutex(bool adaptive) {
11fdf7f2 55 (void) adaptive;
7c673cae
FG
56#ifdef ROCKSDB_PTHREAD_ADAPTIVE_MUTEX
57 if (!adaptive) {
58 PthreadCall("init mutex", pthread_mutex_init(&mu_, nullptr));
59 } else {
60 pthread_mutexattr_t mutex_attr;
61 PthreadCall("init mutex attr", pthread_mutexattr_init(&mutex_attr));
62 PthreadCall("set mutex attr",
63 pthread_mutexattr_settype(&mutex_attr,
64 PTHREAD_MUTEX_ADAPTIVE_NP));
65 PthreadCall("init mutex", pthread_mutex_init(&mu_, &mutex_attr));
66 PthreadCall("destroy mutex attr",
67 pthread_mutexattr_destroy(&mutex_attr));
68 }
69#else
70 PthreadCall("init mutex", pthread_mutex_init(&mu_, nullptr));
71#endif // ROCKSDB_PTHREAD_ADAPTIVE_MUTEX
72}
73
74Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); }
75
76void Mutex::Lock() {
77 PthreadCall("lock", pthread_mutex_lock(&mu_));
78#ifndef NDEBUG
79 locked_ = true;
80#endif
81}
82
83void Mutex::Unlock() {
84#ifndef NDEBUG
85 locked_ = false;
86#endif
87 PthreadCall("unlock", pthread_mutex_unlock(&mu_));
88}
89
90void Mutex::AssertHeld() {
91#ifndef NDEBUG
92 assert(locked_);
93#endif
94}
95
96CondVar::CondVar(Mutex* mu)
97 : mu_(mu) {
98 PthreadCall("init cv", pthread_cond_init(&cv_, nullptr));
99}
100
101CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); }
102
103void CondVar::Wait() {
104#ifndef NDEBUG
105 mu_->locked_ = false;
106#endif
107 PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_));
108#ifndef NDEBUG
109 mu_->locked_ = true;
110#endif
111}
112
113bool CondVar::TimedWait(uint64_t abs_time_us) {
114 struct timespec ts;
115 ts.tv_sec = static_cast<time_t>(abs_time_us / 1000000);
116 ts.tv_nsec = static_cast<suseconds_t>((abs_time_us % 1000000) * 1000);
117
118#ifndef NDEBUG
119 mu_->locked_ = false;
120#endif
121 int err = pthread_cond_timedwait(&cv_, &mu_->mu_, &ts);
122#ifndef NDEBUG
123 mu_->locked_ = true;
124#endif
125 if (err == ETIMEDOUT) {
126 return true;
127 }
128 if (err != 0) {
129 PthreadCall("timedwait", err);
130 }
131 return false;
132}
133
134void CondVar::Signal() {
135 PthreadCall("signal", pthread_cond_signal(&cv_));
136}
137
138void CondVar::SignalAll() {
139 PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
140}
141
142RWMutex::RWMutex() {
143 PthreadCall("init mutex", pthread_rwlock_init(&mu_, nullptr));
144}
145
146RWMutex::~RWMutex() { PthreadCall("destroy mutex", pthread_rwlock_destroy(&mu_)); }
147
148void RWMutex::ReadLock() { PthreadCall("read lock", pthread_rwlock_rdlock(&mu_)); }
149
150void RWMutex::WriteLock() { PthreadCall("write lock", pthread_rwlock_wrlock(&mu_)); }
151
152void RWMutex::ReadUnlock() { PthreadCall("read unlock", pthread_rwlock_unlock(&mu_)); }
153
154void RWMutex::WriteUnlock() { PthreadCall("write unlock", pthread_rwlock_unlock(&mu_)); }
155
156int PhysicalCoreID() {
11fdf7f2
TL
157#if defined(ROCKSDB_SCHED_GETCPU_PRESENT) && defined(__x86_64__) && \
158 (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 22))
159 // sched_getcpu uses VDSO getcpu() syscall since 2.22. I believe Linux offers VDSO
160 // support only on x86_64. This is the fastest/preferred method if available.
161 int cpuno = sched_getcpu();
162 if (cpuno < 0) {
163 return -1;
164 }
165 return cpuno;
166#elif defined(__x86_64__) || defined(__i386__)
167 // clang/gcc both provide cpuid.h, which defines __get_cpuid(), for x86_64 and i386.
7c673cae 168 unsigned eax, ebx = 0, ecx, edx;
11fdf7f2
TL
169 if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
170 return -1;
171 }
7c673cae
FG
172 return ebx >> 24;
173#else
11fdf7f2 174 // give up, the caller can generate a random number or something.
7c673cae
FG
175 return -1;
176#endif
177}
178
179void InitOnce(OnceType* once, void (*initializer)()) {
180 PthreadCall("once", pthread_once(once, initializer));
181}
182
183void Crash(const std::string& srcfile, int srcline) {
184 fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline);
185 fflush(stdout);
186 kill(getpid(), SIGTERM);
187}
188
189int GetMaxOpenFiles() {
190#if defined(RLIMIT_NOFILE)
191 struct rlimit no_files_limit;
192 if (getrlimit(RLIMIT_NOFILE, &no_files_limit) != 0) {
193 return -1;
194 }
195 // protect against overflow
f67539c2
TL
196 if (static_cast<uintmax_t>(no_files_limit.rlim_cur) >=
197 static_cast<uintmax_t>(std::numeric_limits<int>::max())) {
7c673cae
FG
198 return std::numeric_limits<int>::max();
199 }
200 return static_cast<int>(no_files_limit.rlim_cur);
201#endif
202 return -1;
203}
204
11fdf7f2
TL
205void *cacheline_aligned_alloc(size_t size) {
206#if __GNUC__ < 5 && defined(__SANITIZE_ADDRESS__)
207 return malloc(size);
208#elif ( _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || defined(__APPLE__))
209 void *m;
210 errno = posix_memalign(&m, CACHE_LINE_SIZE, size);
211 return errno ? nullptr : m;
212#else
213 return malloc(size);
214#endif
215}
216
217void cacheline_aligned_free(void *memblock) {
218 free(memblock);
219}
220
f67539c2
TL
221static size_t GetPageSize() {
222#if defined(OS_LINUX) || defined(_SC_PAGESIZE)
223 long v = sysconf(_SC_PAGESIZE);
224 if (v >= 1024) {
225 return static_cast<size_t>(v);
226 }
227#endif
228 // Default assume 4KB
229 return 4U * 1024U;
230}
231
232const size_t kPageSize = GetPageSize();
11fdf7f2 233
20effc67
TL
234void SetCpuPriority(ThreadId id, CpuPriority priority) {
235#ifdef OS_LINUX
236 sched_param param;
237 param.sched_priority = 0;
238 switch (priority) {
239 case CpuPriority::kHigh:
240 sched_setscheduler(id, SCHED_OTHER, &param);
241 setpriority(PRIO_PROCESS, id, -20);
242 break;
243 case CpuPriority::kNormal:
244 sched_setscheduler(id, SCHED_OTHER, &param);
245 setpriority(PRIO_PROCESS, id, 0);
246 break;
247 case CpuPriority::kLow:
248 sched_setscheduler(id, SCHED_OTHER, &param);
249 setpriority(PRIO_PROCESS, id, 19);
250 break;
251 case CpuPriority::kIdle:
252 sched_setscheduler(id, SCHED_IDLE, &param);
253 break;
254 default:
255 assert(false);
256 }
257#else
258 (void)id;
259 (void)priority;
260#endif
261}
262
7c673cae 263} // namespace port
f67539c2 264} // namespace ROCKSDB_NAMESPACE
20effc67
TL
265
266#endif