]>
git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/src/c++11/random.cc
3 // Copyright (C) 2012-2020 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
44 #include <cctype> // For std::isdigit.
46 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
49 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
50 # define USE_POSIX_FILE_IO
53 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
54 # include <sys/ioctl.h>
57 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
58 # include <linux/types.h>
61 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
62 # include <linux/random.h>
65 #ifdef _GLIBCXX_USE_CRT_RAND_S
69 #if defined USE_RDRAND || defined USE_RDSEED \
70 || defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
71 # pragma GCC poison _M_mt
73 // Use the mt19937 member of the union, as in previous GCC releases.
74 # define USE_MT19937 1
77 namespace std
_GLIBCXX_VISIBILITY(default)
83 __attribute__ ((target("rdrnd")))
86 unsigned int retries
= 100;
89 while (__builtin_ia32_rdrand32_step(&val
) == 0)
91 std::__throw_runtime_error(__N("random_device: rdrand failed"));
99 __attribute__ ((target("rdseed")))
102 unsigned int retries
= 100;
105 while (__builtin_ia32_rdseed_si_step(&val
) == 0)
108 std::__throw_runtime_error(__N("random_device: rdseed failed"));
109 __builtin_ia32_pause();
116 #ifdef _GLIBCXX_USE_CRT_RAND_S
118 __winxp_rand_s(void*)
121 if (::rand_s(&val
) != 0)
122 std::__throw_runtime_error(__N("random_device: rand_s failed"));
129 random_device::_M_init(const std::string
& token
)
132 // If no real random device is supported then use the mt19937 engine.
133 _M_init_pretr1(token
);
141 const char* fname
[[gnu::unused
]] = nullptr;
142 bool default_token
[[gnu::unused
]] = false;
144 enum { rand_s
, rdseed
, rdrand
, device_file
} which
;
146 if (token
== "default")
148 default_token
= true;
149 fname
= "/dev/urandom";
150 #if defined _GLIBCXX_USE_CRT_RAND_S
152 #elif defined USE_RDSEED
154 #elif defined USE_RDRAND
156 #elif defined _GLIBCXX_USE_DEV_RANDOM
159 # error "either define USE_MT19937 above or set the default device here"
163 else if (token
== "rdseed")
167 else if (token
== "rdrand" || token
== "rdrnd")
170 #ifdef _GLIBCXX_USE_CRT_RAND_S
171 else if (token
== "rand_s")
173 #endif // _GLIBCXX_USE_CRT_RAND_S
174 #ifdef _GLIBCXX_USE_DEV_RANDOM
175 else if (token
== "/dev/urandom" || token
== "/dev/random")
177 fname
= token
.c_str();
180 #endif // _GLIBCXX_USE_DEV_RANDOM
182 std::__throw_runtime_error(
183 __N("random_device::random_device(const std::string&):"
184 " unsupported token"));
188 #ifdef _GLIBCXX_USE_CRT_RAND_S
191 _M_func
= &__winxp_rand_s
;
194 #endif // _GLIBCXX_USE_CRT_RAND_S
198 unsigned int eax
, ebx
, ecx
, edx
;
199 // Check availability of cpuid and, for now at least, also the
200 // CPU signature for Intel and AMD.
201 if (__get_cpuid_max(0, &ebx
) > 0
202 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
204 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
205 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
206 if (ebx
& bit_RDSEED
)
208 _M_func
= &__x86_rdseed
;
212 // If rdseed was explicitly requested then we're done here.
215 // Otherwise fall through to try the next available option.
216 [[gnu::fallthrough
]];
222 unsigned int eax
, ebx
, ecx
, edx
;
223 // Check availability of cpuid and, for now at least, also the
224 // CPU signature for Intel and AMD.
225 if (__get_cpuid_max(0, &ebx
) > 0
226 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
228 // CPUID.01H:ECX.RDRAND[bit 30]
229 __cpuid(1, eax
, ebx
, ecx
, edx
);
232 _M_func
= &__x86_rdrand
;
236 // If rdrand was explicitly requested then we're done here.
239 // Otherwise fall through to try the next available option.
240 [[gnu::fallthrough
]];
243 #ifdef _GLIBCXX_USE_DEV_RANDOM
246 #ifdef USE_POSIX_FILE_IO
247 _M_fd
= ::open(fname
, O_RDONLY
);
250 // Set _M_file to non-null so that _M_fini() will do clean up.
254 #else // USE_POSIX_FILE_IO
255 _M_file
= static_cast<void*>(std::fopen(fname
, "rb"));
258 #endif // USE_POSIX_FILE_IO
259 [[gnu::fallthrough
]];
261 #endif // _GLIBCXX_USE_DEV_RANDOM
265 std::__throw_runtime_error(
266 __N("random_device::random_device(const std::string&):"
267 " device not available"));
268 #endif // USE_MT19937
271 // This function is called by _M_init for targets that use mt19937 for
272 // randomness, and by code compiled against old releases of libstdc++.
274 random_device::_M_init_pretr1(const std::string
& token
)
277 unsigned long seed
= 5489UL;
278 if (token
!= "default" && token
!= "mt19937")
280 const char* nptr
= token
.c_str();
282 seed
= std::strtoul(nptr
, &endptr
, 0);
283 if (*nptr
== '\0' || *endptr
!= '\0')
284 std::__throw_runtime_error(__N("random_device::_M_init_pretr1"
285 "(const std::string&)"));
289 // Convert old default token "mt19937" or numeric seed tokens to "default".
290 if (token
== "mt19937" || std::isdigit((unsigned char)token
[0]))
297 // Called by old ABI version of random_device::_M_init(const std::string&).
299 random_device::_M_init(const char* s
, size_t len
)
301 const std::string
token(s
, len
);
303 _M_init_pretr1(token
);
310 random_device::_M_fini()
312 // _M_file == nullptr means no resources to free.
316 #ifdef USE_POSIX_FILE_IO
320 std::fclose(static_cast<FILE*>(_M_file
));
325 random_device::result_type
326 random_device::_M_getval()
332 #if defined USE_RDRAND || defined USE_RDSEED || defined _GLIBCXX_USE_CRT_RAND_S
334 return _M_func(nullptr);
339 size_t n
= sizeof(result_type
);
340 #ifdef USE_POSIX_FILE_IO
343 const int e
= ::read(_M_fd
, p
, n
);
347 p
= static_cast<char*>(p
) + e
;
349 else if (e
!= -1 || errno
!= EINTR
)
350 __throw_runtime_error(__N("random_device could not be read"));
353 #else // USE_POSIX_FILE_IO
354 const size_t e
= std::fread(p
, n
, 1, static_cast<FILE*>(_M_file
));
356 __throw_runtime_error(__N("random_device could not be read"));
357 #endif // USE_POSIX_FILE_IO
360 #endif // USE_MT19937
363 // Only called by code compiled against old releases of libstdc++.
364 // Forward the call to _M_getval() and let it decide what to do.
365 random_device::result_type
366 random_device::_M_getval_pretr1()
367 { return _M_getval(); }
370 random_device::_M_getentropy() const noexcept
372 #if defined _GLIBCXX_USE_DEV_RANDOM \
373 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
377 #ifdef USE_POSIX_FILE_IO
378 const int fd
= _M_fd
;
380 const int fd
= ::fileno(static_cast<FILE*>(_M_file
));
386 if (::ioctl(fd
, RNDGETENTCNT
, &ent
) < 0)
392 const int max
= sizeof(result_type
) * __CHAR_BIT__
;
396 return static_cast<double>(ent
);
399 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
403 template class mersenne_twister_engine
<
409 0xefc60000UL
, 18, 1812433253UL>;
410 #endif // USE_MT19937
412 #endif // _GLIBCXX_USE_C99_STDINT_TR1