df6b68092c
catch the error() that can be thrown by sleep() and tsleep() in kprocs. add missing pexit() calls. always set the freemem argument to pexit() from kproc otherwise the process gets added to the broken list.
140 lines
2 KiB
C
140 lines
2 KiB
C
#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;
|
|
|
|
while(waserror())
|
|
;
|
|
for(;;){
|
|
if(++rb.randomcount <= 100000)
|
|
continue;
|
|
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;
|
|
}
|