2011-03-30 12:46:40 +00:00
|
|
|
#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;
|
2012-05-03 06:49:25 +00:00
|
|
|
uchar buf[128];
|
2011-03-30 12:46:40 +00:00
|
|
|
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 */
|
2012-05-03 06:49:25 +00:00
|
|
|
addclock0link(randomclock, MS2HZ+3);
|
2011-03-30 12:46:40 +00:00
|
|
|
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;
|
|
|
|
}
|