diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-05-03 08:49:25 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-05-03 08:49:25 +0200 |
commit | 7f04d86dfbb43cdbd18b2e3be31421dc9efee3b7 (patch) | |
tree | 8c8fc0888439b6e20cd856c6e1d9ae27001b14d3 /sys/src/9/port/random.c | |
parent | 5377a194478225481976f8400d10c093e5bdfa01 (diff) |
kernel: move duplicated random.c to port
Diffstat (limited to 'sys/src/9/port/random.c')
-rw-r--r-- | sys/src/9/port/random.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/sys/src/9/port/random.c b/sys/src/9/port/random.c new file mode 100644 index 000000000..3a697827a --- /dev/null +++ b/sys/src/9/port/random.c @@ -0,0 +1,138 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +struct Rb +{ + QLock; + Rendez producer; + Rendez consumer; + ulong randomcount; + uchar buf[128]; + uchar *ep; + uchar *rp; + uchar *wp; + uchar next; + uchar wakeme; + ushort bits; + ulong randn; +} rb; + +static int +rbnotfull(void*) +{ + int i; + + i = rb.rp - rb.wp; + return i != 1 && i != (1 - sizeof(rb.buf)); +} + +static int +rbnotempty(void*) +{ + return rb.wp != rb.rp; +} + +static void +genrandom(void*) +{ + up->basepri = PriNormal; + up->priority = up->basepri; + + for(;;){ + for(;;) + if(++rb.randomcount > 100000) + break; + if(anyhigher()) + sched(); + if(!rbnotfull(0)) + sleep(&rb.producer, rbnotfull, 0); + } +} + +/* + * produce random bits in a circular buffer + */ +static void +randomclock(void) +{ + if(rb.randomcount == 0 || !rbnotfull(0)) + return; + + rb.bits = (rb.bits<<2) ^ rb.randomcount; + rb.randomcount = 0; + + rb.next++; + if(rb.next != 8/2) + return; + rb.next = 0; + + *rb.wp ^= rb.bits; + if(rb.wp+1 == rb.ep) + rb.wp = rb.buf; + else + rb.wp = rb.wp+1; + + if(rb.wakeme) + wakeup(&rb.consumer); +} + +void +randominit(void) +{ + /* Frequency close but not equal to HZ */ + addclock0link(randomclock, MS2HZ+3); + rb.ep = rb.buf + sizeof(rb.buf); + rb.rp = rb.wp = rb.buf; + kproc("genrandom", genrandom, 0); +} + +/* + * consume random bytes from a circular buffer + */ +ulong +randomread(void *xp, ulong n) +{ + uchar *e, *p; + ulong x; + + p = xp; + + if(waserror()){ + qunlock(&rb); + nexterror(); + } + + qlock(&rb); + for(e = p + n; p < e; ){ + if(rb.wp == rb.rp){ + rb.wakeme = 1; + wakeup(&rb.producer); + sleep(&rb.consumer, rbnotempty, 0); + rb.wakeme = 0; + continue; + } + + /* + * beating clocks will be predictable if + * they are synchronized. Use a cheap pseudo- + * random number generator to obscure any cycles. + */ + x = rb.randn*1103515245 ^ *rb.rp; + *p++ = rb.randn = x; + + if(rb.rp+1 == rb.ep) + rb.rp = rb.buf; + else + rb.rp = rb.rp+1; + } + qunlock(&rb); + poperror(); + + wakeup(&rb.producer); + + return n; +} |