FreeBSD/Linux Kernel Cross Reference
sys/pc/random.c
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 precictable 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 }
Cache object: c411abbfd5ab953bcb1545bb2ebf5e30
|