Skip to content

Commit a21e400

Browse files
WIP
1 parent a8aaadf commit a21e400

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

libc/src/stdlib/linux/vsdo_rng.h

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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/OSUtil/linux/vdso.h"
14+
#include "src/__support/OSUtil/syscall.h"
15+
#include "src/__support/blockstore.h"
16+
#include "src/__support/common.h"
17+
#include "src/__support/macros/config.h"
18+
#include "src/__support/mpmc_stack.h"
19+
#include "src/__support/threads/callonce.h"
20+
#include "src/__support/threads/linux/raw_mutex.h"
21+
#include "src/sys/auxv/getauxval.h"
22+
23+
namespace LIBC_NAMESPACE_DECL {
24+
namespace vsdo_rng {
25+
class GlobalState {
26+
public:
27+
struct VGetrandomOpaqueParams {
28+
unsigned int size_of_opaque_states;
29+
unsigned int mmap_prot;
30+
unsigned int mmap_flags;
31+
unsigned int reserved[13];
32+
};
33+
34+
private:
35+
struct Config {
36+
size_t page_size;
37+
size_t pages_per_alloc;
38+
size_t states_per_page;
39+
vdso::VDSOSymType<vdso::VDSOSym::GetRandom> getrandom;
40+
VGetrandomOpaqueParams params;
41+
};
42+
43+
MPMCStack<void *> free_list{};
44+
RawMutex page_queue_mutex{};
45+
BlockStore<void *, 16> allocations{};
46+
static CallOnceFlag config_flag;
47+
static Config config;
48+
49+
LIBC_INLINE static size_t guess_cpu_count() {
50+
char cpu_set[128] = {0};
51+
int res = LIBC_NAMESPACE::syscall_impl<int>(SYS_sched_getaffinity, 0,
52+
sizeof(cpu_set), cpu_set);
53+
if (res <= 0)
54+
return 1;
55+
56+
size_t count = 0;
57+
for (size_t i = 0; i < sizeof(cpu_set) / sizeof(unsigned long); ++i) {
58+
unsigned long *mask_ptr = reinterpret_cast<unsigned long *>(cpu_set);
59+
count += LIBC_NAMESPACE::cpp::popcount(mask_ptr[i]);
60+
}
61+
62+
return count > 0 ? count : 1;
63+
}
64+
65+
public:
66+
LIBC_INLINE constexpr GlobalState() {}
67+
68+
LIBC_INLINE static Config &get_config() {
69+
callonce(&config_flag, []() {
70+
config.getrandom =
71+
LIBC_NAMESPACE::vdso::TypedSymbol<vdso::VDSOSym::GetRandom>{};
72+
if (!config.getrandom)
73+
return;
74+
75+
// Call with special flag to get the desired configuration.
76+
int res = config.getrandom(
77+
/*buf=*/nullptr, /*count=*/0, /*flags=*/0,
78+
/*opaque_states=*/&config.params,
79+
/*size_of_opaque_states=*/~0);
80+
if (res != 0)
81+
return;
82+
83+
config.page_size = LIBC_NAMESPACE::getauxval(AT_PAGESZ);
84+
if (!config.page_size)
85+
return;
86+
87+
size_t cpu_count = guess_cpu_count();
88+
89+
config.states_per_page =
90+
config.page_size / config.params.size_of_opaque_states;
91+
92+
config.pages_per_alloc = cpu_count / config.states_per_page +
93+
(cpu_count % config.states_per_page != 0);
94+
});
95+
return config;
96+
}
97+
};
98+
class LocalState {};
99+
100+
LIBC_INLINE_VAR GlobalState::Config GlobalState::config{};
101+
LIBC_INLINE_VAR CallOnceFlag GlobalState::config_flag = 0;
102+
103+
} // namespace vsdo_rng
104+
} // namespace LIBC_NAMESPACE_DECL
105+
106+
#endif // LIBC_SRC_STDLIB_LINUX_VSDO_RNG_H

0 commit comments

Comments
 (0)