eaabae489cf757ac866703b1468ab99ded86c4d1
[akaros.git] / kern / src / ns / random.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 static struct
17 {
18         qlock_t qlock;
19         struct rendez   producer;
20         struct rendez consumer;
21         uint32_t        randomcount;
22         uint8_t buf[1024];
23         uint8_t *ep;
24         uint8_t *rp;
25         uint8_t *wp;
26         uint8_t next;
27         uint8_t bits;
28         uint8_t wakeme;
29         uint8_t filled;
30         int     target;
31         int     kprocstarted;
32         uint32_t        randn;
33 } rb;
34
35 static int
36 rbnotfull(void*unused)
37 {
38         int i;
39
40         i = rb.wp - rb.rp;
41         if(i < 0)
42                 i += sizeof(rb.buf);
43         return i < rb.target;
44 }
45
46 static int
47 rbnotempty(void*unused)
48 {
49         return rb.wp != rb.rp;
50 }
51
52 static void
53 genrandom(void*unused)
54 {
55 #warning "priority?"
56         //setpri(PriBackground);
57
58         for(;;) {
59                 for(;;)
60                         if(++rb.randomcount > 100000)
61                                 break;
62                 //if(anyhigher())
63                 //      sched();
64                 if(rb.filled || !rbnotfull(0))
65                         rendez_sleep(&rb.producer, rbnotfull, 0);
66         }
67 }
68
69 /*
70  *  produce random bits in a circular buffer
71  */
72 static void
73 randomclock(void)
74 {
75         uint8_t *p;
76
77         if(rb.randomcount == 0)
78                 return;
79
80         if(!rbnotfull(0)) {
81                 rb.filled = 1;
82                 return;
83         }
84
85         rb.bits = (rb.bits<<2) ^ (rb.randomcount&3);
86         rb.randomcount = 0;
87
88         rb.next += 2;
89         if(rb.next != 8)
90                 return;
91
92         rb.next = 0;
93         *rb.wp ^= rb.bits ^ *rb.rp;
94         p = rb.wp+1;
95         if(p == rb.ep)
96                 p = rb.buf;
97         rb.wp = p;
98
99         if(rb.wakeme)
100                 rendez_wakeup(&rb.consumer);
101 }
102
103 void
104 randominit(void)
105 {
106         qlock_init(&rb.qlock);
107         rendez_init(&rb.producer);
108         rendez_init(&rb.consumer);
109         /* Frequency close but not equal to HZ */
110         //addclock0link(randomclock, 13);
111         rb.target = 16;
112         rb.ep = rb.buf + sizeof(rb.buf);
113         rb.rp = rb.wp = rb.buf;
114 }
115
116 /*
117  *  consume random bytes from a circular buffer
118  */
119 uint32_t
120 randomread(void *xp, uint32_t n)
121 {
122         ERRSTACK(1);
123         int i, sofar;
124         uint8_t *e, *p;
125
126         p = xp;
127
128         qlock(&(&rb)->qlock);
129         if(waserror()){
130                 qunlock(&(&rb)->qlock);
131                 nexterror();
132         }
133         if(!rb.kprocstarted){
134                 rb.kprocstarted = 1;
135                 ktask("genrand", genrandom, NULL);
136         }
137
138         for(sofar = 0; sofar < n; sofar += i){
139                 i = rb.wp - rb.rp;
140                 if(i == 0){
141                         rb.wakeme = 1;
142                         rendez_wakeup(&rb.producer);
143                         rendez_sleep(&rb.consumer, rbnotempty, 0);
144                         rb.wakeme = 0;
145                         continue;
146                 }
147                 if(i < 0)
148                         i = rb.ep - rb.rp;
149                 if((i+sofar) > n)
150                         i = n - sofar;
151                 memmove(p + sofar, rb.rp, i);
152                 e = rb.rp + i;
153                 if(e == rb.ep)
154                         e = rb.buf;
155                 rb.rp = e;
156         }
157         if(rb.filled && rb.wp == rb.rp){
158                 i = 2*rb.target;
159                 if(i > sizeof(rb.buf) - 1)
160                         i = sizeof(rb.buf) - 1;
161                 rb.target = i;
162                 rb.filled = 0;
163         }
164         poperror();
165         qunlock(&(&rb)->qlock);
166
167         rendez_wakeup(&rb.producer);
168
169         return n;
170 }