src/corelib/plugin/quuid.cpp
changeset 33 3e2da88830cd
parent 18 2f34d5167611
--- a/src/corelib/plugin/quuid.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/corelib/plugin/quuid.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -546,13 +546,13 @@
     \fn QUuid QUuid::createUuid()
 
     On any platform other than Windows, this function returns a new
-    UUID with variant QUuid::DCE and version QUuid::Random. The random
-    numbers used to construct the UUID are obtained from the local
-    pseudo-random generator, qrand(), which is usually not a cryptographic
-    quality random number generator. Therefore, a UUID generated by
-    this function can't be guaranteed to be unique. If the pseudo-random
-    number generator for the calling thread has not yet been seeded, this
-    function will seed the pseudo-random number generator by calling qsrand().
+    UUID with variant QUuid::DCE and version QUuid::Random.  If
+    the /dev/urandom device exists, then the numbers used to construct
+    the UUID will be of cryptographic quality, which will make the UUID
+    unique.  Otherwise, the numbers of the UUID will be obtained from
+    the local pseudo-random number generator (qrand(), which is seeded
+    by qsrand()) which is usually not of cryptograhic quality, which
+    means that the UUID can't be guaranteed to be unique.
 
     On a Windows platform, a GUID is generated, which almost certainly
     \e{will} be unique, on this or any other system, networked or not.
@@ -577,31 +577,62 @@
 
 QT_BEGIN_INCLUDE_NAMESPACE
 #include "qdatetime.h"
-#include "stdlib.h" // For srand/rand
+#include "qfile.h"
+#include "qthreadstorage.h"
+#include <stdlib.h> // for RAND_MAX
 QT_END_INCLUDE_NAMESPACE
 
-extern void qsrand(); // in qglobal.cpp
-
 QUuid QUuid::createUuid()
 {
-    static const int intbits = sizeof(int)*8;
-    static int randbits = 0;
-    if (!randbits) {
-        int max = RAND_MAX;
-        do { ++randbits; } while ((max=max>>1));
-    }
-
-    // reseed, but only if not already seeded
-    qsrand();
-
     QUuid result;
     uint *data = &(result.data1);
-    int chunks = 16 / sizeof(uint);
-    while (chunks--) {
-        uint randNumber = 0;
-        for (int filled = 0; filled < intbits; filled += randbits)
-            randNumber |= qrand()<<filled;
-         *(data+chunks) = randNumber;
+
+#ifdef Q_OS_UNIX
+    QFile devUrandom;
+    devUrandom.setFileName(QLatin1String("/dev/urandom"));
+    if (devUrandom.open(QIODevice::ReadOnly)) {
+        qint64 numToRead = 4 * sizeof(uint);
+        devUrandom.read((char *) data, numToRead); // should read 128-bits of data
+    } else
+#endif
+    {
+        static const int intbits = sizeof(int)*8;
+        static int randbits = 0;
+        if (!randbits) {
+        int r = 0;
+            int max = RAND_MAX;
+            do { ++r; } while ((max=max>>1));
+            randbits = r;
+        }
+
+    // Seed the PRNG once per thread with a combination of current time, a
+    // stack address and a serial counter (since thread stack addresses are
+    // re-used).
+#ifndef QT_BOOTSTRAPPED
+    static QThreadStorage<int *> uuidseed;
+    if (!uuidseed.hasLocalData())
+    {
+        int *pseed = new int;
+        static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(2);
+        qsrand(*pseed = QDateTime::currentDateTime().toTime_t()
+                        + quintptr(&pseed)
+                        + serial.fetchAndAddRelaxed(1));
+        uuidseed.setLocalData(pseed);
+    }
+#else
+    static bool seeded = false;
+    if (!seeded)
+        qsrand(QDateTime::currentDateTime().toTime_t()
+               + quintptr(&seeded));
+#endif
+
+        int chunks = 16 / sizeof(uint);
+        while (chunks--) {
+            uint randNumber = 0;
+            for (int filled = 0; filled < intbits; filled += randbits)
+                randNumber |= qrand()<<filled;
+             *(data+chunks) = randNumber;
+        }
     }
 
     result.data4[0] = (result.data4[0] & 0x3F) | 0x80;        // UV_DCE