ref: dd16eef8365cb0b9e4805c23291aadcaa596dd87
dir: /os/port/random.c/
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" static struct { QLock; Rendez producer; Rendez consumer; ulong randomcount; uchar buf[1024]; uchar *ep; uchar *rp; uchar *wp; uchar next; uchar bits; uchar wakeme; uchar filled; int target; int kprocstarted; ulong randn; } rb; static int rbnotfull(void*) { int i; i = rb.wp - rb.rp; if(i < 0) i += sizeof(rb.buf); return i < rb.target; } static int rbnotempty(void*) { return rb.wp != rb.rp; } static void genrandom(void*) { setpri(PriBackground); for(;;) { for(;;) if(++rb.randomcount > 100000) break; if(anyhigher()) sched(); if(rb.filled || !rbnotfull(0)) sleep(&rb.producer, rbnotfull, 0); } } /* * produce random bits in a circular buffer */ static void randomclock(void) { uchar *p; if(rb.randomcount == 0) return; if(!rbnotfull(0)) { rb.filled = 1; return; } rb.bits = (rb.bits<<2) ^ (rb.randomcount&3); rb.randomcount = 0; rb.next += 2; if(rb.next != 8) return; rb.next = 0; *rb.wp ^= rb.bits ^ *rb.rp; p = rb.wp+1; if(p == rb.ep) p = rb.buf; rb.wp = p; if(rb.wakeme) wakeup(&rb.consumer); } void randominit(void) { /* Frequency close but not equal to HZ */ addclock0link(randomclock, 13); rb.target = 16; rb.ep = rb.buf + sizeof(rb.buf); rb.rp = rb.wp = rb.buf; } /* * consume random bytes from a circular buffer */ ulong randomread(void *xp, ulong n) { int i, sofar; uchar *e, *p; p = xp; qlock(&rb); if(waserror()){ qunlock(&rb); nexterror(); } if(!rb.kprocstarted){ rb.kprocstarted = 1; kproc("genrand", genrandom, nil, 0); } for(sofar = 0; sofar < n; sofar += i){ i = rb.wp - rb.rp; if(i == 0){ rb.wakeme = 1; wakeup(&rb.producer); sleep(&rb.consumer, rbnotempty, 0); rb.wakeme = 0; continue; } if(i < 0) i = rb.ep - rb.rp; if((i+sofar) > n) i = n - sofar; memmove(p + sofar, rb.rp, i); e = rb.rp + i; if(e == rb.ep) e = rb.buf; rb.rp = e; } if(rb.filled && rb.wp == rb.rp){ i = 2*rb.target; if(i > sizeof(rb.buf) - 1) i = sizeof(rb.buf) - 1; rb.target = i; rb.filled = 0; } poperror(); qunlock(&rb); wakeup(&rb.producer); return n; }