mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
Improve seed() even more
This commit is contained in:
106
seed.c
106
seed.c
@@ -78,6 +78,11 @@
|
|||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
# include <sys/resource.h>
|
# include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_STDLIB_H)
|
||||||
|
# include <stdlib.h>
|
||||||
|
# define RANDOM_CNT (32) /* double random() call repeat count */
|
||||||
|
# define INITSTATE_SIZE (256) /* initstate pool size */
|
||||||
|
#endif
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
#include "qmath.h"
|
#include "qmath.h"
|
||||||
@@ -339,7 +344,10 @@ private_hash64_buf(hash64 hval, char *buf, unsigned len)
|
|||||||
NUMBER *
|
NUMBER *
|
||||||
pseudo_seed(void)
|
pseudo_seed(void)
|
||||||
{
|
{
|
||||||
struct { /* data used for quasi-random seed */
|
/*
|
||||||
|
* sdata - data used for quasi-random seed
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
#if defined(HAVE_GETTIME)
|
#if defined(HAVE_GETTIME)
|
||||||
# if defined(CLOCK_REALTIME)
|
# if defined(CLOCK_REALTIME)
|
||||||
struct timespec realtime; /* POSIX realtime clock */
|
struct timespec realtime; /* POSIX realtime clock */
|
||||||
@@ -399,20 +407,31 @@ pseudo_seed(void)
|
|||||||
time_t time; /* local time */
|
time_t time; /* local time */
|
||||||
size_t size; /* size of this data structure */
|
size_t size; /* size of this data structure */
|
||||||
hash64 prev_hash64_copy; /* copy if the previous hash value */
|
hash64 prev_hash64_copy; /* copy if the previous hash value */
|
||||||
FULL call_count_copy; /* count pf this funcation was called */
|
FULL call_count_copy; /* call count of this funcation */
|
||||||
jmp_buf env; /* setjmp() context */
|
jmp_buf env; /* setjmp() context */
|
||||||
#if defined(HAVE_ENVIRON)
|
#if defined(HAVE_ENVIRON)
|
||||||
char **environ_copy; /* copy of extern char **environ */
|
char **environ_copy; /* copy of extern char **environ */
|
||||||
#endif /* HAVE_ENVIRON */
|
#endif /* HAVE_ENVIRON */
|
||||||
char *sdata_p; /* address of this structure */
|
char *sdata_p; /* address of this structure */
|
||||||
} sdata;
|
} sdata;
|
||||||
hash64 hash_val; /* fnv64 hash of sdata */
|
|
||||||
ZVALUE hash; /* hash_val as a ZVALUE */
|
/**/
|
||||||
NUMBER *ret; /* return seed as a NUMBER */
|
|
||||||
|
#if defined(HAVE_STDLIB_H)
|
||||||
|
unsigned past_hash; /* prev hash or xor-folded prev hash */
|
||||||
|
long random_before[RANDOM_CNT]; /* random() pre initstate() */
|
||||||
|
char *initstate_ret; /* return from initstate() call */
|
||||||
|
char initstate_tbl[INITSTATE_SIZE]; /* initstate pool */
|
||||||
|
long random_after[RANDOM_CNT]; /* random() post initstate() */
|
||||||
|
int j;
|
||||||
|
#endif /* HAVE_STDLIB_H */
|
||||||
#if defined(HAVE_ENVIRON)
|
#if defined(HAVE_ENVIRON)
|
||||||
int i;
|
int i;
|
||||||
size_t envlen; /* length of an environment variable */
|
size_t envlen; /* length of an environment variable */
|
||||||
#endif
|
#endif
|
||||||
|
hash64 hash_val; /* fnv64 hash of sdata */
|
||||||
|
ZVALUE hash; /* hash_val as a ZVALUE */
|
||||||
|
NUMBER *ret; /* return seed as a NUMBER */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize the Fowler/Noll/Vo-1 64 bit hash
|
* initialize the Fowler/Noll/Vo-1 64 bit hash
|
||||||
@@ -426,7 +445,7 @@ pseudo_seed(void)
|
|||||||
* We do NOT care (that much) if these calls fail. We do not
|
* We do NOT care (that much) if these calls fail. We do not
|
||||||
* need to process any data in the 'sdata' structure.
|
* need to process any data in the 'sdata' structure.
|
||||||
*/
|
*/
|
||||||
memset(&sdata, 0, sizeof(sdata));
|
memset(&sdata, 0, sizeof(sdata)); /* zeroize sdata */
|
||||||
#if defined(HAVE_GETTIME)
|
#if defined(HAVE_GETTIME)
|
||||||
# if defined(CLOCK_REALTIME)
|
# if defined(CLOCK_REALTIME)
|
||||||
(void) clock_gettime(CLOCK_REALTIME, &sdata.realtime);
|
(void) clock_gettime(CLOCK_REALTIME, &sdata.realtime);
|
||||||
@@ -491,8 +510,8 @@ pseudo_seed(void)
|
|||||||
#endif
|
#endif
|
||||||
sdata.time = time(NULL);
|
sdata.time = time(NULL);
|
||||||
sdata.size = sizeof(sdata);
|
sdata.size = sizeof(sdata);
|
||||||
sdata.prev_hash64_copy = prev_hash64;
|
sdata.prev_hash64_copy = prev_hash64; /* load previous hash */
|
||||||
sdata.call_count_copy = ++call_count;
|
sdata.call_count_copy = ++call_count; /* update call count */
|
||||||
(void) setjmp(sdata.env);
|
(void) setjmp(sdata.env);
|
||||||
#if defined(HAVE_ENVIRON)
|
#if defined(HAVE_ENVIRON)
|
||||||
sdata.environ_copy = environ;
|
sdata.environ_copy = environ;
|
||||||
@@ -500,13 +519,13 @@ pseudo_seed(void)
|
|||||||
sdata.sdata_p = (char *)&sdata;
|
sdata.sdata_p = (char *)&sdata;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* seed the generator with the above data
|
* seed the generator with the above sdata
|
||||||
*/
|
*/
|
||||||
hash_val = private_hash64_buf(hash_val, (char *)&sdata, sizeof(sdata));
|
hash_val = private_hash64_buf(hash_val, (char *)&sdata, sizeof(sdata));
|
||||||
|
|
||||||
#if defined(HAVE_ENVIRON)
|
#if defined(HAVE_ENVIRON)
|
||||||
/*
|
/*
|
||||||
* seed each envinment variable
|
* mix in each envinment variable
|
||||||
*/
|
*/
|
||||||
for (i=0; environ[i] != NULL; ++i) {
|
for (i=0; environ[i] != NULL; ++i) {
|
||||||
|
|
||||||
@@ -520,10 +539,75 @@ pseudo_seed(void)
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_ENVIRON */
|
#endif /* HAVE_ENVIRON */
|
||||||
|
|
||||||
|
#if defined(HAVE_STDLIB_H)
|
||||||
|
/*
|
||||||
|
* mix in data from 31-bit random() and friends
|
||||||
|
*
|
||||||
|
* While random() returns only 31 bit values, seeded by 32 bits,
|
||||||
|
* we use it twice: once seeded by time of day, count, prev hash
|
||||||
|
* and once seeded by FNV hash of sdata. Both seeds are somewhat
|
||||||
|
* independent of each other, so we get the effect of 64 bits of seed.
|
||||||
|
*
|
||||||
|
* The 2nd seede uses the larger 256 byte state table to help
|
||||||
|
* differentiate the random() returns from the 1st seed.
|
||||||
|
*
|
||||||
|
* Because random() returns a 31-bit number, we call it twice
|
||||||
|
* and xor-shift the 2nd call with the 1st.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* load or xor-fold previous hash */
|
||||||
|
#if defined(HAVE_B64)
|
||||||
|
memcpy(&past_hash, &prev_hash64, sizeof(past_hash));
|
||||||
|
#else /* HAVE_B64 */
|
||||||
|
pash_hash = (unsigned)(prev_hash64.w32[0] ^ prev_hash64.w32[1]);
|
||||||
|
#endif /* HAVE_B64 */
|
||||||
|
|
||||||
|
/* classic random seeded with time of day, count, prev hash */
|
||||||
|
srandom((unsigned)(sdata.time) ^ (unsigned)call_count ^ past_hash);
|
||||||
|
for (j=0; j < RANDOM_CNT; ++j) {
|
||||||
|
random_before[j] = random();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize random state with the FNV hash of sdata */
|
||||||
|
#if defined(HAVE_B64)
|
||||||
|
initstate_ret = initstate((unsigned)hash_val,
|
||||||
|
initstate_tbl,
|
||||||
|
INITSTATE_SIZE);
|
||||||
|
#else /* HAVE_B64 */
|
||||||
|
initstate_ret = initstate((unsigned)(hash_val.w32[0] ^ hash_val.w32[1]),
|
||||||
|
initstate_tbl,
|
||||||
|
INITSTATE_SIZE);
|
||||||
|
#endif /* HAVE_B64 */
|
||||||
|
|
||||||
|
/* use random again with the new random state */
|
||||||
|
for (j=0; j < RANDOM_CNT; ++j) {
|
||||||
|
random_after[j] = random() ^ (random() << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hash all the data from random() and friends
|
||||||
|
*/
|
||||||
|
hash_val = private_hash64_buf(hash_val,
|
||||||
|
(char *)&past_hash,
|
||||||
|
sizeof(past_hash));
|
||||||
|
hash_val = private_hash64_buf(hash_val,
|
||||||
|
(char *)random_before,
|
||||||
|
sizeof(random_before));
|
||||||
|
hash_val = private_hash64_buf(hash_val,
|
||||||
|
(char *)initstate_ret,
|
||||||
|
sizeof(initstate_ret));
|
||||||
|
hash_val = private_hash64_buf(hash_val,
|
||||||
|
(char *)initstate_tbl,
|
||||||
|
sizeof(initstate_tbl));
|
||||||
|
hash_val = private_hash64_buf(hash_val,
|
||||||
|
(char *)random_after,
|
||||||
|
sizeof(random_after));
|
||||||
|
#endif /* HAVE_STDLIB_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* load the hash data into the ZVALUE
|
* load the hash data into the ZVALUE
|
||||||
*
|
*
|
||||||
* We do not care about byte-order or Endian issues, we just
|
* We do not care about byte-order, nor Endian issues, we just
|
||||||
* want to load in data.
|
* want to load in data.
|
||||||
*/
|
*/
|
||||||
hash.len = sizeof(hash_val) / sizeof(HALF);
|
hash.len = sizeof(hash_val) / sizeof(HALF);
|
||||||
|
Reference in New Issue
Block a user