interrupts.scm 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. ;; Fibers: cooperative, event-driven user-space threads.
  2. ;;;; Copyright (C) 2016 Free Software Foundation, Inc.
  3. ;;;;
  4. ;;;; This library is free software; you can redistribute it and/or
  5. ;;;; modify it under the terms of the GNU Lesser General Public
  6. ;;;; License as published by the Free Software Foundation; either
  7. ;;;; version 3 of the License, or (at your option) any later version.
  8. ;;;;
  9. ;;;; This library is distributed in the hope that it will be useful,
  10. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;;; Lesser General Public License for more details.
  13. ;;;;
  14. ;;;; You should have received a copy of the GNU Lesser General Public
  15. ;;;; License along with this library; if not, write to the Free Software
  16. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;;;
  18. (define-module (fibers interrupts)
  19. #:use-module (ice-9 threads)
  20. #:use-module (fibers posix-clocks)
  21. #:export (with-interrupts))
  22. ;; Cause periodic interrupts via `setitimer' and SIGPROF. This
  23. ;; implementation has the disadvantage that it prevents `setitimer'
  24. ;; from being used for other purposes like profiling.
  25. (define (with-interrupts/sigprof hz pred interrupt thunk)
  26. (let ((prev #f))
  27. (define (sigprof-handler _)
  28. (when (pred) (interrupt)))
  29. (define (start-preemption!)
  30. (let ((period-usecs (inexact->exact (round (/ 1e6 hz)))))
  31. (set! prev (car (sigaction SIGPROF sigprof-handler)))
  32. (setitimer ITIMER_PROF 0 period-usecs 0 period-usecs)))
  33. (define (stop-preemption!)
  34. (setitimer ITIMER_PROF 0 0 0 0)
  35. (sigaction SIGPROF prev))
  36. (dynamic-wind start-preemption! thunk stop-preemption!)))
  37. ;; Cause periodic interrupts via a separate thread sleeping on a clock
  38. ;; driven by the current thread's CPU time.
  39. (define (with-interrupts/thread-cputime hz pred interrupt thunk)
  40. (let ((interrupt-thread #f)
  41. (target-thread (current-thread))
  42. (clockid (pthread-getcpuclockid (pthread-self))))
  43. (define (start-preemption!)
  44. (let ((period-nsecs (inexact->exact (round (/ 1e9 hz)))))
  45. (set! interrupt-thread
  46. (call-with-new-thread
  47. (lambda ()
  48. ;; It's possible that the thread has already exited
  49. ;; before we start, and the clock-nanosleep fails
  50. ;; directly. Or who knows what happens when the target
  51. ;; thread dies during the nanosleep? Anyway just wrap
  52. ;; the whole thing in a catch-all and punt.
  53. (false-if-exception
  54. (let lp ()
  55. (clock-nanosleep clockid period-nsecs)
  56. (when (pred)
  57. (system-async-mark interrupt target-thread))
  58. (lp))))))))
  59. (define (stop-preemption!)
  60. (cancel-thread interrupt-thread))
  61. (dynamic-wind start-preemption! thunk stop-preemption!)))
  62. (define (with-interrupts hz pred interrupt thunk)
  63. "Run @var{sched} until there are no more fibers ready to run, no
  64. file descriptors being waited on, and no more timers pending to run.
  65. Return zero values."
  66. (cond
  67. ((zero? hz) (thunk))
  68. ((provided? 'threads)
  69. (with-interrupts/thread-cputime hz pred interrupt thunk))
  70. (else
  71. (with-interrupts/sigprof hz pred interrupt thunk))))