summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qrandom.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-04-13 17:50:05 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-06-12 06:14:37 +0000
commit030782e1a8c44c6be2a95c88d5a4a3a37b3b6173 (patch)
treef5508927660b4728c67a4cd7dca91e2525567c81 /src/corelib/global/qrandom.cpp
parent593f022515da8a834b358b5a57779afff619b3e7 (diff)
Move qrand() & qsrand() to qrandom.cpp
Now that we have the file, may as well consolidate Change-Id: Icd0e0d4b27cb4e5eb892fffd14b51d3e701c6a94 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/global/qrandom.cpp')
-rw-r--r--src/corelib/global/qrandom.cpp141
1 files changed, 140 insertions, 1 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index 74fdf9f318..573e762fc9 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -42,6 +42,7 @@
#include "qrandom.h"
#include "qrandom_p.h"
+#include <qthreadstorage.h>
#if QT_HAS_INCLUDE(<random>)
# include <random>
@@ -62,6 +63,10 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
}
#endif
+#if defined(Q_OS_ANDROID)
+# include <private/qjni_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
namespace {
@@ -231,7 +236,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
quint32 *ptr = reinterpret_cast<quint32 *>(buffer);
quint32 * const end = reinterpret_cast<quint32 *>(bufferEnd);
-#if defined(Q_COMPILER_THREAD_LOCAL)
+#if defined(Q_COMPILER_THREAD_LOCAL) && !defined(QT_BOOTSTRAPPED)
if (SystemRandom::EfficientBufferFill && (end - ptr) < ThreadState::BufferCount
&& uint(qt_randomdevice_control) == 0) {
thread_local ThreadState state;
@@ -724,4 +729,138 @@ void QRandomGenerator::fillRange_helper(void *buffer, void *bufferEnd)
fill(buffer, bufferEnd);
}
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
+
+# if defined(Q_OS_INTEGRITY) && defined(__GHS_VERSION_NUMBER) && (__GHS_VERSION_NUMBER < 500)
+// older versions of INTEGRITY used a long instead of a uint for the seed.
+typedef long SeedStorageType;
+# else
+typedef uint SeedStorageType;
+# endif
+
+typedef QThreadStorage<SeedStorageType *> SeedStorage;
+Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value
+
+#elif defined(Q_OS_ANDROID)
+typedef QThreadStorage<QJNIObjectPrivate> AndroidRandomStorage;
+Q_GLOBAL_STATIC(AndroidRandomStorage, randomTLS)
+#endif
+
+/*!
+ \relates <QtGlobal>
+ \since 4.2
+
+ Thread-safe version of the standard C++ \c srand() function.
+
+ Sets the argument \a seed to be used to generate a new random number sequence of
+ pseudo random integers to be returned by qrand().
+
+ The sequence of random numbers generated is deterministic per thread. For example,
+ if two threads call qsrand(1) and subsequently call qrand(), the threads will get
+ the same random number sequence.
+
+ \sa qrand(), QRandomGenerator
+*/
+void qsrand(uint seed)
+{
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
+ SeedStorage *seedStorage = randTLS();
+ if (seedStorage) {
+ SeedStorageType *pseed = seedStorage->localData();
+ if (!pseed)
+ seedStorage->setLocalData(pseed = new SeedStorageType);
+ *pseed = seed;
+ } else {
+ //global static seed storage should always exist,
+ //except after being deleted by QGlobalStaticDeleter.
+ //But since it still can be called from destructor of another
+ //global static object, fallback to srand(seed)
+ srand(seed);
+ }
+#elif defined(Q_OS_ANDROID)
+ if (randomTLS->hasLocalData()) {
+ randomTLS->localData().callMethod<void>("setSeed", "(J)V", jlong(seed));
+ return;
+ }
+
+ QJNIObjectPrivate random("java/util/Random",
+ "(J)V",
+ jlong(seed));
+ if (!random.isValid()) {
+ srand(seed);
+ return;
+ }
+
+ randomTLS->setLocalData(random);
+#else
+ // On Windows srand() and rand() already use Thread-Local-Storage
+ // to store the seed between calls
+ // this is also valid for QT_NO_THREAD
+ srand(seed);
+#endif
+}
+
+/*!
+ \relates <QtGlobal>
+ \since 4.2
+
+ Thread-safe version of the standard C++ \c rand() function.
+
+ Returns a value between 0 and \c RAND_MAX (defined in \c <cstdlib> and
+ \c <stdlib.h>), the next number in the current sequence of pseudo-random
+ integers.
+
+ Use \c qsrand() to initialize the pseudo-random number generator with a
+ seed value. Seeding must be performed at least once on each thread. If that
+ step is skipped, then the sequence will be pre-seeded with a constant
+ value.
+
+ \sa qsrand(), QRandomGenerator
+*/
+int qrand()
+{
+#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
+ SeedStorage *seedStorage = randTLS();
+ if (seedStorage) {
+ SeedStorageType *pseed = seedStorage->localData();
+ if (!pseed) {
+ seedStorage->setLocalData(pseed = new SeedStorageType);
+ *pseed = 1;
+ }
+ return rand_r(pseed);
+ } else {
+ //global static seed storage should always exist,
+ //except after being deleted by QGlobalStaticDeleter.
+ //But since it still can be called from destructor of another
+ //global static object, fallback to rand()
+ return rand();
+ }
+#elif defined(Q_OS_ANDROID)
+ AndroidRandomStorage *randomStorage = randomTLS();
+ if (!randomStorage)
+ return rand();
+
+ if (randomStorage->hasLocalData()) {
+ return randomStorage->localData().callMethod<jint>("nextInt",
+ "(I)I",
+ RAND_MAX);
+ }
+
+ QJNIObjectPrivate random("java/util/Random",
+ "(J)V",
+ jlong(1));
+
+ if (!random.isValid())
+ return rand();
+
+ randomStorage->setLocalData(random);
+ return random.callMethod<jint>("nextInt", "(I)I", RAND_MAX);
+#else
+ // On Windows srand() and rand() already use Thread-Local-Storage
+ // to store the seed between calls
+ // this is also valid for QT_NO_THREAD
+ return rand();
+#endif
+}
+
QT_END_NAMESPACE