]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/random.c
kernel: kproc error and exit
[plan9front.git] / sys / src / 9 / port / 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 struct Rb
9 {
10         QLock;
11         Rendez  producer;
12         Rendez  consumer;
13         ulong   randomcount;
14         uchar   buf[128];
15         uchar   *ep;
16         uchar   *rp;
17         uchar   *wp;
18         uchar   next;
19         uchar   wakeme;
20         ushort  bits;
21         ulong   randn;
22 } rb;
23
24 static int
25 rbnotfull(void*)
26 {
27         int i;
28
29         i = rb.rp - rb.wp;
30         return i != 1 && i != (1 - sizeof(rb.buf));
31 }
32
33 static int
34 rbnotempty(void*)
35 {
36         return rb.wp != rb.rp;
37 }
38
39 static void
40 genrandom(void*)
41 {
42         up->basepri = PriNormal;
43         up->priority = up->basepri;
44
45         while(waserror())
46                 ;
47         for(;;){
48                 if(++rb.randomcount <= 100000)
49                         continue;
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, MS2HZ+3);
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 }