~ chicken-core (chicken-5) 61caf8a1c8cd50f7654f614d81c3225e5f72bc0a
commit 61caf8a1c8cd50f7654f614d81c3225e5f72bc0a
Author: felix <felix@call-with-current-continuation.org>
AuthorDate: Fri Jul 28 13:12:31 2023 +0200
Commit: felix <felix@call-with-current-continuation.org>
CommitDate: Fri Jul 28 13:12:31 2023 +0200
Provide new thread-safe API for POSIX signals and deprecate old one
diff --git a/DEPRECATED b/DEPRECATED
index 6c2a009e..c8d19bd1 100644
--- a/DEPRECATED
+++ b/DEPRECATED
@@ -5,6 +5,9 @@ Deprecated functions and variables
- read/source-info from the internal, undocumented module
(chicken compiler support) is deprecated. Instead, use
read-with-source-info from (chicken syntax).
+- "set-signal-handler!" and "signal-handler" have been deprecated
+ in favor of "make-signal-handler" and "ignore-signal" which are
+ better suited in a multithreaded environment.
5.2.1
- current-milliseconds and its C implementations C_milliseconds and
diff --git a/NEWS b/NEWS
index 19d2f30e..19686e11 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@
the first non-runtime option or after "-:", whichever comes first.
- Core libraries
+ - Added new thread-safe API for POSIX signals ("make-signal-handler",
+ "signal-ignore" and "signal-default") and deprecated the existing one.
- Added "make-finalizer" to execute finalizers in a thread-safe
manner.
- Added weak pairs to (chicken base), with similar behaviour to Chez Scheme.
diff --git a/manual/Module (chicken process signal) b/manual/Module (chicken process signal)
index 8e40cfdc..a640f165 100644
--- a/manual/Module (chicken process signal)
+++ b/manual/Module (chicken process signal)
@@ -19,34 +19,41 @@ that's the case, the description contains a note.
Sets an internal timer to raise the {{signal/alrm}}
after {{SECONDS}} are elapsed. You can use the
-{{set-signal-handler!}} procedure to write a handler for this signal.
+{{make-signal-handler}} procedure to write a handler for this signal.
'''NOTE''': On native Windows builds (all except cygwin), this
procedure is unimplemented and will raise an error.
-=== signal-handler
-=== set-signal-handler!
+=== make-signal-handler
-<procedure>(signal-handler SIGNUM)</procedure>
+<procedure>(make-signal-handler SIGNUM ...)</procedure>
-Returns the signal handler for the code {{SIGNUM}} or {{#f}}.
+Establishes a handler for the POSIX signals with the numbers {{SIGNUM ...}} and returns
+a procedure of zero or one argument. Should one of the given signals be raised, then it will be stored in a
+queue. Invoking the procedure returned by {{make-signal-handler}} with zero arguments or
+with the argument {{#f}} will remove the oldest
+entry in the queue and return it to the caller. Invoking the procedure with argument {{#t}} when no signal was
+raised since the creation of the signal handler or the most recent call to the handler
+will result in suspending the execution until one of the signals given in {{SIGNUM ...}}
+occurs.
-<procedure>(set-signal-handler! SIGNUM PROC)</procedure>
+Notes:
-Establishes the procedure of one argument {{PROC}} as the handler
-for the signal with the code {{SIGNUM}}. {{PROC}} is called
-with the signal number as its sole argument. If the argument {{PROC}} is {{#f}}
-then any signal handler will be removed, and the corresponding signal set to {{SIG_IGN}}.
+* when signals arrive in quick succession (specifically, before the handler for a signal has been started), then signals will be queued (up to a certain limit); the order in which the queued signals will be handled is not specified
-Notes
+* Any signal handlers for the signals {{signal/segv}}, {{signal/bus}}, {{signal/fpe}} and {{signal/ill}} will be ignored and these signals will always trigger an exception, unless the executable was started with the {{-:S}} runtime option. This feature is only available on platforms that support the {{sigprocmask(3)}} POSIX API function.
-* it is unspecified in which thread of execution the signal handler will be invoked.
+=== signal-ignore
-* when signals arrive in quick succession (specifically, before the handler for a signal has been started), then signals will be queued (up to a certain limit); the order in which the queued signals will be handled is not specified
+<procedure>(signal-ignore SIGNUM)</procedure>
-* {{(set! (signal-handler SIG) PROC)}} can be used as an alternative to {{(set-signal-handler! SIG PROC)}}
+Ignores any future occurrences if the signal {{SIGNUM}} by setting its disposition to {{SIG_IGN}}.
-* Any signal handlers for the signals {{signal/segv}}, {{signal/bus}}, {{signal/fpe}} and {{signal/ill}} will be ignored and these signals will always trigger an exception, unless the executable was started with the {{-:S}} runtime option. This feature is only available on platforms that support the {{sigprocmask(3)}} POSIX API function.
+=== signal-default
+
+<procedure>(signal-default SIGNUM)</procedure>
+
+Sets the default disposition for the signal {{SIGNUM}} by setting its disposition to {{SIG_DFL}}.
=== set-signal-mask!
diff --git a/posix-common.scm b/posix-common.scm
index 8ee394c0..6f7028c3 100644
--- a/posix-common.scm
+++ b/posix-common.scm
@@ -625,19 +625,46 @@ EOF
;;; Signals
-(set! chicken.process.signal#set-signal-handler!
+(set! chicken.process.signal#set-signal-handler! ; DEPRECATED
(lambda (sig proc)
(##sys#check-fixnum sig 'set-signal-handler!)
(##core#inline "C_establish_signal_handler" sig (and proc sig))
(vector-set! ##sys#signal-vector sig proc) ) )
-(set! chicken.process.signal#signal-handler
+(set! chicken.process.signal#signal-handler ; DEPRECATED
(getter-with-setter
(lambda (sig)
(##sys#check-fixnum sig 'signal-handler)
(##sys#slot ##sys#signal-vector sig) )
chicken.process.signal#set-signal-handler!
"(chicken.process.signal#signal-handler sig)"))
+
+(set! chicken.process.signal#make-signal-handler
+ (lambda sigs
+ (let ((q (##sys#make-event-queue)))
+ (for-each
+ (lambda (sig)
+ (##sys#check-fixnum sig 'make-signal-handler)
+ (##core#inline "C_establish_signal_handler" sig sig)
+ (vector-set! ##sys#signal-vector sig
+ (lambda (sig) (##sys#add-event-to-queue! q sig))))
+ sigs)
+ (lambda (#!optional wait)
+ (if wait
+ (##sys#wait-for-next-event q)
+ (##sys#get-next-event q))))))
+
+(set! chicken.process.signal#signal-ignore
+ (lambda (sig)
+ (##sys#check-fixnum sig 'signal-ignore)
+ (##core#inline "C_establish_signal_handler" sig #f)
+ (vector-set! ##sys#signal-vector sig #f)))
+
+(set! chicken.process.signal#signal-default
+ (lambda (sig)
+ (##sys#check-fixnum sig 'signal-default)
+ (##core#inline "C_establish_signal_handler" sig #t)
+ (vector-set! ##sys#signal-vector sig #f)))
;;; Processes
diff --git a/posix.scm b/posix.scm
index b28f21b1..a082f054 100644
--- a/posix.scm
+++ b/posix.scm
@@ -263,8 +263,10 @@
(module chicken.process.signal
- (set-alarm! set-signal-handler! set-signal-mask!
- signal-handler signal-mask signal-mask! signal-masked? signal-unmask!
+ (set-alarm! set-signal-mask!
+ make-signal-handler signal-ignore signal-default
+ set-signal-handler! signal-handler ; DEPRECATED
+ signal-mask signal-mask! signal-masked? signal-unmask!
signal/abrt signal/alrm signal/break signal/bus signal/chld
signal/cont signal/fpe signal/hup signal/ill signal/int signal/io
signal/kill signal/pipe signal/prof signal/quit signal/segv
@@ -276,9 +278,12 @@
;; These are all set! inside the posix module
(define set-alarm!)
-(define set-signal-handler!)
+(define set-signal-handler!) ; DEPRECATED
(define set-signal-mask!)
-(define signal-handler)
+(define signal-handler) ; DEPRECATED
+(define make-signal-handler)
+(define signal-ignore)
+(define signal-default)
(define signal-mask)
(define signal-mask!)
diff --git a/runtime.c b/runtime.c
index 6fdd7fca..9becd2aa 100644
--- a/runtime.c
+++ b/runtime.c
@@ -4942,6 +4942,7 @@ C_regparm C_word C_fcall C_establish_signal_handler(C_word signum, C_word reason
#endif
if(reason == C_SCHEME_FALSE) C_signal(sig, SIG_IGN);
+ else if(reason == C_SCHEME_TRUE) C_signal(sig, SIG_DFL);
else {
signal_mapping_table[ sig ] = C_unfix(reason);
#if defined(HAVE_SIGACTION)
diff --git a/types.db b/types.db
index 62d98126..ad4f547f 100644
--- a/types.db
+++ b/types.db
@@ -2111,9 +2111,10 @@
;; process.signal
(chicken.process.signal#set-alarm! (#(procedure #:clean #:enforce) chicken.process#set-alarm! (integer) integer))
-(chicken.process.signal#set-signal-handler! (#(procedure #:clean #:enforce) chicken.process.signal#set-signal-handler! (fixnum (or false (procedure (fixnum) . *))) undefined))
+(chicken.process.signal#make-signal-handler (#(procedure #:clean #:enforce) chicken.process.signal#make-signal-handler (#!rest fixnum) (procedure () fixnum)))
(chicken.process.signal#set-signal-mask! (#(procedure #:clean #:enforce) chicken.process.signal#set-signal-mask! ((list-of fixnum)) undefined))
-(chicken.process.signal#signal-handler (#(procedure #:clean #:enforce) chicken.process.signal#signal-handler (fixnum) (or false (procedure (fixnum) . *))))
+(chicken.process.signal#signal-ignore (#(procedure #:clean #:enforce) chicken.process.signal#signal-ignore (fixnum) undefined))
+(chicken.process.signal#signal-default (#(procedure #:clean #:enforce) chicken.process.signal#signal-default (fixnum) undefined))
(chicken.process.signal#signal-mask (#(procedure #:clean) chicken.process.signal#signal-mask () fixnum))
(chicken.process.signal#signal-mask! (#(procedure #:clean #:enforce) chicken.process.signal#signal-mask! (fixnum) undefined))
(chicken.process.signal#signal-masked? (#(procedure #:clean #:enforce) chicken.process.signal#signal-masked? (fixnum) boolean))
Trap