Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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