]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/random.c
kernel: fix sysexec() error handling compiler problem, sysrendez() busyloop
[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         for(;;){
46                 for(;;)
47                         if(++rb.randomcount > 100000)
48                                 break;
49                 if(anyhigher())
50                         sched();
51                 if(!rbnotfull(0))
52                         sleep(&rb.producer, rbnotfull, 0);
53         }
54 }
55
56 /*
57  *  produce random bits in a circular buffer
58  */
59 static void
60 randomclock(void)
61 {
62         if(rb.randomcount == 0 || !rbnotfull(0))
63                 return;
64
65         rb.bits = (rb.bits<<2) ^ rb.randomcount;
66         rb.randomcount = 0;
67
68         rb.next++;
69         if(rb.next != 8/2)
70                 return;
71         rb.next = 0;
72
73         *rb.wp ^= rb.bits;
74         if(rb.wp+1 == rb.ep)
75                 rb.wp = rb.buf;
76         else
77                 rb.wp = rb.wp+1;
78
79         if(rb.wakeme)
80                 wakeup(&rb.consumer);
81 }
82
83 void
84 randominit(void)
85 {
86         /* Frequency close but not equal to HZ */
87         addclock0link(randomclock, MS2HZ+3);
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 predictable 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 }