1

In sigaction manpage it's written :

sa_sigaction also specifies the action to be associated with signum. This function receives the signal number as its first argument, a pointer to a siginfo_t as its second argument and a pointer to a ucon- text_t (cast to void*) as its third argument.

So we can pass arguments to the signal handler (throught void*), but I can't find the way. Is there no way to put it anywhere?

Example :

struct ping_val
{
    int data1;
    int data2;
};

void ping(int sig, siginfo_t *siginf, void *ptr) 
{
    // ....
}

int main()
{
    struct sigaction sa_ping;
    ping_val foo;
    foo.data1 = 3;
    foo.data2 = 4;
    sa_ping.sa_sigaction = ping;
    sigemptyset(&sa_ping.sa_mask);
    sa_ping.sa_flags = 0;
    sigaction(SIGALRM, &sa_ping, NULL);
    // ....
}

Where I can pass foo structure value in argument in ping (with a cast in struct *)???

Jonas
  • 6,915
  • 8
  • 35
  • 53
Mathi.J
  • 51
  • 7
  • 3
    No you can't pass arbitrary data to the signal handler. You only have control of the `sigaction` structure and it have no user-data field. Also, for the three-argument variant of the signal function to be called you *must* specify the `SA_SIGINFO` flag. – Some programmer dude Jul 03 '17 at 07:16
  • 2
    Your confusion probably comes from the `u` in the name `ucontext_t`? It doesn't stand for "user data", it's a structure for the stack frame of the thread causing the signal. – Some programmer dude Jul 03 '17 at 07:24

3 Answers3

0

You cannot pass any arguments to a signal handler because you never call it yourselves. A signal handler is called by the OS that doesn't know anything about your arguments.

The standard way to have a signal handler communicate with the main program is through global (or file-scoped) variables.

tofro
  • 5,640
  • 14
  • 31
0

The siginfo_t structure that a signal handler receives contains a union sigval si_value member:

union sigval {
    int    sival_int; // Integer signal value 
    void  *sival_ptr; // Pointer signal value 
}

So if you're sending signals within a single process (or among forks, in some cases, I suppose), you can send a pointer to some data.

I know of two ways to send a sigval value to a signal handler:

If you use timer_create to create a timer, you pass it a sigevent struct, which contains a union sigval sigev_value member. By convention, user code will set sigev_value.sival_ptr to be the timer ID, so that the signal handler can distinguish among several timers if necessary, but you can set it to any void * value.

If you use sigqueue (as opposed to kill, raise, faults, etc.) to send the signals, you give it a union sigval as an argument.

Mark Plotnick
  • 9,598
  • 1
  • 24
  • 40
0

You write:

So we can pass arguments to the signal handler [through the void* ucontext_t argument], but I can't find the way.

There is no such way to be found — the ucontext_t argument is set by the system itself and refers to "the receiving thread's context that was interrupted when the signal was delivered."

(Specifically, by spec it contains at least a reference to that interrupted context, and to a machine-specific representation of that context, and also the current context's stack and its set of blocked signals.)

You probably don't need any of this. If you want your program to take some action and/or modify its state on receipt of a signal, you've a limited number of tactics that can be safely used in a signal handler (volatile sigatomic_t flags, self-pipes, platform-specific interfaces), but then your main loop can of course do whatever you want with the knowledge that SIGFOO was just received.

pilcrow
  • 56,591
  • 13
  • 94
  • 135