]>
Commit | Line | Data |
---|---|---|
6a4e41f8 | 1 | // random -*- C++ -*- |
2 | ||
f1717362 | 3 | // Copyright (C) 2012-2016 Free Software Foundation, Inc. |
6a4e41f8 | 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 | ||
63f54259 | 25 | #define _GLIBCXX_USE_CXX11_ABI 1 |
6a4e41f8 | 26 | #include <random> |
27 | ||
236745b6 | 28 | #ifdef _GLIBCXX_USE_C99_STDINT_TR1 |
29 | ||
6a4e41f8 | 30 | #if defined __i386__ || defined __x86_64__ |
31 | # include <cpuid.h> | |
32 | #endif | |
33 | ||
fd16f36d | 34 | #include <cerrno> |
05427669 | 35 | #include <cstdio> |
36 | ||
9b9e702b | 37 | #ifdef _GLIBCXX_HAVE_UNISTD_H |
38 | # include <unistd.h> | |
39 | #endif | |
6a4e41f8 | 40 | |
41 | namespace std _GLIBCXX_VISIBILITY(default) | |
42 | { | |
6a4e41f8 | 43 | namespace |
44 | { | |
45 | static unsigned long | |
46 | _M_strtoul(const std::string& __str) | |
47 | { | |
48 | unsigned long __ret = 5489UL; | |
49 | if (__str != "mt19937") | |
50 | { | |
51 | const char* __nptr = __str.c_str(); | |
52 | char* __endptr; | |
53 | __ret = std::strtoul(__nptr, &__endptr, 0); | |
54 | if (*__nptr == '\0' || *__endptr != '\0') | |
55 | std::__throw_runtime_error(__N("random_device::_M_strtoul" | |
56 | "(const std::string&)")); | |
57 | } | |
58 | return __ret; | |
59 | } | |
60 | ||
bdbf421c | 61 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
6a4e41f8 | 62 | unsigned int |
63 | __attribute__ ((target("rdrnd"))) | |
64 | __x86_rdrand(void) | |
65 | { | |
66 | unsigned int retries = 100; | |
67 | unsigned int val; | |
68 | ||
69 | while (__builtin_ia32_rdrand32_step(&val) == 0) | |
70 | if (--retries == 0) | |
71 | std::__throw_runtime_error(__N("random_device::__x86_rdrand(void)")); | |
72 | ||
73 | return val; | |
74 | } | |
75 | #endif | |
76 | } | |
77 | ||
6a4e41f8 | 78 | void |
79 | random_device::_M_init(const std::string& token) | |
80 | { | |
81 | const char *fname = token.c_str(); | |
82 | ||
83 | if (token == "default") | |
84 | { | |
bdbf421c | 85 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
6a4e41f8 | 86 | unsigned int eax, ebx, ecx, edx; |
45d7e715 | 87 | // Check availability of cpuid and, for now at least, also the |
88 | // CPU signature for Intel's | |
865812bf | 89 | if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_INTEL_ebx) |
6a4e41f8 | 90 | { |
91 | __cpuid(1, eax, ebx, ecx, edx); | |
92 | if (ecx & bit_RDRND) | |
93 | { | |
94 | _M_file = nullptr; | |
95 | return; | |
96 | } | |
97 | } | |
98 | #endif | |
99 | ||
100 | fname = "/dev/urandom"; | |
101 | } | |
102 | else if (token != "/dev/urandom" && token != "/dev/random") | |
103 | fail: | |
104 | std::__throw_runtime_error(__N("random_device::" | |
105 | "random_device(const std::string&)")); | |
106 | ||
05427669 | 107 | _M_file = static_cast<void*>(std::fopen(fname, "rb")); |
108 | if (!_M_file) | |
6a4e41f8 | 109 | goto fail; |
110 | } | |
111 | ||
112 | void | |
113 | random_device::_M_init_pretr1(const std::string& token) | |
6a4e41f8 | 114 | { |
115 | _M_mt.seed(_M_strtoul(token)); | |
116 | } | |
117 | ||
118 | void | |
119 | random_device::_M_fini() | |
120 | { | |
121 | if (_M_file) | |
05427669 | 122 | std::fclose(static_cast<FILE*>(_M_file)); |
6a4e41f8 | 123 | } |
124 | ||
125 | random_device::result_type | |
126 | random_device::_M_getval() | |
127 | { | |
bdbf421c | 128 | #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND |
05427669 | 129 | if (!_M_file) |
6a4e41f8 | 130 | return __x86_rdrand(); |
131 | #endif | |
132 | ||
133 | result_type __ret; | |
8efb09c4 | 134 | void* p = &__ret; |
135 | size_t n = sizeof(result_type); | |
9b9e702b | 136 | #ifdef _GLIBCXX_HAVE_UNISTD_H |
8efb09c4 | 137 | do |
138 | { | |
139 | const int e = read(fileno(static_cast<FILE*>(_M_file)), p, n); | |
140 | if (e > 0) | |
141 | { | |
142 | n -= e; | |
143 | p = static_cast<char*>(p) + e; | |
144 | } | |
145 | else if (e != -1 || errno != EINTR) | |
146 | __throw_runtime_error(__N("random_device could not be read")); | |
147 | } | |
148 | while (n > 0); | |
9b9e702b | 149 | #else |
8efb09c4 | 150 | const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file)); |
151 | if (e != 1) | |
152 | __throw_runtime_error(__N("random_device could not be read")); | |
9b9e702b | 153 | #endif |
84bb4e67 | 154 | |
6a4e41f8 | 155 | return __ret; |
156 | } | |
157 | ||
158 | random_device::result_type | |
159 | random_device::_M_getval_pretr1() | |
160 | { | |
161 | return _M_mt(); | |
162 | } | |
163 | ||
164 | template class mersenne_twister_engine< | |
165 | uint_fast32_t, | |
166 | 32, 624, 397, 31, | |
167 | 0x9908b0dfUL, 11, | |
168 | 0xffffffffUL, 7, | |
169 | 0x9d2c5680UL, 15, | |
170 | 0xefc60000UL, 18, 1812433253UL>; | |
6a4e41f8 | 171 | } |
236745b6 | 172 | #endif |