sleep.scm 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom
  3. ; Sleeping for N milliseconds.
  4. (define (sleep user-n)
  5. (let ((n (coerce-to-nonnegative-integer user-n)))
  6. (cond ((not n)
  7. (assertion-violation 'sleep "wrong type argument" user-n))
  8. ((< 0 n)
  9. (let ((cell (make-cell (current-thread))))
  10. (disable-interrupts!)
  11. (set-thread-cell! (current-thread) cell)
  12. (register-dozer-unsafe! (+ (real-time) n)
  13. (lambda ()
  14. (and (cell-ref cell)
  15. #t))
  16. (lambda ()
  17. (make-ready (cell-ref cell))))
  18. (block))))))
  19. (define (coerce-to-nonnegative-integer n)
  20. (if (real? n)
  21. (let* ((n (round n))
  22. (n (if (exact? n)
  23. n
  24. (inexact->exact n))))
  25. (if (<= 0 n)
  26. n
  27. #f))
  28. #f))
  29. ; We insert a pair consisting of a wakeup time and another pair.
  30. ; The second pair contains two thunks; the first one checks if the
  31. ; dozer is still alive, the second wakes it up.
  32. (define (register-dozer-unsafe! wakeup-time alive? wakeup!)
  33. (session-data-set! dozers
  34. (insert (cons wakeup-time
  35. (cons alive? wakeup!))
  36. (session-data-ref dozers)
  37. (lambda (frob1 frob2)
  38. (< (car frob1)
  39. (car frob2))))))
  40. ; Note that, if ALIVE? or WAKEUP! isn't a thunk or doesn't run without
  41. ; problems, there'll be hell to pay upon wakeup.
  42. (define (register-dozer! user-wakeup-time alive? wakeup!)
  43. (let ((wakeup-time (coerce-to-nonnegative-integer user-wakeup-time)))
  44. (cond ((not wakeup-time)
  45. (assertion-violation 'register-dozer! "wrong type argument" user-wakeup-time))
  46. (else
  47. (let ((ints (set-enabled-interrupts! 0)))
  48. (register-dozer-unsafe! wakeup-time alive? wakeup!)
  49. (set-enabled-interrupts! ints))))))
  50. (define dozers (make-session-data-slot! '()))
  51. (define (insert x l <)
  52. (cond ((null? l)
  53. (list x))
  54. ((< x (car l))
  55. (cons x l))
  56. (else
  57. (cons (car l)
  58. (insert x (cdr l) <)))))
  59. ; Called by root scheduler, so won't be interrupted.
  60. ; This returns two values, a boolean that indicates if any threads were
  61. ; woken and the time until the next sleeper wakes. We have to check for
  62. ; threads that have been started for some other reason.
  63. (define (wake-some-threads)
  64. (if (null? (session-data-ref dozers))
  65. (values #f #f)
  66. (let ((time (real-time)))
  67. (let loop ((to-do (session-data-ref dozers)) (woke? #f))
  68. (if (null? to-do)
  69. (begin
  70. (session-data-set! dozers '())
  71. (values woke? #f))
  72. (let* ((next (car to-do))
  73. (alive? (cadr next)))
  74. (cond
  75. ((not (alive?))
  76. (loop (cdr to-do) woke?))
  77. ((< time (car next))
  78. (session-data-set! dozers to-do)
  79. (values woke? (- (car next) time)))
  80. (else
  81. ((cddr next))
  82. (loop (cdr to-do) #t)))))))))