From 021c79f038c218a55b145fafcda5c59cf3a309d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Fri, 11 Oct 2013 14:55:33 +0200 Subject: [PATCH] Android: Use java.util.Random in qrand() Android does not provide rand_r(), so we would fall back to rand() and srand() which means we where not keeping the promise of qrand and qsrand being thread-safe. As a replacement we can use the Java api and have one Random object for each thread. Task-number: QTBUG-32814 Change-Id: Id46d195a0bb122bc7a5a8de43bdf088e11a9c42e Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/global/qglobal.cpp | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ff2c4bbe5e1..1dd77c5859c 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -76,6 +76,10 @@ #include #endif +#if defined(Q_OS_ANDROID) +#include +#endif + QT_BEGIN_NAMESPACE #if !QT_DEPRECATED_SINCE(5, 0) @@ -2335,6 +2339,9 @@ typedef uint SeedStorageType; typedef QThreadStorage SeedStorage; Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value +#elif defined(Q_OS_ANDROID) +typedef QThreadStorage AndroidRandomStorage; +Q_GLOBAL_STATIC(AndroidRandomStorage, randomTLS) #endif /*! @@ -2368,6 +2375,16 @@ void qsrand(uint seed) //global static object, fallback to srand(seed) srand(seed); } +#elif defined(Q_OS_ANDROID) + QJNIObjectPrivate random = QJNIObjectPrivate("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 @@ -2409,6 +2426,25 @@ int qrand() //global static object, fallback to rand() return rand(); } +#elif defined(Q_OS_ANDROID) + AndroidRandomStorage *randomStorage = randomTLS(); + if (!randomStorage) + return rand(); + + QJNIObjectPrivate random; + if (!randomStorage->hasLocalData()) { + random = QJNIObjectPrivate("java/util/Random", + "(J)V", + jlong(1)); + if (!random.isValid()) + return rand(); + + randomStorage->setLocalData(random); + } else { + random = randomStorage->localData(); + } + + return random.callMethod("nextInt", "(I)I", RAND_MAX); #else // On Windows srand() and rand() already use Thread-Local-Storage // to store the seed between calls