This file is indexed.

/usr/share/scheme48-1.9/posix/signal.scm is in scheme48 1.9-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Marcus Crestani,
; Roderic Morris, Will Noble

; 3.3 Signals

(import-dynamic-externals "=scheme48external/posix")

; int kill(pid_t pid, int sig)
;
; Also signal sets, sigaction(), blocked and waiting signals,
; alarm(), pause(), sleep().
;
; There are two signal record types, one for signals whose names we know and
; one for those which are anonymous.  The anonymous signals cannot be dumped
; in images, because we have no way of knowing if they will have the same
; meaning on startup.
;
; Only the C code can determine which names correspond to signals in the current
; OS, and then only at compile time by doing
;   #ifdef SIGSTKFLT		/* or whatever the name is */
;     ...
;   #endif
; So what we do is construct a C file that checks for the presence of all of the
; signals we have ever heard of.  Any others have to be anonymous and cannot be
; saved in images.

(define-record-type unnamed-signal :unnamed-signal
  (make-unnamed-signal resume-value os-number queues)
  unnamed-signal?
  (resume-value unnamed-signal-resume-value)
  (os-number    unnamed-signal-os-number)
  (queues	unnamed-signal-queues set-unnamed-signal-queues!))

(define-record-discloser :unnamed-signal
  (lambda (u-s)
    (list 'signal (unnamed-signal-os-number u-s))))

; These are not meaningful after a dump (because the value may not have the
; same meaning on the OS on which we are resumed).

(define-record-resumer :unnamed-signal #f)

(define *unnamed-signals* #f)

(define-finite-type signal :named-signal
  (queues)
  named-signal?
  named-signals
  named-signal-name
  named-signal-index
  (os-number named-signal-os-number set-named-signal-os-number!)
  (queues named-signal-queues set-named-signal-queues!)
  (; POSIX
   (abrt '())	; abort - abnormal termination (as by abort())
   (alrm '())	; alarm - timeout signal (as by alarm())
   (fpe  '())	; floating point exception
   (hup  '())	; hangup - hangup on controlling terminal or death of
   		;  controlling process
   (ill  '())	; illegal instruction
   (int  '())	; interrupt - interaction attention
   (kill '())	; kill - termination signal, cannot be caught or ignored
   (pipe '())	; pipe - write on a pipe with no readers
   (quit '())	; quit - interaction termination
   (segv '())	; segmentation violation - invalid memory reference
   (term '())	; termination - termination signal
   (usr1 '())	; user1 - for use by applications
   (usr2 '())	; user2 - for use by applications
   (chld '())	; child - child process stopped or terminated
   (cont '())	; continue - continue if stopped
   (stop '())	; stop - cannot be caught or ignored
   (tstp '())	; interactive stop
   (ttin '())	; read from control terminal attempted by background process
   (ttou '())	; write to control terminal attempted by background process
   (bus  '())	; bus error - access to undefined portion of memory

   ; Additional signals from (RedHat) Linux
   (trap   '())	; trace or breakpoint trap
   (iot    '())	; IOT trap - a synonym for ABRT
   (emt    '())	; ambulance?
   (sys    '())	; bad argument to routine	(SVID)
   (stkflt '())	; stack fault on coprocessor
   (urg    '())	; urgent condition on socket	(4.2 BSD)
   (io     '())	; I/O now possible		(4.2 BSD)
   (poll   '())	; A synonym for SIGIO		(System V)
   (cld    '())	; A synonym for SIGCHLD
   (xcpu   '())	; CPU time limit exceeded	(4.2 BSD)
   (xfsz   '())	; File size limit exceeded	(4.2 BSD)
   (vtalrm '())	; Virtual alarm clock		(4.2 BSD)
   (prof   '())	; Profile alarm clock
   (pwr    '())	; Power failure			(System V)
   (info   '())	; A synonym for SIGPWR
   (lost   '())	; File lock lost
   (winch  '())	; Window resize signal		(4.3 BSD, Sun)
   (unused '())	; Unused signal
   ))

(define-record-discloser :named-signal
  (lambda (n-s)
    (list 'signal (named-signal-name n-s))))

; Find the signal called `name'.

(define (name->signal name)
  (if (not (symbol? name))
      (assertion-violation 'name->signal "argument not a symbol" name)
      (let loop ((i 0))
	(cond ((= i (vector-length named-signals))
	       #f)
	      ((eq? name
		    (named-signal-name
		      (vector-ref named-signals i)))
	       (vector-ref named-signals i))
	      (else
	       (loop (+ i 1)))))))

(define (get-unnamed-signal signum)
  (call-with-current-continuation
   (lambda (return)
     (walk-population
      (lambda (sig)
	(if (= signum (unnamed-signal-os-number sig)) (return sig)))
      *unnamed-signals*)
     (let ((sig (make-unnamed-signal 'nonportable-signal signum '())))
       (add-to-population! sig *unnamed-signals*)
       sig))))

(define (integer->signal signum)
  (let loop ((i 0))
    (if (= i (vector-length named-signals))
	(get-unnamed-signal signum)
	(let ((s (vector-ref named-signals i)))
	  (if (= signum (named-signal-os-number s))
	      s
	      (loop (+ i 1)))))))

; Write the contents of the C array mapping canonical signal numbers
; to os signal numbers.
(define (write-c-signal-include-file filename)
  (call-with-output-file filename
    (lambda (out)
      (do ((i 0 (+ i 1)))
	  ((= i (vector-length named-signals)))
	(let ((name (symbol->string
		     (named-signal-name
		      (vector-ref named-signals i)))))
	  (display (string-append
		    "#ifdef SIG" (string-upcase name) newline-string
		    "  SIG" (string-upcase name) "," newline-string
		    "#else" newline-string
		    "  -1," newline-string
		    "#endif" newline-string)
		   out))))))

(define newline-string (list->string '(#\newline)))

(define (string-map proc)
  (lambda (list)
    (list->string (map proc (string->list list)))))

(define string-upcase   (string-map char-upcase))
(define string-downcase (string-map char-downcase))

;----------------
; Dispatching on the two kinds of signals.

(define (signal? x)
  (or (named-signal? x)
      (unnamed-signal? x)))

(define (signal-name x)
  (cond ((named-signal? x)
	 (named-signal-name x))
	((unnamed-signal? x)
	 #f)
	(else
	 (assertion-violation 'signal-name "argument not a signal" x))))

(define (signal-os-number x)
  (cond ((named-signal? x)
	 (named-signal-os-number x))
	((unnamed-signal? x)
	 (unnamed-signal-os-number x))
	(else
	 (assertion-violation 'signal-os-number "argument not a signal" x))))

(define (signal-queues x)
  (cond ((named-signal? x)
	 (named-signal-queues x))
	((unnamed-signal? x)
	 (unnamed-signal-queues x))
	(else
	 (assertion-violation 'signal-queues "argument not a signal" x))))

(define (set-signal-queues! x qs)
  (cond ((named-signal? x)
	 (set-named-signal-queues! x qs))
	((unnamed-signal? x)
	 (set-unnamed-signal-queues! x qs))
	(else
	 (assertion-violation 'set-signal-queues! "argument not a signal" x qs))))

(define (clean-signal-queues x)
  (let* ((old (signal-queues x))
	 (new (clean-weaks old)))
    (if (not (eq? new old))
	(set-signal-queues! x new))
    new))

; Two signals are the same if they are exactly the same or if they are
; both named signals and have the same (non-#F) os number.

(define (signal=? s1 s2)
  (or (eq? s1 s2)
      (and (named-signal? s1)
	   (named-signal? s2)
	   (named-signal-os-number s1)
	   (eq? (named-signal-os-number s1)
		(named-signal-os-number s2)))))

;----------------
; What we contribute to and receive from the C layer.

(define-exported-binding "posix-signals-vector" named-signals)

(import-lambda-definition-2 initialize-named-signals ()
			  "posix_initialize_named_signals")
(import-lambda-definition-2 request-interrupts! (os-number)
			  "posix_request_interrupts")
(import-lambda-definition-2 cancel-interrupt-request! (os-number)
			  "posix_cancel_interrupt_request")

;----------------
; A vector mapping os-signal numbers to signals and add to it any signals
; that have existing signal queues.

(define os-signal-map (make-session-data-slot! #f))

; Initializing the above vector.

(define (initialize-signals)
  (set! *unnamed-signals* (make-population))
  (let ((ints (set-enabled-interrupts! no-interrupts)))
    (initialize-named-signals)
    (let* ((named (vector->list named-signals))
	   (size (+ 1 (apply max
			     (map (lambda (signal)
				    (or (signal-os-number signal)
					-1))
				  named))))
	   (mapper (make-vector size '())))
      (for-each (lambda (signal)
		  (if (and (signal-os-number signal)
			   (not (null? (clean-signal-queues signal))))
		      (let* ((number (signal-os-number signal))
			     (old (vector-ref mapper number)))
			(if (null? old)
			    (request-interrupts! number))
			(vector-set! mapper number (cons signal old)))))
		named)
      (session-data-set! os-signal-map mapper)
      (maybe-request-os-signal! (signal chld))
      (set-enabled-interrupts! ints)))  
  (set-interrupt-handler! (enum interrupt os-signal) os-signal-handler))

; Add SIGNAL to the list of those waiting for that signal number from the OS.
; If this is the first such we tell the OS we want the signal.
;
; Called with interrupts disabled.

(define (maybe-request-os-signal! signal)
  (let* ((os-number (signal-os-number signal))
	 (mapper (session-data-ref os-signal-map))
	 (mapper (if (< os-number (vector-length mapper))
		     mapper
		     (let ((new (make-vector (+ os-number 1) '())))
		       (do ((i 0 (+ i 1)))
			   ((= i (vector-length mapper)))
			 (vector-set! new i (vector-ref mapper i)))
		       (session-data-set! os-signal-map new)
		       new)))
	 (old (vector-ref mapper os-number)))
    (if (not (memq signal old))
	(begin
	  (vector-set! mapper os-number (cons signal old))
	  (if (null? old)
	      (request-interrupts! os-number))))))

;----------------
; Sending a signal to a process.

(import-lambda-definition-2 posix-kill (pid signal) "posix_kill")

(define (signal-process pid signal)
  (posix-kill (process-id->integer pid) (signal-os-number signal)))

;----------------
; Handling signals sent to the current process.  Runs with interrupts disabled.
;
; SIGCHLD has meaning for the POSIX layer, nothing else does.  The proc code
; could create a queue to receive SIGCHLD signals, but that would require a
; separate thread.  That would be too much mechanism.
;
; Find the list of signals for OS-NUMBER and then deliver the signal to each.
; If no one really wants it we tell the OS layer to stop delivering it to us.

(define (os-signal-handler os-number enabled-interrupts)
  (if (= os-number (signal-os-number (signal chld)))
      (process-terminated-children))
  (let ((mapper (session-data-ref os-signal-map)))
    (if (<= (vector-length mapper)
	    os-number)
	(cancel-interrupt-request! os-number)
	(let ((signals (vector-ref mapper os-number)))
	  (let loop ((signals signals)
		     (okay '()))
	    (cond ((null? signals)
		   (if (null? okay)
		       (cancel-interrupt-request! os-number))
		   (vector-set! mapper os-number okay))
		  (else
		   (loop (cdr signals)
			 (if (or (deliver-signal (car signals))
                                 ;; Never cancel interrupts for SIGCHLD.
                                 (signal=? (car signals) (signal chld)))
			     (cons (car signals) okay)
			     okay)))))))))

; Send SIGNAL to each of its queues.

(define (deliver-signal signal)
  (let loop ((queues (signal-queues signal))
	     (okay '()))
    (cond ((null? queues)
	   (set-signal-queues! signal okay)
	   (not (null? okay)))
	  (else
	   (loop (cdr queues)
		 (cond ((weak-pointer-ref (car queues))
			=> (lambda (queue)
			     (if (memq signal
				       (signal-queue-signals queue))
				 (begin
				   (pipe-push! (signal-queue-pipe queue)
					       signal)
				   (cons (car queues)
					 okay))
				 okay)))
		       (else
			okay)))))))

; Adding and removing QUEUE to the list of queues receiving SIGNAL.
;
; 1. check to see if it is already doing so.
; 2. add the signal to the queue and the (weak) queue to the signal
; 3. check that the os-signal has been requested

(define (add-signal-queue-signal! queue signal)
  (let ((ints (set-enabled-interrupts! no-interrupts)))
    (if (not (memq signal (signal-queue-signals queue)))
	(begin
	  (set-signal-queues! signal
			      (cons (signal-queue-weak queue)
				    (signal-queues signal)))
	  (set-signal-queue-signals! queue
				     (cons signal
					   (signal-queue-signals queue)))
	  (maybe-request-os-signal! signal)))
    (set-enabled-interrupts! ints)))

; Undo the above actions.  The signal will be un-requested the next time it
; is delivered.

(define (remove-signal-queue-signal! queue signal)
  (let ((ints (set-enabled-interrupts! no-interrupts)))
    (if (memq signal (signal-queue-signals queue))
	(begin
	  (set-signal-queues! signal (delq (signal-queue-weak queue)
					   (signal-queues signal)))
	  (set-signal-queue-signals! queue
				     (delq signal
					   (signal-queue-signals queue)))))
    (set-enabled-interrupts! ints)))

(define (delq signal signals)
  (let recur ((signals signals))
    (cond ((null? signals)
	   '())
	  ((eq? signal (car signals))
	   (cdr signals))
	  (else
	   (cons (car signals)
		 (recur (cdr signals)))))))

; A signal queue has:
;  - list of the the signals of interest
;  - pipe for received signals
;  - stashed weak pointer for adding to signals' queue lists

(define-record-type signal-queue :signal-queue
  (really-make-signal-queue signals pipe)
  signal-queue?
  (signals signal-queue-signals set-signal-queue-signals!)
  (pipe    signal-queue-pipe)
  (weak    signal-queue-weak set-signal-queue-weak!))

; Exported version that copies the list.

(define (signal-queue-monitored-signals queue)
  (apply list (signal-queue-signals queue)))

(define (make-signal-queue signals)
  (let ((queue (really-make-signal-queue '() (make-pipe))))
    (set-signal-queue-weak! queue (make-weak-pointer queue))
    (for-each (lambda (signal)
		(add-signal-queue-signal! queue signal))
	      signals)
    queue))

; (read-signal <signal-queue>) -> <signal> is analogous to
; (read-char <input-port>) -> <char>
; MAYBE-READ-SIGNAL returns #f if there are no signals currently on the queue.

(define (dequeue-signal! queue)
  (find-next-signal queue pipe-read!))

(define (maybe-dequeue-signal! queue)
  (find-next-signal queue pipe-maybe-read!))

(define (find-next-signal queue pipe-reader)
  (let ((pipe (signal-queue-pipe queue)))
    (let loop ()
      (let ((signal (pipe-reader pipe)))
	(cond ((not signal)
	       #f)
	      ((memq signal (signal-queue-signals queue))
	       signal)
	      (else
	       (loop)))))))

;----------------
; Returns the weak-pointers in WEAKS that still have values.  No copying is done
; if all have values.

(define (clean-weaks weaks)
  (let recur ((weaks weaks) (top? #t))
    (cond ((null? weaks)
	   (if top? '() #f))
	  ((weak-pointer-ref (car weaks))
	   (let ((rest (recur (cdr weaks) #f)))
	     (if rest
		 (cons (car weaks)
		       rest)
		 weaks)))
	  (else
	   (recur (cdr weaks) #t)))))

;----------------
; Initialize signals now ...

(initialize-signals)

; ... and on later startups.

(define-reinitializer signal-reinitializer initialize-signals)