123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- #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[1024];
- 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, 13);
- 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;
- }
|