cosmopolitan/examples/getrandom.c
Justine Tunney 6f7d0cb1c3
Pay off more technical debt
This makes breaking changes to add underscores to many non-standard
function names provided by the c library. MODE=tiny is now tinier and
we now use smaller locks that are better for tiny apps in this mode.
Some headers have been renamed to be in the same folder as the build
package, so it'll be easier to know which build dependency is needed.
Certain old misguided interfaces have been removed. Intel intrinsics
headers are now listed in libc/isystem (but not in the amalgamation)
to help further improve open source compatibility. Header complexity
has also been reduced. Lastly, more shell scripts are now available.
2022-09-12 23:36:56 -07:00

319 lines
7.6 KiB
C

#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/xorshift.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/grnd.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/hyperion.h"
#include "third_party/getopt/getopt.h"
#define B 4096
bool isdone;
bool isbinary;
unsigned long count = -1;
uint64_t bcast(uint64_t f(void)) {
unsigned i;
uint64_t x;
for (x = i = 0; i < 8; ++i) {
x <<= 8;
x |= f() & 255;
}
return x;
}
uint64_t randv6(void) {
static int16_t gorp;
gorp = (gorp + 625) & 077777;
return gorp;
}
uint64_t randv7(void) {
static uint32_t randx = 1;
return ((randx = randx * 1103515245 + 12345) >> 16) & 077777;
}
uint64_t zero(void) {
return 0;
}
uint64_t inc(void) {
static uint64_t x;
return x++;
}
uint64_t unixv6(void) {
return bcast(randv6);
}
uint64_t unixv7(void) {
return bcast(randv7);
}
uint64_t ape(void) {
static int i;
if ((i += 8) > _end - _base) i = 8;
return READ64LE(_base + i);
}
uint64_t moby(void) {
static int i;
if ((i += 8) > kMobySize) i = 8;
return READ64LE(kMoby + i);
}
uint64_t knuth(void) {
uint64_t a, b;
static uint64_t x = 1;
x *= 6364136223846793005;
x += 1442695040888963407;
a = x >> 32;
x *= 6364136223846793005;
x += 1442695040888963407;
b = x >> 32;
return a | b << 32;
}
uint64_t rngset64(void) {
static unsigned i;
static uint64_t s;
if (!i) {
s = rand64();
i = (s + 1) & (511);
}
return MarsagliaXorshift64(&s);
}
uint64_t xorshift64(void) {
static uint64_t s = kMarsagliaXorshift64Seed;
return MarsagliaXorshift64(&s);
}
uint64_t xorshift32(void) {
static uint32_t s = kMarsagliaXorshift32Seed;
uint64_t a = MarsagliaXorshift32(&s);
uint64_t b = MarsagliaXorshift32(&s);
return (uint64_t)a << 32 | b;
}
uint64_t libc(void) {
uint64_t x;
CHECK_EQ(8, getrandom(&x, 8, 0));
return x;
}
uint64_t GetRandom(void) {
uint64_t x;
CHECK_EQ(8, getrandom(&x, 8, 0));
return x;
}
uint32_t python(void) {
#define K 0 // 624 /* wut */
#define N 624
#define M 397
static int index;
static char once;
static uint32_t mt[N];
static const uint32_t mag01[2] = {0, 0x9908b0dfu};
uint32_t y;
int kk;
if (!once) {
char *sp;
ssize_t rc;
uint32_t i, j, k, s[K];
mt[0] = 19650218;
for (i = 1; i < N; i++) {
mt[i] = (1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i);
}
if (K) {
for (sp = (char *)s, i = 0; i < sizeof(s); i += rc) {
if ((rc = getrandom(sp + i, sizeof(s) - i, 0)) == -1) {
if (errno != EINTR) abort();
}
}
for (i = 1, j = 0, k = MAX(N, K); k; k--) {
mt[i] =
(mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525u)) + s[j] + j;
if (++i >= N) mt[0] = mt[N - 1], i = 1;
if (++j >= K) j = 0;
}
for (k = N - 1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941u)) - i;
if (++i >= N) mt[0] = mt[N - 1], i = 1;
}
mt[0] = 0x80000000;
explicit_bzero(s, sizeof(s));
}
once = 1;
}
if (index >= N) {
for (kk = 0; kk < N - M; kk++) {
y = (mt[kk] & 0x80000000u) | (mt[kk + 1] & 0x7fffffff);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 1];
}
for (; kk < N - 1; kk++) {
y = (mt[kk] & 0x80000000u) | (mt[kk + 1] & 0x7fffffff);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 1];
}
y = (mt[N - 1] & 0x80000000u) | (mt[0] & 0x7fffffffu);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 1];
index = 0;
}
y = mt[index++];
y ^= y >> 11;
y ^= (y << 7) & 0x9d2c5680u;
y ^= (y << 15) & 0xefc60000u;
y ^= y >> 18;
return y;
#undef M
#undef N
#undef K
}
uint64_t pythonx2(void) {
uint64_t x = python();
x <<= 32;
x |= python();
return x;
}
const struct Function {
const char *s;
uint64_t (*f)(void);
} kFunctions[] = {
{"ape", ape}, //
{"getrandom", GetRandom}, //
{"inc", inc}, //
{"knuth", knuth}, //
{"lemur64", lemur64}, //
{"libc", libc}, //
{"moby", moby}, //
{"mt19937", _mt19937}, //
{"python", pythonx2}, //
{"rand64", rand64}, //
{"rdrand", rdrand}, //
{"rdrnd", rdrand}, //
{"rdseed", rdseed}, //
{"rngset64", rngset64}, //
{"unixv6", unixv6}, //
{"unixv7", unixv7}, //
{"vigna", vigna}, //
{"xorshift32", xorshift32}, //
{"xorshift64", xorshift64}, //
{"zero", zero}, //
};
void OnInt(int sig) {
isdone = true;
}
wontreturn void PrintUsage(FILE *f, int rc) {
fprintf(f, "Usage: %s [-b] [-n NUM] [FUNC]\n", program_invocation_name);
exit(rc);
}
int main(int argc, char *argv[]) {
char *p;
int i, opt;
ssize_t rc;
uint64_t x;
static char buf[B];
uint64_t (*f)(void);
while ((opt = getopt(argc, argv, "hbc:n:")) != -1) {
switch (opt) {
case 'b':
isbinary = true;
break;
case 'c':
case 'n':
count = sizetol(optarg, 1024);
break;
case 'h':
PrintUsage(stdout, EXIT_SUCCESS);
default:
PrintUsage(stderr, EX_USAGE);
}
}
if (optind == argc) {
f = libc;
} else {
for (f = 0, i = 0; i < ARRAYLEN(kFunctions); ++i) {
if (!strcasecmp(argv[optind], kFunctions[i].s)) {
f = kFunctions[i].f;
break;
}
}
if (!f) {
fprintf(stderr, "unknown function: %`'s\n", argv[optind]);
fprintf(stderr, "try: ");
for (i = 0; i < ARRAYLEN(kFunctions); ++i) {
if (i) fprintf(stderr, ", ");
fprintf(stderr, "%s", kFunctions[i].s);
}
fprintf(stderr, "\n");
return 1;
}
}
signal(SIGINT, OnInt);
signal(SIGPIPE, SIG_IGN);
if (!isbinary) {
for (; count && !isdone && !feof(stdout); --count) {
printf("0x%016lx\n", f());
}
fflush(stdout);
return ferror(stdout) ? 1 : 0;
}
while (count && !isdone) {
if (count >= B) {
for (i = 0; i < B / 8; ++i) {
x = f();
p = buf + i * 8;
WRITE64LE(p, x);
}
for (i = 0; i < B; i += rc) {
rc = write(1, buf + i, B - i);
if (rc == -1 && errno == EPIPE) exit(1);
if (rc == -1) perror("write"), exit(1);
}
} else {
x = f();
rc = write(1, &x, MIN(8, count));
}
if (!rc) break;
if (rc == -1 && errno == EPIPE) exit(1);
if (rc == -1) perror("write"), exit(1);
count -= rc;
}
return 0;
}