Skip to content

Commit d050054

Browse files
WIP
1 parent a8aaadf commit d050054

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed

libc/src/stdlib/linux/vsdo_rng.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//===-- vDSO based RNG ----------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LIBC_SRC_STDLIB_LINUX_VSDO_RNG_H
10+
#define LIBC_SRC_STDLIB_LINUX_VSDO_RNG_H
11+
12+
#include "src/__support/CPP/bit.h"
13+
#include "src/__support/CPP/mutex.h"
14+
#include "src/__support/OSUtil/linux/vdso.h"
15+
#include "src/__support/OSUtil/syscall.h"
16+
#include "src/__support/blockstore.h"
17+
#include "src/__support/common.h"
18+
#include "src/__support/macros/config.h"
19+
#include "src/__support/mpmc_stack.h"
20+
#include "src/__support/threads/callonce.h"
21+
#include "src/__support/threads/linux/raw_mutex.h"
22+
#include "src/sys/auxv/getauxval.h"
23+
24+
namespace LIBC_NAMESPACE_DECL {
25+
namespace vsdo_rng {
26+
class GlobalState {
27+
public:
28+
struct VGetrandomOpaqueParams {
29+
unsigned int size_of_opaque_states;
30+
unsigned int mmap_prot;
31+
unsigned int mmap_flags;
32+
unsigned int reserved[13];
33+
};
34+
35+
private:
36+
struct Config {
37+
size_t page_size;
38+
size_t pages_per_alloc;
39+
size_t states_per_page;
40+
vdso::VDSOSymType<vdso::VDSOSym::GetRandom> getrandom;
41+
VGetrandomOpaqueParams params;
42+
};
43+
44+
// A lock-free stack of free opaque states.
45+
MPMCStack<void *> free_list{};
46+
// A mutex protecting the allocation of new pages.
47+
RawMutex allocation_mutex{};
48+
// A block store of allocated pages.
49+
BlockStore<void *, 16> allocations{};
50+
51+
// Shared global configuration.
52+
static CallOnceFlag config_flag;
53+
static Config config;
54+
55+
// We grow the states by the number of CPUs. This function uses
56+
// SYS_sched_getaffinity to get the number of CPUs.
57+
LIBC_INLINE static size_t cpu_count();
58+
59+
// Grow available states. This function can fail if the system is out of
60+
// memory.
61+
LIBC_INLINE bool grow();
62+
63+
public:
64+
LIBC_INLINE constexpr GlobalState() {}
65+
LIBC_INLINE static Config &get_config();
66+
LIBC_INLINE ~GlobalState() {}
67+
};
68+
69+
class LocalState {};
70+
71+
LIBC_INLINE_VAR GlobalState::Config GlobalState::config{};
72+
LIBC_INLINE_VAR CallOnceFlag GlobalState::config_flag = 0;
73+
74+
LIBC_INLINE size_t GlobalState::cpu_count() {
75+
char cpu_set[128] = {0};
76+
int res = LIBC_NAMESPACE::syscall_impl<int>(SYS_sched_getaffinity, 0,
77+
sizeof(cpu_set), cpu_set);
78+
if (res <= 0)
79+
return 1;
80+
81+
size_t count = 0;
82+
for (size_t i = 0; i < sizeof(cpu_set) / sizeof(unsigned long); ++i) {
83+
unsigned long *mask_ptr = reinterpret_cast<unsigned long *>(cpu_set);
84+
count += LIBC_NAMESPACE::cpp::popcount(mask_ptr[i]);
85+
}
86+
87+
return count > 0 ? count : 1;
88+
}
89+
90+
LIBC_INLINE GlobalState::Config &GlobalState::get_config() {
91+
callonce(&config_flag, []() {
92+
config.getrandom =
93+
LIBC_NAMESPACE::vdso::TypedSymbol<vdso::VDSOSym::GetRandom>{};
94+
if (!config.getrandom)
95+
return;
96+
97+
// Call with special flag to get the desired configuration.
98+
int res = config.getrandom(
99+
/*buf=*/nullptr, /*count=*/0, /*flags=*/0,
100+
/*opaque_states=*/&config.params,
101+
/*size_of_opaque_states=*/~0);
102+
if (res != 0)
103+
return;
104+
105+
config.page_size = LIBC_NAMESPACE::getauxval(AT_PAGESZ);
106+
if (!config.page_size)
107+
return;
108+
109+
size_t count = cpu_count();
110+
111+
config.states_per_page =
112+
config.page_size / config.params.size_of_opaque_states;
113+
114+
config.pages_per_alloc =
115+
count / config.states_per_page + (count % config.states_per_page != 0);
116+
});
117+
return config;
118+
}
119+
120+
LIBC_INLINE bool GlobalState::grow() {
121+
// reserve a slot for the new page.
122+
if (!allocations.push_back(nullptr))
123+
return false;
124+
}
125+
126+
} // namespace vsdo_rng
127+
} // namespace LIBC_NAMESPACE_DECL
128+
129+
#endif // LIBC_SRC_STDLIB_LINUX_VSDO_RNG_H

0 commit comments

Comments
 (0)