[Linux][C/C++] Understanding Signals – User Signal Handler

Signal is used for interaction between User Mode processes(henceforth UMP) and for kernel to notify processes of system events.
There are lots of materials you can find to understand what Signal is. So, let’s skip it.
The point of this article is “How user signal handler(henceforth USH) is executed?” in Linux.

The core what Linux Kernel does to deliver signal, is modifying stack of UMP – usually adding data.
This is very important! UMP’s stack itself is changed!
Kernel changes UMP’ stack and register values as if  USH is called from specific function – let’s call it F.
(For example, PC is set to USH. Return address in stack is set to function F.)
And, usually, F is just system call – sigreturn. At this system call, Kernel back UMP’s stack to original values.
Here is simplified flow.

Signal is issued –> Kernel changes UMP’s stack -> USH is executed -> return to function F -> System call (sigreturn) -> UMP’s stack is restored -> UMP is executed in normal.

In case of multi-threaded process, thread stack is changed. Nothing different.
Understood? Than what is point?
Yes, USH is run at issued process’s / thread’s context in User Mode.
Let’s see following codes.

/* Timer is used for example */
static pthread_mutex_t _m;
...
static void
_signal_handler(int sig, siginfo_t* si, void* uc) {
    pthread_mutex_lock(&_m);
    ...
    pthread_mutex_unlock(&_m);
}

int main(...) {
    ... /* signal is requested (ex timer) somewhere here */
    pthread_mutex_lock(&_m);
    ... /* <--- *a */
    pthread_mutex_unlock(&_m);
    ...
    return 0;
}

Can you image what I am going to talk about?
As I mentioned above signal handler is run in issued thread’s context. So, if signal is issued at (*a), program is stuck due to deadlock!
So, signal handler of above codes should be like follows

static void*
_signal_handler_thread(void* arg) {
    pthread_mutex_lock(&_m);
    ...
    pthread_mutex_unlock(&_m);
}

static void
_signal_handler(int sig, siginfo_t* si, void* uc) {
    pthread_t thd;
    pthread_create(&thd, NULL, &_signal_handler_thread, NULL);
}

Done!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s