Providing/passing argument to signal handler

CSignalsSignal Handling

C Problem Overview


Can I provide/pass any arguments to signal handler?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

Now, handler looks like this:

void signal_handler(int signo) {
    /* some code */
}

If I want to do something special i.e. delete temp files, can I provide those files as an argument to this handler?

Edit 0: Thanks for the answers. We generally avoid/discourage use of global variables. And in this case, If you have a huge program, things can go wrong at different places and you might need to do a lot of cleanup. Why was the API designed this way?

C Solutions


Solution 1 - C

You can't have data of your own passed to the signal handler as parameters. Instead you'll have to store your parameters in global variables. (And be really, really careful if you ever need to change those data after installing the the signal handler).

Response to edit 0: Historical reasons. Signals are a really old and really low-level design. Basically you're just given the kernel a single address to some machine code and asking it to go to this specific address if such and such happens. We're back in the "portable assembler" mindset here, where the kernels provide a no-frills baseline service, and whatever the user process can reasonably be expected to to for itself, it must do itself.

Also, the usual arguments against global variables don't really apply here. The signal handler itself is a global setting, so there is no relevant possibility of having several different sets of user-specified parameters for it around. (Well, actually it is not entirely global but only thread-global. But the threading API will include some mechanism for thread-local storage, which is just what you need in this case).

Solution 2 - C

A signal handler registration is already a global state equivalent to global variables. So it's no greater offense to use global variables to pass arguments to it. However, it's a huge mistake (almost certainly undefined behavior unless you're an expert!) to do anything from a signal handler anyway. If you instead just block signals and poll for them from your main program loop, you can avoid all these issues.

Solution 3 - C

This is a really old question but I think I can show you a nice trick that would have answered your problem. No need to use sigqueue or whatever.

I also dislike the use of globals variables so I had to find a clever way, in my case, to send a void ptr (which you can later cast to whatever suits your need).

Actually you can do this :

signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc

Then your sighandler would look like this :

int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !

You might ask : How to get the *ptr then ?

Here's how : At initialization

signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);

In your sighandler func :

int sighandler(const int signal, void *ptr)
{
  static my_struct saved = NULL;

  if (saved == NULL)
     saved = ptr;
  if (signal == SIGNALWHATEVER)
     // DO YOUR STUFF OR FREE YOUR PTR
   return (0);
}

Solution 4 - C

Absolutely. You can pass integers and pointers to signal handlers by using sigqueue() instead of the usual kill().

http://man7.org/linux/man-pages/man2/sigqueue.2.html

Solution 5 - C

Store the names of the files in a global variable and then access it from the handler. The signal handler callback will only be passed one argument: the ID for the actual signal that caused the problem (eg SIGINT, SIGTSTP)

Edit 0: "There must be a rock solid reason for not allowing arguments to the handler." <-- There is an interrupt vector (basically, a set of jump addresses to routines for each possible signal). Given the way that the interrupt is triggered, based on the interrupt vector, a particular function is called. Unfortunately, it's not clear where the memory associated with the variable will be called, and depending on the interrupt that memory may actually be corrupted. There is a way to get around it, but then you can't leverage the existing int 0x80 assembly instruction (which some systems still use)

Solution 6 - C

I think you it's better to use SA_SIGINFO in sa_flags so the handler will get void signal_handler(int sig, siginfo_t *info, void *secret) in siginfo_t you can provide your params. Ty:HAPPY code

Solution 7 - C

You can use a signal handler which is a method of a class. Then that handler can access member data from that class. I'm not entirely sure what Python does under the covers here around the C signal() call, but it must be re-scoping data?

I was amazed that this works, but it does. Run this and then kill the process from another terminal.

import os, signal, time

class someclass:
    def __init__(self):
        self.myvalue = "something initialized not globally defined"
        signal.signal(signal.SIGTERM, self.myHandler)
    def myHandler(self, s, f):
        # WTF u can do this?
        print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue
    

print "Making an object"
a = someclass()

while 1:
    print "sleeping.  Kill me now."
    time.sleep(60)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhariView Question on Stackoverflow
Solution 1 - Chmakholm left over MonicaView Answer on Stackoverflow
Solution 2 - CR.. GitHub STOP HELPING ICEView Answer on Stackoverflow
Solution 3 - Crak007View Answer on Stackoverflow
Solution 4 - CDavid YeagerView Answer on Stackoverflow
Solution 5 - CFoo BahView Answer on Stackoverflow
Solution 6 - CfadView Answer on Stackoverflow
Solution 7 - Cdrizzo4shizzoView Answer on Stackoverflow