+2020-05-19 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/94087
+ * src/c++11/random.cc (__x86_rdseed): Allow fallback function to be
+ passed in.
+ (__x86_rdseed_rdrand): New function that uses rdseed with rdrand
+ fallback.
+ (random_device::_M_init): Use __x86_rdseed_rdrand when both
+ instructions are available.
+ * testsuite/26_numerics/random/random_device/94087.cc: New test.
+
2020-05-19 Patrick Palka <ppalka@redhat.com>
PR c++/66439
#if USE_RDSEED
unsigned int
__attribute__ ((target("rdseed")))
- __x86_rdseed(void*)
+ __x86_rdseed(void* fallback)
{
unsigned int retries = 100;
unsigned int val;
while (__builtin_ia32_rdseed_si_step(&val) == 0)
{
if (--retries == 0)
- std::__throw_runtime_error(__N("random_device: rdseed failed"));
+ {
+ if (auto f = reinterpret_cast<unsigned int(*)(void*)>(fallback))
+ return f(nullptr);
+ std::__throw_runtime_error(__N("random_device: rdseed failed"));
+ }
__builtin_ia32_pause();
}
return val;
}
+
+#if USE_RDRAND
+ unsigned int
+ __attribute__ ((target("rdseed,rdrnd")))
+ __x86_rdseed_rdrand(void*)
+ {
+ return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand));
+ }
+#endif
#endif
#ifdef _GLIBCXX_USE_CRT_RAND_S
__cpuid_count(7, 0, eax, ebx, ecx, edx);
if (ebx & bit_RDSEED)
{
+#ifdef USE_RDRAND
+ // CPUID.01H:ECX.RDRAND[bit 30]
+ __cpuid(1, eax, ebx, ecx, edx);
+ if (ecx & bit_RDRND)
+ {
+ _M_func = &__x86_rdseed_rdrand;
+ return;
+ }
+#endif
_M_func = &__x86_rdseed;
return;
}
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+// { dg-options "-pthread" }
+// { dg-require-effective-target c++11 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <random>
+#include <memory>
+#include <thread>
+#include <cstdio>
+
+bool
+random_device_available(const char* token) noexcept
+{
+ try {
+ std::random_device dev(token);
+ return true;
+ } catch (...) {
+ std::printf("random_device(\"%s\") not available\n", token);
+ return false;
+ }
+}
+
+void read_random_device(const char* token, int iterations)
+{
+ std::random_device dev(token);
+ for (int i = 0; i != iterations; ++i)
+ (void) dev();
+}
+
+int main() {
+ std::thread workers[8];
+
+ // N.B. don't test /dev/random as it might block, and /dev/urandom
+ // "can incur an appreciable delay when requesting large amounts of data".
+ for (const char* dev : { "default", "rdrand", "rdseed", "rand_s" })
+ {
+ if (random_device_available(dev))
+ {
+ for (auto& w : workers)
+ w = std::thread{read_random_device, dev, 1000};
+ for (auto& w : workers)
+ w.join();
+ }
+ }
+}