signal.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. ; Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; 3.3 Signals
  3. ;
  4. ; int kill(pid_t pid, int sig)
  5. ;
  6. ; Also signal sets, sigaction(), blocked and waiting signals,
  7. ; alarm(), pause(), sleep().
  8. ;
  9. ; There are two signal record types, one for signals whose names we know and
  10. ; one for those which are anonymous. The anonymous signals cannot be dumped
  11. ; in images, because we have no way of knowing if they will have the same
  12. ; meaning on startup.
  13. ;
  14. ; Only the C code can determine which names correspond to signals in the current
  15. ; OS, and then only at compile time by doing
  16. ; #ifdef SIGSTKFLT /* or whatever the name is */
  17. ; ...
  18. ; #endif
  19. ; So what we do is construct a C file that checks for the presence of all of the
  20. ; signals we have ever heard of. Any others have to be anonymous and cannot be
  21. ; saved in images.
  22. (define-record-type unnamed-signal :unnamed-signal
  23. (unnamed-signals-are-made-by-c-code)
  24. unnamed-signal?
  25. (resume-value unnamed-signal-resume-value)
  26. (os-number unnamed-signal-os-number)
  27. (queues unnamed-signal-queues set-unnamed-signal-queues!))
  28. (define-record-discloser :unnamed-signal
  29. (lambda (u-s)
  30. (list 'signal (unnamed-signal-os-number u-s))))
  31. ; These are not meaningful after a dump (because the value may not have the
  32. ; same meaning on the OS on which we are resumed).
  33. (define-record-resumer :unnamed-signal #f)
  34. (define-finite-type signal :named-signal
  35. (queues)
  36. named-signal?
  37. named-signals
  38. named-signal-name
  39. named-signal-index
  40. (os-number named-signal-os-number set-named-signal-os-number!)
  41. (queues named-signal-queues set-named-signal-queues!)
  42. (; POSIX
  43. (abrt '()) ; abort - abnormal termination (as by abort())
  44. (alrm '()) ; alarm - timeout signal (as by alarm())
  45. (fpe '()) ; floating point exception
  46. (hup '()) ; hangup - hangup on controlling terminal or death of
  47. ; controlling process
  48. (ill '()) ; illegal instruction
  49. (int '()) ; interrupt - interaction attention
  50. (kill '()) ; kill - termination signal, cannot be caught or ignored
  51. (pipe '()) ; pipe - write on a pipe with no readers
  52. (quit '()) ; quit - interaction termination
  53. (segv '()) ; segmentation violation - invalid memory reference
  54. (term '()) ; termination - termination signal
  55. (usr1 '()) ; user1 - for use by applications
  56. (usr2 '()) ; user2 - for use by applications
  57. (chld '()) ; child - child process stopped or terminated
  58. (cont '()) ; continue - continue if stopped
  59. (stop '()) ; stop - cannot be caught or ignored
  60. (tstp '()) ; interactive stop
  61. (ttin '()) ; read from control terminal attempted by background process
  62. (ttou '()) ; write to control terminal attempted by background process
  63. (bus '()) ; bus error - access to undefined portion of memory
  64. ; Additional signals from (RedHat) Linux
  65. (trap '()) ; trace or breakpoint trap
  66. (iot '()) ; IOT trap - a synonym for ABRT
  67. (emt '()) ; ambulance?
  68. (sys '()) ; bad argument to routine (SVID)
  69. (stkflt '()) ; stack fault on coprocessor
  70. (urg '()) ; urgent condition on socket (4.2 BSD)
  71. (io '()) ; I/O now possible (4.2 BSD)
  72. (poll '()) ; A synonym for SIGIO (System V)
  73. (cld '()) ; A synonym for SIGCHLD
  74. (xcpu '()) ; CPU time limit exceeded (4.2 BSD)
  75. (xfsz '()) ; File size limit exceeded (4.2 BSD)
  76. (vtalrm '()) ; Virtual alarm clock (4.2 BSD)
  77. (prof '()) ; Profile alarm clock
  78. (pwr '()) ; Power failure (System V)
  79. (info '()) ; A synonym for SIGPWR
  80. (lost '()) ; File lock lost
  81. (winch '()) ; Window resize signal (4.3 BSD, Sun)
  82. (unused '()) ; Unused signal
  83. ))
  84. (define-record-discloser :named-signal
  85. (lambda (n-s)
  86. (list 'signal (named-signal-name n-s))))
  87. ; Find the signal called `name'.
  88. (define (name->signal name)
  89. (if (not (symbol? name))
  90. (call-error "argument not a symbol" name->signal name)
  91. (let loop ((i 0))
  92. (cond ((= i (vector-length named-signals))
  93. #f)
  94. ((eq? name
  95. (named-signal-name
  96. (vector-ref named-signals i)))
  97. (vector-ref named-signals i))
  98. (else
  99. (loop (+ i 1)))))))
  100. ;----------------
  101. ; Code to produce a C include file that checks whether each signal is defined.
  102. ; The output file looks like:
  103. ;
  104. ; signal_count_is(<number of signals>);
  105. ; #ifdef SIGABRT
  106. ; signal_map[0] = SIGABRT;
  107. ; #endif
  108. ; #ifdef SIGALRM
  109. ; signal_map[1] = SIGALRM;
  110. ; #endif
  111. ; ...
  112. (define (write-c-signal-include-file filename)
  113. (call-with-output-file filename
  114. (lambda (out)
  115. (display (string-append "signal_count_is("
  116. (number->string (vector-length named-signals))
  117. ");"
  118. newline-string)
  119. out)
  120. (do ((i 0 (+ i 1)))
  121. ((= i (vector-length named-signals)))
  122. (let ((name (symbol->string
  123. (named-signal-name
  124. (vector-ref named-signals i)))))
  125. (display (string-append "#ifdef SIG" (string-upcase name)
  126. newline-string
  127. "signal_map["
  128. (number->string i)
  129. "] = SIG"
  130. (string-upcase name)
  131. ";"
  132. newline-string
  133. "#endif"
  134. newline-string)
  135. out))))))
  136. (define newline-string (list->string '(#\newline)))
  137. (define (string-map proc)
  138. (lambda (list)
  139. (list->string (map proc (string->list list)))))
  140. (define string-upcase (string-map char-upcase))
  141. (define string-downcase (string-map char-downcase))
  142. ;----------------
  143. ; Dispatching on the two kinds of signals.
  144. (define (signal? x)
  145. (or (named-signal? x)
  146. (unnamed-signal? x)))
  147. (define (signal-name x)
  148. (cond ((named-signal? x)
  149. (named-signal-name x))
  150. ((unnamed-signal? x)
  151. #f)
  152. (else
  153. (call-error "argument not a signal" signal-name x))))
  154. (define (signal-os-number x)
  155. (cond ((named-signal? x)
  156. (named-signal-os-number x))
  157. ((unnamed-signal? x)
  158. (unnamed-signal-os-number x))
  159. (else
  160. (call-error "argument not a signal" signal-os-number x))))
  161. (define (signal-queues x)
  162. (cond ((named-signal? x)
  163. (named-signal-queues x))
  164. ((unnamed-signal? x)
  165. (unnamed-signal-queues x))
  166. (else
  167. (call-error "argument not a signal" signal-queues x))))
  168. (define (set-signal-queues! x qs)
  169. (cond ((named-signal? x)
  170. (set-named-signal-queues! x qs))
  171. ((unnamed-signal? x)
  172. (set-unnamed-signal-queues! x qs))
  173. (else
  174. (call-error "argument not a signal" set-signal-queues! x qs))))
  175. (define (clean-signal-queues x)
  176. (let* ((old (signal-queues x))
  177. (new (clean-weaks old)))
  178. (if (not (eq? new old))
  179. (set-signal-queues! x new))
  180. new))
  181. ; Two signals are the same if they are exactly the same or if they are
  182. ; both named signals and have the same (non-#F) os number.
  183. (define (signal=? s1 s2)
  184. (or (eq? s1 s2)
  185. (and (named-signal? s1)
  186. (named-signal? s2)
  187. (named-signal-os-number s1)
  188. (eq? (named-signal-os-number s1)
  189. (named-signal-os-number s2)))))
  190. ;----------------
  191. ; What we contribute to and receive from the C layer.
  192. (define-exported-binding "posix-signals-vector" named-signals)
  193. (define-exported-binding "posix-named-signal-type" :named-signal)
  194. (define-exported-binding "posix-unnamed-signal-type" :unnamed-signal)
  195. (define-exported-binding "posix-unnamed-signal-marker" 'nonportable-signal)
  196. (import-lambda-definition integer->signal (int) "posix_integer_to_signal")
  197. (import-lambda-definition initialize-named-signals ()
  198. "posix_initialize_named_signals")
  199. (import-lambda-definition request-interrupts! (os-number)
  200. "posix_request_interrupts")
  201. (import-lambda-definition cancel-interrupt-request! (os-number)
  202. "posix_cancel_interrupt_request")
  203. ;----------------
  204. ; A vector mapping os-signal numbers to signals and add to it any signals
  205. ; that have existing signal queues.
  206. (define os-signal-map (make-session-data-slot! #f))
  207. ; Initializing the above vector.
  208. (define (initialize-signals)
  209. (let ((ints (set-enabled-interrupts! no-interrupts)))
  210. (initialize-named-signals)
  211. (let* ((named (vector->list named-signals))
  212. (size (+ 1 (apply max
  213. (map (lambda (signal)
  214. (or (signal-os-number signal)
  215. -1))
  216. named))))
  217. (mapper (make-vector size '())))
  218. (for-each (lambda (signal)
  219. (if (and (signal-os-number signal)
  220. (not (null? (clean-signal-queues signal))))
  221. (let* ((number (signal-os-number signal))
  222. (old (vector-ref mapper number)))
  223. (if (null? old)
  224. (request-interrupts! number))
  225. (vector-set! mapper number (cons signal old)))))
  226. named)
  227. (session-data-set! os-signal-map mapper)
  228. (set-enabled-interrupts! ints))))
  229. ; Add SIGNAL to the list of those waiting for that signal number from the OS.
  230. ; If this is the first such we tell the OS we want the signal.
  231. ;
  232. ; Called with interrupts disabled.
  233. (define (maybe-request-os-signal! signal)
  234. (let* ((os-number (signal-os-number signal))
  235. (mapper (session-data-ref os-signal-map))
  236. (mapper (if (< os-number (vector-length mapper))
  237. mapper
  238. (let ((new (make-vector (+ os-number 1) '())))
  239. (do ((i 0 (+ i 1)))
  240. ((= i (vector-length mapper)))
  241. (vector-set! new i (vector-ref mapper i)))
  242. (session-data-set! os-signal-map new)
  243. new)))
  244. (old (vector-ref mapper os-number)))
  245. (if (not (memq signal old))
  246. (begin
  247. (vector-set! mapper os-number (cons signal old))
  248. (if (null? old)
  249. (request-interrupts! os-number))))))
  250. ;----------------
  251. ; Sending a signal to a process.
  252. (import-lambda-definition signal-process (pid signal) "posix_kill")
  253. ;----------------
  254. ; Handling signals sent to the current process. Runs with interrupts disabled.
  255. ;
  256. ; SIGCHLD has meaning for the POSIX layer, nothing else does. The proc code
  257. ; could create a queue to receive SIGCHLD signals, but that would require a
  258. ; separate thread. That would be too much mechanism.
  259. ;
  260. ; Find the list of signals for OS-NUMBER and then deliver the signal to each.
  261. ; If no one really wants it we tell the OS layer to stop delivering it to us.
  262. (define (os-signal-handler os-number enabled-interrupts)
  263. (if (= os-number (signal-os-number (signal chld)))
  264. (process-terminated-children))
  265. (let ((mapper (session-data-ref os-signal-map)))
  266. (if (<= (vector-length mapper)
  267. os-number)
  268. (cancel-interrupt-request! os-number)
  269. (let ((signals (vector-ref mapper os-number)))
  270. (let loop ((signals signals)
  271. (okay '()))
  272. (cond ((null? signals)
  273. (if (null? okay)
  274. (cancel-interrupt-request! os-number))
  275. (vector-set! mapper os-number okay))
  276. (else
  277. (loop (cdr signals)
  278. (if (deliver-signal (car signals))
  279. (cons (car signals) okay)
  280. okay)))))))))
  281. (set-interrupt-handler! (enum interrupt os-signal) os-signal-handler)
  282. ; Send SIGNAL to each of its queues.
  283. (define (deliver-signal signal)
  284. (let loop ((queues (signal-queues signal))
  285. (okay '()))
  286. (cond ((null? queues)
  287. (set-signal-queues! signal okay)
  288. (not (null? okay)))
  289. (else
  290. (loop (cdr queues)
  291. (cond ((weak-pointer-ref (car queues))
  292. => (lambda (queue)
  293. (if (memq signal
  294. (signal-queue-signals queue))
  295. (begin
  296. (pipe-push! (signal-queue-pipe queue)
  297. signal)
  298. (cons (car queues)
  299. okay))
  300. okay)))
  301. (else
  302. okay)))))))
  303. ; Adding and removing QUEUE to the list of queues receiving SIGNAL.
  304. ;
  305. ; 1. check to see if it is already doing so.
  306. ; 2. add the signal to the queue and the (weak) queue to the signal
  307. ; 3. check that the os-signal has been requested
  308. (define (add-signal-queue-signal! queue signal)
  309. (let ((ints (set-enabled-interrupts! no-interrupts)))
  310. (if (not (memq signal (signal-queue-signals queue)))
  311. (begin
  312. (set-signal-queues! signal
  313. (cons (signal-queue-weak queue)
  314. (signal-queues signal)))
  315. (set-signal-queue-signals! queue
  316. (cons signal
  317. (signal-queue-signals queue)))
  318. (maybe-request-os-signal! signal)))
  319. (set-enabled-interrupts! ints)))
  320. ; Undo the above actions. The signal will be un-requested the next time it
  321. ; is delivered.
  322. (define (remove-signal-queue-signal! queue signal)
  323. (let ((ints (set-enabled-interrupts! no-interrupts)))
  324. (if (memq signal (signal-queue-signals queue))
  325. (begin
  326. (set-signal-queues! signal (delq (signal-queue-weak queue)
  327. (signal-queues signal)))
  328. (set-signal-queue-signals! signal
  329. (delq signal
  330. (signal-queue-signals queue)))))
  331. (set-enabled-interrupts! ints)))
  332. (define (delq signal signals)
  333. (let recur ((signals signals))
  334. (cond ((null? signals)
  335. '())
  336. ((eq? signal (car signals))
  337. (cdr signals))
  338. (else
  339. (cons (car signals)
  340. (recur (cdr signals)))))))
  341. ; A signal queue has:
  342. ; - list of the the signals of interest
  343. ; - pipe for received signals
  344. ; - stashed weak pointer for adding to signals' queue lists
  345. (define-record-type signal-queue :signal-queue
  346. (really-make-signal-queue signals pipe)
  347. signal-queue?
  348. (signals signal-queue-signals set-signal-queue-signals!)
  349. (pipe signal-queue-pipe)
  350. (weak signal-queue-weak set-signal-queue-weak!))
  351. ; Exported version that copies the list.
  352. (define (signal-queue-monitored-signals queue)
  353. (apply list (signal-queue-signals queue)))
  354. (define (make-signal-queue signals)
  355. (let ((queue (really-make-signal-queue '() (make-pipe))))
  356. (set-signal-queue-weak! queue (make-weak-pointer queue))
  357. (for-each (lambda (signal)
  358. (add-signal-queue-signal! queue signal))
  359. signals)
  360. queue))
  361. ; (read-signal <signal-queue>) -> <signal> is analogous to
  362. ; (read-char <input-port>) -> <char>
  363. ; MAYBE-READ-SIGNAL returns #f if there are no signals currently on the queue.
  364. (define (dequeue-signal! queue)
  365. (find-next-signal queue pipe-read!))
  366. (define (maybe-dequeue-signal! queue)
  367. (find-next-signal queue pipe-maybe-read!))
  368. (define (find-next-signal queue pipe-reader)
  369. (let ((pipe (signal-queue-pipe queue)))
  370. (let loop ()
  371. (let ((signal (pipe-reader pipe)))
  372. (cond ((not signal)
  373. #f)
  374. ((memq signal (signal-queue-signals queue))
  375. signal)
  376. (else
  377. (loop)))))))
  378. ;----------------
  379. ; Returns the weak-pointers in WEAKS that still have values. No copying is done
  380. ; if all have values.
  381. (define (clean-weaks weaks)
  382. (let recur ((weaks weaks) (top? #t))
  383. (cond ((null? weaks)
  384. (if top? '() #f))
  385. ((weak-pointer-ref (car weaks))
  386. (let ((rest (recur (cdr weaks) #f)))
  387. (if rest
  388. (cons (car weaks)
  389. rest)
  390. weaks)))
  391. (else
  392. (recur (cdr weaks) #t)))))
  393. ;----------------
  394. ; Initialize signals now ...
  395. (initialize-signals)
  396. ; ... and on later startups.
  397. (define-reinitializer signal-reinitializer initialize-signals)