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