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