Coverage Report

Created: 2025-07-23 07:17

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