On Domingo 08 Marzo 2009, Sidney Markowitz wrote:
> Christophe Rhodes wrote, On 8/3/09 5:51 AM:
> > That depends on your definition of "just fine". I ask you again:
> > why are you generating 100 new random-state objects within such a
> > short timeframe?
> I agree that Justin's test case makes little sense, but there are use
> cases for calling (make-random-state t) more than once within a
> second. If you combine two simulation programs into one, you might be
> running two independent random streams that are initialized within
> one second of each other. Or you might run multiple instances of the
> same simulation program on a cluster of machines.
> The latter one in particular seems like a reasonable use case in
> which the current implementation will cause problems. The situation
> is made worse by the fact that there is no portable way defined to
> initialize a random-state with your own seed that you can ensure is
> unique. So how would one run simulations in parallel on a cluster?
> Admittedly, the Common Lisp spec does not explicitly say that you get
> a different value every time you call (make-random-state t), but the
> hyperspec does say "that has been randomly initialized by some
> means". It is surprising behavior if things which have been
> independently randomly initialized consistently have the same value.
> I'm not sure what the right thing to do here is. Given that
> implementations do seed from (get-universal-time) it would not be
> portable for anyone to count on different behavior. On the other
> hand, there doesn't seem to be any portable way to make sure that you
> are initializing with a properly random seed.
> cmucl reads from /dev/urandom to initialize the seed in
> (make-random-state t) with an ignore-errors to fall back to
> (get-universal-time) on systems that don't have a working
> That seems to be a simple way to avoid surprising behavior on most
> platforms without being worse than the current implementation.
> -- Sidney Markowitz
diff --git a/src/code/target-random.lisp b/src/code/target-random.lisp
index f0b740f..596d109 100644
@@ -67,6 +67,29 @@
(setf *random-state* (%make-random-state))
(/show0 "returning from !RANDOM-COLD-INIT"))
+;;; Generate a random seed that can be used for seeding the generator.
+;;; If /dev/urandom is available, it is used to generate random data
+;;; as the seed. Otherwise, the current time is used as the seed.
+;;; The /dev/urandom device exists on Linux, FreeBSD, Solaris 8 and
+;;; later. (You need to have patch 112438-01 for Solaris 8 to get that
+;;; device, though). It returns pseudorandom data with entropy that
+;;; the kernel collects from the environment. Unlike the related
+;;; /dev/random, this device does not block when the entropy pool has
+;;; been depleted.
+(defun generate-seed ()
+ ;; On some systems (as reported by Ole Rohne on cmucl-imp),
+ ;; /dev/urandom isn't what we think it is, so if it doesn't work,
+ ;; silently generate the seed from the current time.
+ (or (ignore-errors
+ (with-open-file (rand "/dev/urandom"
+ :direction :input
+ :element-type '(unsigned-byte 32))
+ (read-byte rand)))
+ (logand (get-universal-time) #xffffffff)))
(defun make-random-state (&optional state)
"Make a random state object. If STATE is not supplied, return a copy
@@ -94,9 +117,7 @@
(/show0 "T clause")
- (%make-random-state :state (init-random-state
- (logand (get-universal-time)
+ (%make-random-state :state (init-random-state (generate-seed)))))))
;;;; random entries