FreeBSD/Linux Kernel Cross Reference
sys/bitsy/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[128];
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 addclock0link(randomclock, 1000/HZ);
88 rb.ep = rb.buf + sizeof(rb.buf);
89 rb.rp = rb.wp = rb.buf;
90 kproc("genrandom", genrandom, 0);
91 }
92
93 /*
94 * consume random bytes from a circular buffer
95 */
96 ulong
97 randomread(void *xp, ulong n)
98 {
99 uchar *e, *p;
100 ulong x;
101
102 p = xp;
103
104 if(waserror()){
105 qunlock(&rb);
106 nexterror();
107 }
108
109 qlock(&rb);
110 for(e = p + n; p < e; ){
111 if(rb.wp == rb.rp){
112 rb.wakeme = 1;
113 wakeup(&rb.producer);
114 sleep(&rb.consumer, rbnotempty, 0);
115 rb.wakeme = 0;
116 continue;
117 }
118
119 /*
120 * beating clocks will be precictable if
121 * they are synchronized. Use a cheap pseudo
122 * random number generator to obscure any cycles.
123 */
124 x = rb.randn*1103515245 ^ *rb.rp;
125 *p++ = rb.randn = x;
126
127 if(rb.rp+1 == rb.ep)
128 rb.rp = rb.buf;
129 else
130 rb.rp = rb.rp+1;
131 }
132 qunlock(&rb);
133 poperror();
134
135 wakeup(&rb.producer);
136
137 return n;
138 }
Cache object: b6cd3a6aeb078aa3c91811567ab41ce0
|