diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-04-13 17:50:05 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-12 06:14:37 +0000 |
commit | 030782e1a8c44c6be2a95c88d5a4a3a37b3b6173 (patch) | |
tree | f5508927660b4728c67a4cd7dca91e2525567c81 /src/corelib/global/qrandom.cpp | |
parent | 593f022515da8a834b358b5a57779afff619b3e7 (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.cpp | 141 |
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 |