Skip to content

Commit d436705

Browse files
committed
Lwt_engine: allow external signal handlers
Before installing a signal handler, Lwt now checks first with the engine, which may now prevent Lwt from installing its handler and instead forward signals from some external handler. This allows e.g. sharing the SIGCHLD handler with Eio.
1 parent 890b19a commit d436705

File tree

5 files changed

+40
-4
lines changed

5 files changed

+40
-4
lines changed

src/unix/lwt_engine.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class virtual abstract = object(self)
108108
method timer_count = Lwt_sequence.length timers
109109

110110
method fork = ()
111+
112+
method forwards_signal (_signum:int) = false
111113
end
112114

113115
class type t = object
@@ -433,6 +435,7 @@ let readable_count () = !current#readable_count
433435
let writable_count () = !current#writable_count
434436
let timer_count () = !current#timer_count
435437
let fork () = !current#fork
438+
let forwards_signal n = !current#forwards_signal n
436439

437440
module Versioned =
438441
struct

src/unix/lwt_engine.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ val fake_io : Unix.file_descr -> unit
5353
val fork : unit -> unit
5454
(** Called internally by Lwt_unix.fork to make sure we don't get strange behaviour *)
5555

56+
val forwards_signal : int -> bool
57+
(** [forwards_signal signum] is [true] if the engine will call {!Lwt_unix.handle_signal}
58+
when signal [signum] occurs. In this case, Lwt will not install its own signal handler.
59+
60+
Normally, this just returns [false], but when Lwt is used in combination
61+
with other IO libraries, this allows sharing e.g. the SIGCHLD handler. *)
62+
5663
(** {2 Engines} *)
5764

5865
(** An engine represents a set of functions used to register different
@@ -82,6 +89,7 @@ class virtual abstract : object
8289
method readable_count : int
8390
method writable_count : int
8491
method timer_count : int
92+
method forwards_signal : int -> bool
8593

8694
(** {2 Backend methods} *)
8795

src/unix/lwt_unix.cppo.ml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,12 +2227,19 @@ let event_notifications = ref (Lwt_engine.on_readable (init_notification ()) han
22272227
| Signals |
22282228
+-----------------------------------------------------------------+ *)
22292229

2230-
external set_signal : int -> int -> unit = "lwt_unix_set_signal"
2231-
external remove_signal : int -> unit = "lwt_unix_remove_signal"
2230+
external set_signal : int -> int -> bool -> unit = "lwt_unix_set_signal"
2231+
external remove_signal : int -> bool -> unit = "lwt_unix_remove_signal"
22322232
external init_signals : unit -> unit = "lwt_unix_init_signals"
2233+
external handle_signal : int -> unit = "lwt_unix_handle_signal"
22332234

22342235
let () = init_signals ()
22352236

2237+
let set_signal signum notification =
2238+
set_signal signum notification (Lwt_engine.forwards_signal signum)
2239+
2240+
let remove_signal signum =
2241+
remove_signal signum (Lwt_engine.forwards_signal signum)
2242+
22362243
module Signal_map = Map.Make(struct type t = int let compare a b = a - b end)
22372244

22382245
type signal_handler = {

src/unix/lwt_unix.cppo.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,14 @@ val reinstall_signal_handler : int -> unit
854854
signal handler (with [Sys.set_signal]). This is useful in case
855855
another part of the program install another signal handler. *)
856856

857+
val handle_signal : int -> unit
858+
(** [handle_signal signum] acts as if Lwt had received the [signum] signal.
859+
This allows another IO library to install the handler, perform its own
860+
handling, but still notify Lwt. It is particularly useful for SIGCHLD,
861+
where several IO libraries may be spawning sub-processes.
862+
863+
This function is thread-safe. *)
864+
857865
(** {2 Sockets} *)
858866

859867
type inet_addr = Unix.inet_addr

src/unix/lwt_unix_stubs.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@ static void handle_signal(int signum) {
801801
}
802802
}
803803

804+
CAMLprim value lwt_unix_handle_signal(value val_signum) {
805+
handle_signal(caml_convert_signal_number(Int_val(val_signum)));
806+
return Val_unit;
807+
}
808+
804809
#if defined(LWT_ON_WINDOWS)
805810
/* Handle Ctrl+C on windows. */
806811
static BOOL WINAPI handle_break(DWORD event) {
@@ -813,7 +818,7 @@ static BOOL WINAPI handle_break(DWORD event) {
813818
#endif
814819

815820
/* Install a signal handler. */
816-
CAMLprim value lwt_unix_set_signal(value val_signum, value val_notification) {
821+
CAMLprim value lwt_unix_set_signal(value val_signum, value val_notification, value val_forwarded) {
817822
#if !defined(LWT_ON_WINDOWS)
818823
struct sigaction sa;
819824
#endif
@@ -825,6 +830,8 @@ CAMLprim value lwt_unix_set_signal(value val_signum, value val_notification) {
825830

826831
signal_notifications[signum] = notification;
827832

833+
if (Bool_val(val_forwarded)) return Val_unit;
834+
828835
#if defined(LWT_ON_WINDOWS)
829836
if (signum == SIGINT) {
830837
if (!SetConsoleCtrlHandler(handle_break, TRUE)) {
@@ -855,14 +862,17 @@ CAMLprim value lwt_unix_set_signal(value val_signum, value val_notification) {
855862
}
856863

857864
/* Remove a signal handler. */
858-
CAMLprim value lwt_unix_remove_signal(value val_signum) {
865+
CAMLprim value lwt_unix_remove_signal(value val_signum, value val_forwarded) {
859866
#if !defined(LWT_ON_WINDOWS)
860867
struct sigaction sa;
861868
#endif
862869
/* The signal number is valid here since it was when we did the
863870
set_signal. */
864871
int signum = caml_convert_signal_number(Int_val(val_signum));
865872
signal_notifications[signum] = -1;
873+
874+
if (Bool_val(val_forwarded)) return Val_unit;
875+
866876
#if defined(LWT_ON_WINDOWS)
867877
if (signum == SIGINT)
868878
SetConsoleCtrlHandler(NULL, FALSE);

0 commit comments

Comments
 (0)