]>
Commit | Line | Data |
---|---|---|
a8c3f4c9 UD |
1 | // random -*- C++ -*- |
2 | ||
a5544970 | 3 | // Copyright (C) 2012-2019 Free Software Foundation, Inc. |
a8c3f4c9 UD |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
34a2b755 | 25 | #define _GLIBCXX_USE_CXX11_ABI 1 |
a8c3f4c9 UD |
26 | #include <random> |
27 | ||
645708ab JW |
28 | #ifdef _GLIBCXX_USE_C99_STDINT_TR1 |
29 | ||
a8c3f4c9 UD |
30 | #if defined __i386__ || defined __x86_64__ |
31 | # include <cpuid.h> | |
32 | #endif | |
33 | ||
0b546684 | 34 | #include <cerrno> |
821f6f1b PC |
35 | #include <cstdio> |
36 | ||
94e7477f PC |
37 | #ifdef _GLIBCXX_HAVE_UNISTD_H |
38 | # include <unistd.h> | |
39 | #endif | |
a8c3f4c9 | 40 | |
78aa76df XR |
41 | #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H |
42 | # include <sys/ioctl.h> | |
43 | #endif | |
44 | ||
dac867c9 UB |
45 | #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H |
46 | # include <linux/types.h> | |
47 | #endif | |
48 | ||
78aa76df XR |
49 | #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H |
50 | # include <linux/random.h> | |
51 | #endif | |
52 | ||
a8c3f4c9 UD |
53 | namespace std _GLIBCXX_VISIBILITY(default) |
54 | { | |
a8c3f4c9 UD |
55 | namespace |
56 | { | |
57 | static unsigned long | |
58 | _M_strtoul(const std::string& __str) | |
59 | { | |
60 | unsigned long __ret = 5489UL; | |
61 | if (__str != "mt19937") | |
62 | { | |
63 | const char* __nptr = __str.c_str(); | |
64 | char* __endptr; | |
65 | __ret = std::strtoul(__nptr, &__endptr, 0); | |
66 | if (*__nptr == '\0' || *__endptr != '\0') | |
67 | std::__throw_runtime_error(__N("random_device::_M_strtoul" | |
68 | "(const std::string&)")); | |
69 | } | |
70 | return __ret; | |
71 | } | |
72 | ||
3ca6351d | 73 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
a8c3f4c9 UD |
74 | unsigned int |
75 | __attribute__ ((target("rdrnd"))) | |
76 | __x86_rdrand(void) | |
77 | { | |
78 | unsigned int retries = 100; | |
79 | unsigned int val; | |
80 | ||
81 | while (__builtin_ia32_rdrand32_step(&val) == 0) | |
82 | if (--retries == 0) | |
83 | std::__throw_runtime_error(__N("random_device::__x86_rdrand(void)")); | |
84 | ||
85 | return val; | |
86 | } | |
87 | #endif | |
88 | } | |
89 | ||
a8c3f4c9 UD |
90 | void |
91 | random_device::_M_init(const std::string& token) | |
92 | { | |
93 | const char *fname = token.c_str(); | |
94 | ||
95 | if (token == "default") | |
96 | { | |
3ca6351d | 97 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
a8c3f4c9 | 98 | unsigned int eax, ebx, ecx, edx; |
efc622f8 UD |
99 | // Check availability of cpuid and, for now at least, also the |
100 | // CPU signature for Intel's | |
ef64d158 | 101 | if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_INTEL_ebx) |
a8c3f4c9 UD |
102 | { |
103 | __cpuid(1, eax, ebx, ecx, edx); | |
104 | if (ecx & bit_RDRND) | |
105 | { | |
106 | _M_file = nullptr; | |
107 | return; | |
108 | } | |
109 | } | |
110 | #endif | |
111 | ||
112 | fname = "/dev/urandom"; | |
113 | } | |
114 | else if (token != "/dev/urandom" && token != "/dev/random") | |
115 | fail: | |
116 | std::__throw_runtime_error(__N("random_device::" | |
117 | "random_device(const std::string&)")); | |
118 | ||
821f6f1b PC |
119 | _M_file = static_cast<void*>(std::fopen(fname, "rb")); |
120 | if (!_M_file) | |
a8c3f4c9 UD |
121 | goto fail; |
122 | } | |
123 | ||
124 | void | |
125 | random_device::_M_init_pretr1(const std::string& token) | |
a8c3f4c9 UD |
126 | { |
127 | _M_mt.seed(_M_strtoul(token)); | |
128 | } | |
129 | ||
130 | void | |
131 | random_device::_M_fini() | |
132 | { | |
133 | if (_M_file) | |
821f6f1b | 134 | std::fclose(static_cast<FILE*>(_M_file)); |
a8c3f4c9 UD |
135 | } |
136 | ||
137 | random_device::result_type | |
138 | random_device::_M_getval() | |
139 | { | |
3ca6351d | 140 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
821f6f1b | 141 | if (!_M_file) |
a8c3f4c9 UD |
142 | return __x86_rdrand(); |
143 | #endif | |
144 | ||
145 | result_type __ret; | |
a2b4d73d JW |
146 | void* p = &__ret; |
147 | size_t n = sizeof(result_type); | |
94e7477f | 148 | #ifdef _GLIBCXX_HAVE_UNISTD_H |
a2b4d73d JW |
149 | do |
150 | { | |
151 | const int e = read(fileno(static_cast<FILE*>(_M_file)), p, n); | |
152 | if (e > 0) | |
153 | { | |
154 | n -= e; | |
155 | p = static_cast<char*>(p) + e; | |
156 | } | |
157 | else if (e != -1 || errno != EINTR) | |
158 | __throw_runtime_error(__N("random_device could not be read")); | |
159 | } | |
160 | while (n > 0); | |
94e7477f | 161 | #else |
a2b4d73d JW |
162 | const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file)); |
163 | if (e != 1) | |
164 | __throw_runtime_error(__N("random_device could not be read")); | |
94e7477f | 165 | #endif |
42b6aad9 | 166 | |
a8c3f4c9 UD |
167 | return __ret; |
168 | } | |
169 | ||
170 | random_device::result_type | |
171 | random_device::_M_getval_pretr1() | |
172 | { | |
173 | return _M_mt(); | |
174 | } | |
175 | ||
78aa76df XR |
176 | double |
177 | random_device::_M_getentropy() const noexcept | |
178 | { | |
179 | #if defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT | |
180 | if (!_M_file) | |
181 | return 0.0; | |
182 | ||
183 | const int fd = fileno(static_cast<FILE*>(_M_file)); | |
184 | if (fd < 0) | |
185 | return 0.0; | |
186 | ||
187 | int ent; | |
188 | if (ioctl(fd, RNDGETENTCNT, &ent) < 0) | |
189 | return 0.0; | |
190 | ||
191 | if (ent < 0) | |
192 | return 0.0; | |
193 | ||
b6784361 JW |
194 | const int max = sizeof(result_type) * __CHAR_BIT__; |
195 | if (ent > max) | |
196 | ent = max; | |
78aa76df XR |
197 | |
198 | return static_cast<double>(ent); | |
199 | #else | |
200 | return 0.0; | |
201 | #endif | |
202 | } | |
203 | ||
a8c3f4c9 UD |
204 | template class mersenne_twister_engine< |
205 | uint_fast32_t, | |
206 | 32, 624, 397, 31, | |
207 | 0x9908b0dfUL, 11, | |
208 | 0xffffffffUL, 7, | |
209 | 0x9d2c5680UL, 15, | |
210 | 0xefc60000UL, 18, 1812433253UL>; | |
a8c3f4c9 | 211 | } |
645708ab | 212 | #endif |