# Async signal handling in ada

**URL:** https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348
**Category:** Help
**Tags:** gnat, linux
**Created:** [April 14, 2026, 7:51pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348 "2026-04-14T19:51:09Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![tremon](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@tremon](https://forum.ada-lang.io/u/tremon)
#### Post date: [April 14, 2026, 7:51pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348/1 "2026-04-14T19:51:09Z")

</div>

Is there a way to make gnat play nice with asynchronous signal handling, i.e. signalfd(2)? From my experimentation so far, it seems that the gnat/ada runtime always spawns a separate signal handling thread (i.e. Interrupt\_Manager), which is fine – but it always terminates the program at the first received event without attached handler, which is rather not fine.

I’m aware of pragma Interrupt\_State, but it seems to exacerbate this issue, not help here: Interrupt\_State(Int, SYSTEM) disallows attaching a handler, basically guaranteeing the abort-on-signal behaviour, while Interrupt\_State(Int, USER) does allow attaching a handler but does not seem to mask the signal when no synchronous handler is attached.

In order to process the signal through signalfd it must not have been handled another way, so attaching a null handler in ada or setting it to SIG\_IGN via sigaction is not an option. Is there any way to control the signal mask on the Interrupt\_Manager thread?

---

<div class="post-metadata">

### Author: ![Irvise](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/i/7ba0ec/32.png) [@Irvise](https://forum.ada-lang.io/u/Irvise)
#### Post date: [April 17, 2026, 5:12pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348/2 "2026-04-17T17:12:21Z")

</div>

Bump. I am also interested in async handling of events/data in Ada and I would like to know how people can do it.

---

<div class="post-metadata">

### Author: ![jere](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jere/32/87_2.png) [@jere](https://forum.ada-lang.io/u/jere)
#### Post date: [April 17, 2026, 5:47pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348/3 "2026-04-17T17:47:05Z")

</div>

I’m not very well versed in this, but would blocking the default handling at the kernel level help at all? Something like:

```C
    sigset_t new_set, old_set;

    // 1. Initialize the set and add SIGINT
    sigemptyset(&new_set);
    sigaddset(&new_set, SIGINT);

    // 2. Block SIGINT, save the current mask in old_set
    if (sigprocmask(SIG_BLOCK, &new_set, &old_set) < 0) {
        perror("sigprocmask");
        return 1;
    }

```

Maybe that would keep the runtime from handling it? I haven’t tried anything like this mind you. It was just mentioined in the man file for signalfd(2): [signalfd(2) - Linux manual page](https://man7.org/linux/man-pages/man2/signalfd.2.html)

I googled an example of how to use it.

---

<div class="post-metadata">

### Author: ![tremon](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/t/df705f/32.png) [@tremon](https://forum.ada-lang.io/u/tremon)
#### Post date: [April 23, 2026, 4:05pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348/4 "2026-04-23T16:05:29Z")

</div>

The problem with [rt\_]sigprocmask is that only affects the current thread; there is no way to set the signal mask for an already-running thread, which is why in C you set the signal mask before spawning any threads.

Luckily, I’ve found that what I need is the rather obvious GNAT.Signals.Block\_Signal. Not sure why I couldn’t find it earlier, maybe I was looking specifially for signal masking rather than blocking. Anyway, this seems to work:

```ada
  function Create_Fd (Mask : aliased kernel_sigset_t;
                      Flags : signalfd_flags_t) return C.int is
      Value : C.int;
   begin
      Value := signalfd (-1, Mask, Flags);
      if Value < 0 then
         raise Syscall_Error with "could not create signalfd: " & Errno_Message;
      end if;
      Iterate (Mask, GNAT.Signals.Block_Signal'Access);
      return Value;
   end Create_Fd;

```

(with Iterate being a custom procedural iterator that calls proc for every set bit in Mask, since Block\_Signal only operates on one signal at a time).

It does seem that an explicit call read(2) is required to reset the pending signal flag. Converting the signalfd to a stream via C\_Streams.fdopen() and then trying to read it via Ada.Direct\_IO does return the signal data, however the program is now stuck in an endless loop between epoll/select indicating there is data on the file descriptor and the fd having no data to offer.

Also, pragma `Interrupt_State` hardly seems useful. The only signal for which it has any effect is SIGINT – all other signals can either be masked by default, or are reserved by the runtime and cannot be masked at all under pain of `Program_Error`.

---

<div class="post-metadata">

### Author: ![bjorn-lundin](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/bjorn-lundin/32/106_2.png) [@bjorn-lundin](https://forum.ada-lang.io/u/bjorn-lundin)
#### Post date: [April 23, 2026, 7:49pm UTC](https://forum.ada-lang.io/t/async-signal-handling-in-ada/4348/5 "2026-04-23T19:49:29Z")

</div>

We do this to block SIGPIPE when reading from sockets via our home-brew sockets package.

We have another tasks reading from a named pipe as well, which may cause SIGPIPE we’d like to ignore.

```ada

with Ada.Interrupts; use Ada.Interrupts;
with Ada.Interrupts.Names; use Ada.Interrupts.Names;

package Sockets.Sigpipe_Ignore is

   protected Signal_Handlers is
      procedure Ignore_Signal;
      pragma Interrupt_Handler(Ignore_Signal);
      pragma Attach_Handler(Ignore_Signal, Sigpipe);
   end Signal_Handlers;

end Sockets.Sigpipe_Ignore;

```

```ada

package body Sockets.Sigpipe_Ignore is

   protected body Signal_Handlers is

      procedure Ignore_Signal is
      begin
         null;
      end Ignore_Signal;

   end Signal_Handlers;

end Sockets.Sigpipe_Ignore;

```

This was on AIX, I don’t know if really needed on Linux, but we still have it in place.

I did not know a signal could carry user data - or I might be misunderstanding your use case
