diff options
author | Paul R. Eggert <eggert@cs.ucla.edu> | 2010-07-23 15:07:27 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2010-07-23 15:08:36 -0700 |
commit | df906d2e75d6822c88999b8cc537166371f2da6e (patch) | |
tree | 74be2ee6513ee1ee98ffe683cfa3d2b134fc9dd7 /gl/lib/randread.c | |
parent | 47076e3c7c22fc7557f388ad3d47228b922da71e (diff) | |
download | coreutils-df906d2e75d6822c88999b8cc537166371f2da6e.tar.xz |
randread: run 2x faster on 64-bit hosts, don't assume no padding bits
* gl/lib/rand-isaac.c: Remove the I/O; this belongs elsewhere.
Add support for ISAAC64. Port to hosts with padding bits.
Add self to author list. Include <limits.h>, for CHAR_BIT.
Don't include string.h, sys/time.h, unistd.h.
(min, just): New functions.
(IF32): New macros.
(ind, ISAAC_STEP, isaac_refill, mix, isaac_init, isaac_seed):
Add support for ISAAC64. Port to hosts with padding bits.
(ind): Now an inline function rather than a macro; no need for it
to be a macro with modern compilers.
(ISAAC_STEP): Renamed from isaac_step, since it's not function-like.
Don't bother to pass args that are always the same. All uses changed.
(ISAAC_STEP, ISAAC_SEED): Move to inside the only function body
that can use it.
(ISAAC_MIX): Renamed from isaac_mix, since it's now a macro and is
no longer function-like. Don't bother saving and restoring state;
no longer needed now that we're not a function. All uses changed.
(isaac_seed_start, isaac_seed_data, isaac_seed_finish): Remove.
(isaac_seed): Take just the one arg; the caller now sets s->m.
* gl/lib/rand-isaac.h: Use _GL_RAND_ISAAC_H to protect, instead
of RAND_ISAAC_H. Try out " #" rather than "# " for indenting.
(ISAAC_BITS_LOG, ISAAC_BITS): New macros.
(ISAAC_WORDS_LOG): Renamed from ISAAC_LOG.
(isaac_word): New type. All uses of uint32_t changed to isaac_word,
to support ISAAC64.
(struct isaac_state): Rename member MM to M, and make it public.
(isaac_seed, isaac_refill): Adjust to new API.
* gl/lib/randread.c: Include sys/time.h.
(get_nonce): New function, containing the nonce stuff that used
to be in rand-isaac.c but better belongs here.
(randread_new): Use it.
* gl/modules/randread (Depends-on): Add inline.
* gl/modules/randread-tests: New file.
* gl/tests/test-rand-isaac.c: New file.
Diffstat (limited to 'gl/lib/randread.c')
-rw-r--r-- | gl/lib/randread.c | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/gl/lib/randread.c b/gl/lib/randread.c index a681c8dae..dcaeee460 100644 --- a/gl/lib/randread.c +++ b/gl/lib/randread.c @@ -31,6 +31,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/time.h> #include <unistd.h> #include "gettext.h" @@ -106,7 +107,7 @@ struct randread_source /* Up to a buffer's worth of pseudorandom data. */ union { - uint32_t w[ISAAC_WORDS]; + isaac_word w[ISAAC_WORDS]; unsigned char b[ISAAC_BYTES]; } data; } isaac; @@ -139,6 +140,52 @@ simple_new (FILE *source, void const *handler_arg) return s; } +/* Put a nonce value into BUFFER, with size BUFSIZE, but do not get + more than BYTES_BOUND bytes' worth of random information from any + nonce device. */ + +static void +get_nonce (void *buffer, size_t bufsize, size_t bytes_bound) +{ + char *buf = buffer; + ssize_t seeded = 0; + + /* Get some data from FD if available. */ + int fd = open (NAME_OF_NONCE_DEVICE, O_RDONLY | O_BINARY); + if (0 <= fd) + { + seeded = read (fd, buf, MIN (bufsize, bytes_bound)); + if (seeded < 0) + seeded = 0; + close (fd); + } + + /* If there's no nonce device, use a poor approximation + by getting the time of day, etc. */ +# define ISAAC_SEED(type, initialize_v) \ + if (seeded < bufsize) \ + { \ + type v; \ + size_t nbytes = MIN (sizeof v, bufsize - seeded); \ + initialize_v; \ + memcpy (buf + seeded, &v, nbytes); \ + seeded += nbytes; \ + } + ISAAC_SEED (struct timeval, gettimeofday (&v, NULL)); + ISAAC_SEED (pid_t, v = getpid ()); + ISAAC_SEED (pid_t, v = getppid ()); + ISAAC_SEED (uid_t, v = getuid ()); + ISAAC_SEED (uid_t, v = getgid ()); + +#ifdef lint + /* Normally we like having the extra randomness from uninitialized + parts of BUFFER. However, omit this randomness if we want to + avoid false-positives from memory-checking debugging tools. */ + memset (buf + seeded, 0, bufsize - seeded); +#endif +} + + /* Create and initialize a random data source from NAME, or use a reasonable default source if NAME is null. BYTES_BOUND is an upper bound on the number of bytes that will be needed. If zero, it is a @@ -170,11 +217,10 @@ randread_new (char const *name, size_t bytes_bound) setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound)); else { - int nonce_device = open (NAME_OF_NONCE_DEVICE, O_RDONLY | O_BINARY); s->buf.isaac.buffered = 0; - isaac_seed (&s->buf.isaac.state, nonce_device, bytes_bound); - if (0 <= nonce_device) - close (nonce_device); + get_nonce (s->buf.isaac.state.m, sizeof s->buf.isaac.state.m, + bytes_bound); + isaac_seed (&s->buf.isaac.state); } return s; @@ -245,9 +291,9 @@ readisaac (struct isaac *isaac, unsigned char *p, size_t size) /* If P is aligned, write to *P directly to avoid the overhead of copying from the buffer. */ - if (ALIGNED_POINTER (p, uint32_t)) + if (ALIGNED_POINTER (p, isaac_word)) { - uint32_t *wp = (uint32_t *) p; + isaac_word *wp = (isaac_word *) p; while (ISAAC_BYTES <= size) { isaac_refill (&isaac->state, wp); |