Skip to content
Advertisement

How do I install a signal handler for a custom I/O signal?

I am trying to set up a signal and signal handler to rebuffer CAN frames as they arrive. Below is my code. I can send a frame from the computer running this code, but when I send a frame back the other way, nothing happens. I am holding the programme with scanf(). Can you see why this signal handler is never called?

Admission of guilt: I tailored this code very little from some tutorial. I’ve read the relevent manual pages, but I’m a socket noob.

void
my_handler(int       const        signal_number,
           siginfo_t       *const p_signal_info,
           void            *const p_ucontext)
{
    (void) p_ucontext;

    printf("Signal with number %d on socket %dn",
        signal_number,
        p_signal_info->si_fd);
}

...
/* At init */
struct sigaction            signal_action = {0};

signal_action.sa_sigaction = &my_handler;
signal_action.sa_flags = SA_SIGINFO;
result = sigaction(SIGRTMIN, &signal_action, NULL);

/* On start of comms */
struct ifreq         interface_request = {0};
struct sockaddr_can  interface_address = {0};

sockets[can_interface_id] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strncpy(interface_request.ifr_name, my_if_name, sizeof(interface_request.ifr_name) - 1);
result = ioctl(sockets[can_interface_id], SIOCGIFINDEX, &interface_request);
interface_address->can_family = AF_CAN;
interface_address->can_ifindex = interface_request.ifr_ifindex;
result = bind(sockets[can_interface_id],
              (struct sockaddr *) &interface_address,
              sizeof(interface_address));

result = fcntl(sockets[can_interface_id],
               F_SETSIG,
               SIGRTMIN);

result = fcntl(sockets[can_interface_id], F_GETFL);
result = fcntl(sockets[can_interface_id],
               F_SETFL,
               result | O_NONBLOCK | O_ASYNC);

Advertisement

Answer

On Linux at least, and perhaps other platforms, F_SETOWN is required for F_SETFL/O_ASYNC to take effect: you must specify the recipient pid of the signal. See, for example, a similar situation in Perl.

For your C code, then, you’d want something like this:

/* _GNU_SOURCE for F_SETSIG */
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>

....

result = fcntl(sockets[can_interface_id],
               F_SETSIG,
               SIGRTMIN);

result = fcntl(sockets[can_interface_id], F_GETFL);
result = fcntl(sockets[can_interface_id],
               F_SETFL,
               result | O_NONBLOCK | O_ASYNC);

result = fcntl(sockets[can_interface_id],
               F_SETOWN,                  /* <----     */
               getpid());
7 People found this is helpful
Advertisement