random.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. struct Rb
  8. {
  9. QLock;
  10. Rendez producer;
  11. Rendez consumer;
  12. ulong randomcount;
  13. uchar buf[128];
  14. uchar *ep;
  15. uchar *rp;
  16. uchar *wp;
  17. uchar next;
  18. uchar wakeme;
  19. ushort bits;
  20. ulong randn;
  21. } rb;
  22. static int
  23. rbnotfull(void*)
  24. {
  25. int i;
  26. i = rb.rp - rb.wp;
  27. return i != 1 && i != (1 - sizeof(rb.buf));
  28. }
  29. static int
  30. rbnotempty(void*)
  31. {
  32. return rb.wp != rb.rp;
  33. }
  34. static void
  35. genrandom(void*)
  36. {
  37. up->basepri = PriNormal;
  38. up->priority = up->basepri;
  39. for(;;){
  40. for(;;)
  41. if(++rb.randomcount > 100000)
  42. break;
  43. if(anyhigher())
  44. sched();
  45. if(!rbnotfull(0))
  46. sleep(&rb.producer, rbnotfull, 0);
  47. }
  48. }
  49. /*
  50. * produce random bits in a circular buffer
  51. */
  52. static void
  53. randomclock(void)
  54. {
  55. if(rb.randomcount == 0 || !rbnotfull(0))
  56. return;
  57. rb.bits = (rb.bits<<2) ^ rb.randomcount;
  58. rb.randomcount = 0;
  59. rb.next++;
  60. if(rb.next != 8/2)
  61. return;
  62. rb.next = 0;
  63. *rb.wp ^= rb.bits;
  64. if(rb.wp+1 == rb.ep)
  65. rb.wp = rb.buf;
  66. else
  67. rb.wp = rb.wp+1;
  68. if(rb.wakeme)
  69. wakeup(&rb.consumer);
  70. }
  71. void
  72. randominit(void)
  73. {
  74. addclock0link(randomclock, 1000/HZ);
  75. rb.ep = rb.buf + sizeof(rb.buf);
  76. rb.rp = rb.wp = rb.buf;
  77. kproc("genrandom", genrandom, 0);
  78. }
  79. /*
  80. * consume random bytes from a circular buffer
  81. */
  82. ulong
  83. randomread(void *xp, ulong n)
  84. {
  85. uchar *e, *p;
  86. ulong x;
  87. p = xp;
  88. if(waserror()){
  89. qunlock(&rb);
  90. nexterror();
  91. }
  92. qlock(&rb);
  93. for(e = p + n; p < e; ){
  94. if(rb.wp == rb.rp){
  95. rb.wakeme = 1;
  96. wakeup(&rb.producer);
  97. sleep(&rb.consumer, rbnotempty, 0);
  98. rb.wakeme = 0;
  99. continue;
  100. }
  101. /*
  102. * beating clocks will be predictable if
  103. * they are synchronized. Use a cheap pseudo
  104. * random number generator to obscure any cycles.
  105. */
  106. x = rb.randn*1103515245 ^ *rb.rp;
  107. *p++ = rb.randn = x;
  108. if(rb.rp+1 == rb.ep)
  109. rb.rp = rb.buf;
  110. else
  111. rb.rp = rb.rp+1;
  112. }
  113. qunlock(&rb);
  114. poperror();
  115. wakeup(&rb.producer);
  116. return n;
  117. }