]>
git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/src/c++11/random.cc
3 // Copyright (C) 2012-2019 Free Software Foundation, Inc.
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)
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.
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.
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/>.
25 #define _GLIBCXX_USE_CXX11_ABI 1
26 #define _CRT_RAND_S // define this before including <stdlib.h> to get rand_s
30 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
32 #if defined __i386__ || defined __x86_64__
34 # ifdef _GLIBCXX_X86_RDRAND
37 # ifdef _GLIBCXX_X86_RDSEED
45 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
48 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
49 # define USE_POSIX_FILE_IO
52 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
53 # include <sys/ioctl.h>
56 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
57 # include <linux/types.h>
60 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
61 # include <linux/random.h>
64 #ifdef _GLIBCXX_USE_CRT_RAND_S
68 #if defined USE_RDRAND || defined USE_RDSEED \
69 || defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
70 # pragma GCC poison _M_mt
72 // Use the mt19937 member of the union, as in previous GCC releases.
73 # define USE_MT19937 1
76 namespace std
_GLIBCXX_VISIBILITY(default)
82 __attribute__ ((target("rdrnd")))
85 unsigned int retries
= 100;
88 while (__builtin_ia32_rdrand32_step(&val
) == 0)
90 std::__throw_runtime_error(__N("random_device: rdrand failed"));
98 __attribute__ ((target("rdseed")))
101 unsigned int retries
= 100;
104 while (__builtin_ia32_rdseed_si_step(&val
) == 0)
107 std::__throw_runtime_error(__N("random_device: rdseed failed"));
108 __builtin_ia32_pause();
115 #ifdef _GLIBCXX_USE_CRT_RAND_S
117 __winxp_rand_s(void*)
120 if (::rand_s(&val
) != 0)
121 std::__throw_runtime_error(__N("random_device: rand_s failed"));
128 random_device::_M_init(const std::string
& token
)
131 // If no real random device is supported then use the mt19937 engine.
132 _M_init_pretr1(token
);
140 const char* fname
[[gnu::unused
]] = nullptr;
141 bool default_token
[[gnu::unused
]] = false;
143 enum { rand_s
, rdseed
, rdrand
, device_file
} which
;
145 if (token
== "default")
147 default_token
= true;
148 fname
= "/dev/urandom";
149 #if defined _GLIBCXX_USE_CRT_RAND_S
151 #elif defined USE_RDSEED
153 #elif defined USE_RDRAND
155 #elif defined _GLIBCXX_USE_DEV_RANDOM
158 # error "either define USE_MT19937 above or set the default device here"
162 else if (token
== "rdseed")
166 else if (token
== "rdrand" || token
== "rdrnd")
169 #ifdef _GLIBCXX_USE_CRT_RAND_S
170 else if (token
== "rand_s")
172 #endif // _GLIBCXX_USE_CRT_RAND_S
173 #ifdef _GLIBCXX_USE_DEV_RANDOM
174 else if (token
== "/dev/urandom" || token
== "/dev/random")
176 fname
= token
.c_str();
179 #endif // _GLIBCXX_USE_DEV_RANDOM
181 std::__throw_runtime_error(
182 __N("random_device::random_device(const std::string&):"
183 " unsupported token"));
187 #ifdef _GLIBCXX_USE_CRT_RAND_S
190 _M_func
= &__winxp_rand_s
;
193 #endif // _GLIBCXX_USE_CRT_RAND_S
197 unsigned int eax
, ebx
, ecx
, edx
;
198 // Check availability of cpuid and, for now at least, also the
199 // CPU signature for Intel and AMD.
200 if (__get_cpuid_max(0, &ebx
) > 0
201 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
203 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
204 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
205 if (ebx
& bit_RDSEED
)
207 _M_func
= &__x86_rdseed
;
211 // If rdseed was explicitly requested then we're done here.
214 // Otherwise fall through to try the next available option.
215 [[gnu::fallthrough
]];
221 unsigned int eax
, ebx
, ecx
, edx
;
222 // Check availability of cpuid and, for now at least, also the
223 // CPU signature for Intel and AMD.
224 if (__get_cpuid_max(0, &ebx
) > 0
225 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
227 // CPUID.01H:ECX.RDRAND[bit 30]
228 __cpuid(1, eax
, ebx
, ecx
, edx
);
231 _M_func
= &__x86_rdrand
;
235 // If rdrand was explicitly requested then we're done here.
238 // Otherwise fall through to try the next available option.
239 [[gnu::fallthrough
]];
242 #ifdef _GLIBCXX_USE_DEV_RANDOM
245 #ifdef USE_POSIX_FILE_IO
246 _M_fd
= ::open(fname
, O_RDONLY
);
249 // Set _M_file to non-null so that _M_fini() will do clean up.
253 #else // USE_POSIX_FILE_IO
254 _M_file
= static_cast<void*>(std::fopen(fname
, "rb"));
257 #endif // USE_POSIX_FILE_IO
258 [[gnu::fallthrough
]];
260 #endif // _GLIBCXX_USE_DEV_RANDOM
264 std::__throw_runtime_error(
265 __N("random_device::random_device(const std::string&):"
266 " device not available"));
267 #endif // USE_MT19937
270 // This function is called by _M_init for targets that use mt19937 for
271 // randomness, and by code compiled against old releases of libstdc++.
273 random_device::_M_init_pretr1(const std::string
& token
)
276 unsigned long seed
= 5489UL;
277 if (token
!= "default" && token
!= "mt19937")
279 const char* nptr
= token
.c_str();
281 seed
= std::strtoul(nptr
, &endptr
, 0);
282 if (*nptr
== '\0' || *endptr
!= '\0')
283 std::__throw_runtime_error(__N("random_device::_M_init_pretr1"
284 "(const std::string&)"));
288 // Convert old default token "mt19937" or numeric seed tokens to "default".
289 if (token
== "mt19937" || isdigit((unsigned char)token
[0]))
296 // Called by old ABI version of random_device::_M_init(const std::string&).
298 random_device::_M_init(const char* s
, size_t len
)
300 const std::string
token(s
, len
);
302 _M_init_pretr1(token
);
309 random_device::_M_fini()
311 // _M_file == nullptr means no resources to free.
315 #ifdef USE_POSIX_FILE_IO
319 std::fclose(static_cast<FILE*>(_M_file
));
324 random_device::result_type
325 random_device::_M_getval()
331 #if defined USE_RDRAND || defined USE_RDSEED || defined _GLIBCXX_USE_CRT_RAND_S
333 return _M_func(nullptr);
338 size_t n
= sizeof(result_type
);
339 #ifdef USE_POSIX_FILE_IO
342 const int e
= ::read(_M_fd
, p
, n
);
346 p
= static_cast<char*>(p
) + e
;
348 else if (e
!= -1 || errno
!= EINTR
)
349 __throw_runtime_error(__N("random_device could not be read"));
352 #else // USE_POSIX_FILE_IO
353 const size_t e
= std::fread(p
, n
, 1, static_cast<FILE*>(_M_file
));
355 __throw_runtime_error(__N("random_device could not be read"));
356 #endif // USE_POSIX_FILE_IO
359 #endif // USE_MT19937
362 // Only called by code compiled against old releases of libstdc++.
363 // Forward the call to _M_getval() and let it decide what to do.
364 random_device::result_type
365 random_device::_M_getval_pretr1()
366 { return _M_getval(); }
369 random_device::_M_getentropy() const noexcept
371 #if defined _GLIBCXX_USE_DEV_RANDOM \
372 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
376 #ifdef USE_POSIX_FILE_IO
377 const int fd
= _M_fd
;
379 const int fd
= ::fileno(static_cast<FILE*>(_M_file
));
385 if (::ioctl(fd
, RNDGETENTCNT
, &ent
) < 0)
391 const int max
= sizeof(result_type
) * __CHAR_BIT__
;
395 return static_cast<double>(ent
);
398 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
402 template class mersenne_twister_engine
<
408 0xefc60000UL
, 18, 1812433253UL>;
409 #endif // USE_MT19937
411 #endif // _GLIBCXX_USE_C99_STDINT_TR1