Linux: Can a signal handler shutdown be unloaded?

I came across the following signal handler code that stores the errno variable so that it does not affect the errno processing of the main thread.

void myhandler(int signo) { int esaved; esaved = errno; write(STDOUT_FILENO, "Got a signal\n", 13); errno = esaved; } 

But does this really serve the purpose? What happens if another thread checks the shared errno variable right after write () and before errno is restored? Will this thread change the errno value due to race conditions?

Or does the signal handler execute atomically with respect to the thread / process, so that as soon as the signal handler is executed, the kernel will not schedule the thread until the signal handler finishes?

Enter other words. Once it starts, does the signal handler execute without interruption:

  - 1) Scheduler (process/threads), or - 2) Other signals, or - 3) Hardware interrupt handlers ? 
+4
source share
3 answers

The errno variable depends on the stream or, more precisely, in the streaming environment, is a stream-local value or a value for the stream string, so what is done with errno in this stream will not affect errno in other streams.

The purpose of saving and restoring errno code is to hide any error set by the write() system call in myhandler() . But if write() fails, it can set errno some new value - it will not be zero, but that's all you can say - but the code you request restores the value before calling write() after the call write() , so the fact that a write has occurred is "invisible" in the sense that it does not affect errno for this stream.

The signal handler function itself can be interrupted by signals that are not blocked by the signal mask for the signal to which it is responding. It can also be carried over. Hardware interruptions may also occur, but the code will be very difficult to notice these effects.


On Linux, you can find /usr/include/bits/errno.h errno macro definition (wrapped in more #ifdef code than shown here):

 extern int *__errno_location (void) __THROW __attribute__ ((__const__)); # if !defined _LIBC || defined _LIBC_REENTRANT /* When using threads, errno is a per-thread value. */ # define errno (*__errno_location ()) # endif 
+4
source

On Linux, errno is a macro that expands into a function call that returns a mutable lvalue that is different for each thread.

View the man page :

errno is defined by the ISO C standard as a mutable value of l of type int and should not be explicitly declared; errno may be a macro. errno is thread-local; setting it to one thread does not affect its value in any other thread.

However, indeed, the signal may be triggered again in the middle of the signal handler (if you used signal() instead of sigaction() , depending on your environment, these discrepancies are explained by why it is recommended to use sigaction() ), or another signal may interrupt execution of your handler. That is why when you set the signal setting, you make it block the signal (s, in the case of several signals using this handler) - by adding it to the signal mask - during the execution of the signal handler, This prevents the signal handler from being interrupted ( in some cases prevents an infinite loop).

Literature:

  • sa_mask , which can be passed to sigaction() :

    sa_mask defines the mask of signals that should be blocked (i.e. added to the signal mask of the stream in which the signal handler is called) during the execution of the signal handler. In addition, the signal that the called handler will be blocked if the SA_NODEFER flag is not used.

  • signal() :

    The only portable use of the signal () is to set the signal location to SIG_DFL or SIG_IGN. The semantics of using a signal () to create a signal handler varies in different systems (and POSIX.1 explicitly allows this variation); Do not use it for this purpose.

    POSIX.1 resolved the portability mess by specifying sigaction (2) , which provides explicit semantics control when the signal handler is called; use this interface instead of signal ().

    [...] In addition, fast deliveries of the same signal can lead to recursive calls to the handler.

+3
source

A signal handler can indeed be interrupted by another signal (assuming that this is not the same signal as the one that caused the handler in the first place).

your handler may still be interrupted by the delivery of another type of signal. To avoid this, you can use the sa_mask member of the action structure passed to sigaction to explicitly indicate which signals should be blocked during the execution of the signal handler. These signals are in addition to the signal for which the handler was called, and any other signals that are normally blocked by the process. See Lock for handler.

When the handler returns, the set of blocked signals is restored to the value it had before the handler started. Therefore, using sigprocmask inside the handler affects only what signals may appear during the execution of the handler itself, and not what signals may appear after the handler returns.

http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html#Signals-in-Handler

+3
source

All Articles