xref: /plan9-contrib/sys/src/9/vt4/random.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1*d6dfd9efSDavid du Colombier #include	"u.h"
2*d6dfd9efSDavid du Colombier #include	"../port/lib.h"
3*d6dfd9efSDavid du Colombier #include	"mem.h"
4*d6dfd9efSDavid du Colombier #include	"dat.h"
5*d6dfd9efSDavid du Colombier #include	"fns.h"
6*d6dfd9efSDavid du Colombier #include	"../port/error.h"
7*d6dfd9efSDavid du Colombier 
8*d6dfd9efSDavid du Colombier 
9*d6dfd9efSDavid du Colombier struct Rb
10*d6dfd9efSDavid du Colombier {
11*d6dfd9efSDavid du Colombier 	QLock;
12*d6dfd9efSDavid du Colombier 	Rendez	producer;
13*d6dfd9efSDavid du Colombier 	Rendez	consumer;
14*d6dfd9efSDavid du Colombier 	ulong	randomcount;
15*d6dfd9efSDavid du Colombier 	uchar	buf[128];
16*d6dfd9efSDavid du Colombier 	uchar	*ep;
17*d6dfd9efSDavid du Colombier 	uchar	*rp;
18*d6dfd9efSDavid du Colombier 	uchar	*wp;
19*d6dfd9efSDavid du Colombier 	uchar	next;
20*d6dfd9efSDavid du Colombier 	uchar	wakeme;
21*d6dfd9efSDavid du Colombier 	ushort	bits;
22*d6dfd9efSDavid du Colombier 	ulong	randn;
23*d6dfd9efSDavid du Colombier } rb;
24*d6dfd9efSDavid du Colombier 
25*d6dfd9efSDavid du Colombier static int
rbnotfull(void *)26*d6dfd9efSDavid du Colombier rbnotfull(void*)
27*d6dfd9efSDavid du Colombier {
28*d6dfd9efSDavid du Colombier 	int i;
29*d6dfd9efSDavid du Colombier 
30*d6dfd9efSDavid du Colombier 	i = rb.rp - rb.wp;
31*d6dfd9efSDavid du Colombier 	return i != 1 && i != (1 - sizeof(rb.buf));
32*d6dfd9efSDavid du Colombier }
33*d6dfd9efSDavid du Colombier 
34*d6dfd9efSDavid du Colombier static int
rbnotempty(void *)35*d6dfd9efSDavid du Colombier rbnotempty(void*)
36*d6dfd9efSDavid du Colombier {
37*d6dfd9efSDavid du Colombier 	return rb.wp != rb.rp;
38*d6dfd9efSDavid du Colombier }
39*d6dfd9efSDavid du Colombier 
40*d6dfd9efSDavid du Colombier static void
genrandom(void *)41*d6dfd9efSDavid du Colombier genrandom(void*)
42*d6dfd9efSDavid du Colombier {
43*d6dfd9efSDavid du Colombier 	up->basepri = PriNormal;
44*d6dfd9efSDavid du Colombier 	up->priority = up->basepri;
45*d6dfd9efSDavid du Colombier 
46*d6dfd9efSDavid du Colombier 	for(;;){
47*d6dfd9efSDavid du Colombier 		for(;;)
48*d6dfd9efSDavid du Colombier 			if(++rb.randomcount > 100000)
49*d6dfd9efSDavid du Colombier 				break;
50*d6dfd9efSDavid du Colombier 		if(anyhigher())
51*d6dfd9efSDavid du Colombier 			sched();
52*d6dfd9efSDavid du Colombier 		if(!rbnotfull(0))
53*d6dfd9efSDavid du Colombier 			sleep(&rb.producer, rbnotfull, 0);
54*d6dfd9efSDavid du Colombier 	}
55*d6dfd9efSDavid du Colombier }
56*d6dfd9efSDavid du Colombier 
57*d6dfd9efSDavid du Colombier /*
58*d6dfd9efSDavid du Colombier  *  produce random bits in a circular buffer
59*d6dfd9efSDavid du Colombier  */
60*d6dfd9efSDavid du Colombier static void
randomclock(void)61*d6dfd9efSDavid du Colombier randomclock(void)
62*d6dfd9efSDavid du Colombier {
63*d6dfd9efSDavid du Colombier 	if(rb.randomcount == 0 || !rbnotfull(0))
64*d6dfd9efSDavid du Colombier 		return;
65*d6dfd9efSDavid du Colombier 
66*d6dfd9efSDavid du Colombier 	rb.bits = (rb.bits<<2) ^ rb.randomcount;
67*d6dfd9efSDavid du Colombier 	rb.randomcount = 0;
68*d6dfd9efSDavid du Colombier 
69*d6dfd9efSDavid du Colombier 	rb.next++;
70*d6dfd9efSDavid du Colombier 	if(rb.next != 8/2)
71*d6dfd9efSDavid du Colombier 		return;
72*d6dfd9efSDavid du Colombier 	rb.next = 0;
73*d6dfd9efSDavid du Colombier 
74*d6dfd9efSDavid du Colombier 	*rb.wp ^= rb.bits;
75*d6dfd9efSDavid du Colombier 	if(rb.wp+1 == rb.ep)
76*d6dfd9efSDavid du Colombier 		rb.wp = rb.buf;
77*d6dfd9efSDavid du Colombier 	else
78*d6dfd9efSDavid du Colombier 		rb.wp = rb.wp+1;
79*d6dfd9efSDavid du Colombier 
80*d6dfd9efSDavid du Colombier 	if(rb.wakeme)
81*d6dfd9efSDavid du Colombier 		wakeup(&rb.consumer);
82*d6dfd9efSDavid du Colombier }
83*d6dfd9efSDavid du Colombier 
84*d6dfd9efSDavid du Colombier void
randominit(void)85*d6dfd9efSDavid du Colombier randominit(void)
86*d6dfd9efSDavid du Colombier {
87*d6dfd9efSDavid du Colombier 	/* Frequency close but not equal to HZ */
88*d6dfd9efSDavid du Colombier 	addclock0link(randomclock, 13);
89*d6dfd9efSDavid du Colombier 	rb.ep = rb.buf + sizeof(rb.buf);
90*d6dfd9efSDavid du Colombier 	rb.rp = rb.wp = rb.buf;
91*d6dfd9efSDavid du Colombier 	kproc("genrandom", genrandom, 0);
92*d6dfd9efSDavid du Colombier }
93*d6dfd9efSDavid du Colombier 
94*d6dfd9efSDavid du Colombier /*
95*d6dfd9efSDavid du Colombier  *  consume random bytes from a circular buffer
96*d6dfd9efSDavid du Colombier  */
97*d6dfd9efSDavid du Colombier ulong
randomread(void * xp,ulong n)98*d6dfd9efSDavid du Colombier randomread(void *xp, ulong n)
99*d6dfd9efSDavid du Colombier {
100*d6dfd9efSDavid du Colombier 	uchar *e, *p;
101*d6dfd9efSDavid du Colombier 	ulong x;
102*d6dfd9efSDavid du Colombier 
103*d6dfd9efSDavid du Colombier 	p = xp;
104*d6dfd9efSDavid du Colombier 
105*d6dfd9efSDavid du Colombier 	if(waserror()){
106*d6dfd9efSDavid du Colombier 		qunlock(&rb);
107*d6dfd9efSDavid du Colombier 		nexterror();
108*d6dfd9efSDavid du Colombier 	}
109*d6dfd9efSDavid du Colombier 
110*d6dfd9efSDavid du Colombier 	qlock(&rb);
111*d6dfd9efSDavid du Colombier 	for(e = p + n; p < e; ){
112*d6dfd9efSDavid du Colombier 		if(rb.wp == rb.rp){
113*d6dfd9efSDavid du Colombier 			rb.wakeme = 1;
114*d6dfd9efSDavid du Colombier 			wakeup(&rb.producer);
115*d6dfd9efSDavid du Colombier 			sleep(&rb.consumer, rbnotempty, 0);
116*d6dfd9efSDavid du Colombier 			rb.wakeme = 0;
117*d6dfd9efSDavid du Colombier 			continue;
118*d6dfd9efSDavid du Colombier 		}
119*d6dfd9efSDavid du Colombier 
120*d6dfd9efSDavid du Colombier 		/*
121*d6dfd9efSDavid du Colombier 		 *  beating clocks will be predictable if
122*d6dfd9efSDavid du Colombier 		 *  they are synchronized.  Use a cheap pseudo
123*d6dfd9efSDavid du Colombier 		 *  random number generator to obscure any cycles.
124*d6dfd9efSDavid du Colombier 		 */
125*d6dfd9efSDavid du Colombier 		x = rb.randn*1103515245 ^ *rb.rp;
126*d6dfd9efSDavid du Colombier 		*p++ = rb.randn = x;
127*d6dfd9efSDavid du Colombier 
128*d6dfd9efSDavid du Colombier 		if(rb.rp+1 == rb.ep)
129*d6dfd9efSDavid du Colombier 			rb.rp = rb.buf;
130*d6dfd9efSDavid du Colombier 		else
131*d6dfd9efSDavid du Colombier 			rb.rp = rb.rp+1;
132*d6dfd9efSDavid du Colombier 	}
133*d6dfd9efSDavid du Colombier 	qunlock(&rb);
134*d6dfd9efSDavid du Colombier 	poperror();
135*d6dfd9efSDavid du Colombier 
136*d6dfd9efSDavid du Colombier 	wakeup(&rb.producer);
137*d6dfd9efSDavid du Colombier 
138*d6dfd9efSDavid du Colombier 	return n;
139*d6dfd9efSDavid du Colombier }
140