Async code in signal handlers

25 views
Skip to first unread message

Andre Nathan

unread,
Feb 2, 2015, 2:28:50 PM2/2/15
to ocaml...@googlegroups.com
Hello again

Is there a way to run async code in a Unix signal handler? I don't think that would be safe, but it doesn't hurt to ask :) The use case is simple to be able to use the Log module from async_extra when a signal is received.

I tried using [Thread_safe.block_on_async_exn] because the [(unit -> 'a Deferred.t) -> 'a] type allows me to spawn a thread in a signal handler (which has type [Signal.t -> unit]), but then I get "called run_in_async_wait from the main thread" (expectedly, I guess).

Cheers,
Andre

Stephen Weeks

unread,
Feb 2, 2015, 4:06:27 PM2/2/15
to ocaml...@googlegroups.com
Try Async.Std.Signal.handle:

(** [handle ?stop signals ~f] arranges so that whenever a signal in
[signals] is delivered, [f] is called on that signal. If [f]
raises, then an exception will be raised to the monitor in
effect when [handle] was called.

Multiple calls to [handle] with the same signal will cause all
the handlers to run when that signal is delivered, not just the
last handler from the last call to [handle].

The first time [handle] is called for a signal, it will install
a C signal handler for that signal, which will replace the
existing C signal handler for that signal. *)
val handle : ?stop:unit Deferred.t -> t list -> f:(t -> unit) -> unit

Left implicit is that [f ()] runs as an ordinary Async job.

Andre Nathan

unread,
Feb 2, 2015, 5:54:07 PM2/2/15
to ocaml...@googlegroups.com
Hi Stephen.

I'm not sure I understand... Signal.handle is indeed the function I found to install a handler, but if ~f is [Signal.t -> unit], how can I run an async computation in it? Or do you mean using the ~stop parameter?

Thanks
Andre

Stephen Weeks

unread,
Feb 2, 2015, 6:05:36 PM2/2/15
to ocaml...@googlegroups.com
> if ~f is [Signal.t -> unit], how can I run an async computation in
> it?

By scheduling Async jobs to run in the background. My preferred idiom
for that is to use [don't_wait_for begin ... end]. E.g.:

Signal.handle signal ~f:(fun _ ->
don't_wait_for begin
some_async_thing ()
>>= fun () ->
another_async_thing ()
>>= fun () ->
return 13
end)

Yaron Minsky

unread,
Feb 2, 2015, 6:55:44 PM2/2/15
to ocaml...@googlegroups.com
This is a general and common confusion about Async: functions that
don't return deferreds can still schedule things to happen. Returning
a deferred is a way of giving the caller something they can block on,
but IO and concurrency can happen one way or the other.

Lwt is the same in this regard, for what it's worth.

y
> --
> You received this message because you are subscribed to the Google Groups "ocaml-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to ocaml-core+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Malcolm Matalka

unread,
Feb 3, 2015, 3:21:17 AM2/3/15
to ocaml...@googlegroups.com
Correct me if I'm misspeaking, but I thought that signal handlers could,
by the spec, only modify values of type [volatile sig_atomic_t]
otherwise the result of executing a signal handler may be undefined.

Doe Async leverage platform specific semantics or am I confused?

Reference:

https://www.securecoding.cert.org/confluence/display/seccode/SIG31-C.+Do+not+access+shared+objects+in+signal+handlers

Jeremie Dimino

unread,
Feb 3, 2015, 5:22:45 AM2/3/15
to ocaml...@googlegroups.com
On Tue, Feb 3, 2015 at 8:21 AM, Malcolm Matalka <mmat...@gmail.com> wrote:
Correct me if I'm misspeaking, but I thought that signal handlers could,
by the spec, only modify values of type [volatile sig_atomic_t]
otherwise the result of executing a signal handler may be undefined.

Doe Async leverage platform specific semantics or am I confused?

Async doesn't run the handler passed to [Async.Std.Signal.handle] immediately when it receives the signal. Instead it queues it and notify the scheduler. The handler is then executed normally by the scheduler.

-- 
Jeremie

Andre Nathan

unread,
Feb 3, 2015, 7:16:55 AM2/3/15
to ocaml...@googlegroups.com
On Monday, February 2, 2015 at 9:55:44 PM UTC-2, Yaron Minsky wrote:
This is a general and common confusion about Async: functions that
don't return deferreds can still schedule things to happen.  Returning
a deferred is a way of giving the caller something they can block on,
but IO and concurrency can happen one way or the other.

Yes, I had tried [let _t = some_async_computation in ...] but I got confused because I still got the "called run_in_async_wait from the main thread" error. Turns out there was another signal handler installed where I erroneously called [Thread_safe.run_in_async_wait_exn], but I missed it in my test and thought the error was coming from the first handler. Stephe's solution worked fine too.

Thanks guys!
Reply all
Reply to author
Forward
0 new messages