This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Re: determine whether code is running in a signal handler context
- From: Yubin Ruan <ablacktshirt at gmail dot com>
- To: libc-help at sourceware dot org
- Cc: "Carlos O'Donell" <carlos at redhat dot com>, Will Hawkins <whh8b at virginia dot edu>, spc at conman dot org, noloader at gmail dot com, Szabolcs Nagy <szabolcs dot nagy at arm dot com>
- Date: Mon, 27 Nov 2017 16:42:50 +0800
- Subject: Re: determine whether code is running in a signal handler context
- Authentication-results: sourceware.org; auth=none
- References: <CAJYFCiPkMNCr0X61AQ9MqhXyagOb0k4tTp5mRAD171VLkedVYQ@mail.gmail.com>
Hi friends,
Still remember this thread? It turn out that determining whether or not you
are currently in a signal handler is trivial with libunwind:
Assume that you have build libunwind properly:
------------------------------------
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
/* assume that you have build libunwind properly */
#include "./libunwindout/include/libunwind.h"
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
void show_backtrace(void) {
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
while(unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
/* Upon unwinding to a signal handler, you get a "1" */
printf("Is in a signal handler [%d]\n",
unw_is_signal_frame(&cursor));
printf("ip = %lx, sp = %lx \n", (long)ip, (long)sp);
}
}
struct sigaction act;
/* Upon receiving a SIGQUIT, this signal handler will be invoked */
void sighandler(int signum, siginfo_t *info, void *ptr) {
printf("Received signal: %d\n", signum);
printf("signal originate from pid[%d]\n", info->si_pid);
printf("Inside a signal handler...\n");
show_backtrace();
while(1)
;
printf("[FATAL] quiting the signal handler\n");
}
int main(int argc, char *argv[]) {
{
printf("Pid of the current process: %d\n", getpid());
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGQUIT, &act, NULL);
while(1)
;
return 0;
}
------------------ END -------------
So you should run this program, and then send it a SIGQUIT. Upon receiving a
SIGQUIT, the signal handler will be invoked and the show_backtrace() function
will be called, which will unwind the stack and eventually find the signal
handler frame, reporting 1.
More interesting, libunwind allows you to detect "remotely" with its
libunwind-ptrace module. By "remotely", it simply means that you can use
ptrace(2) to attach to a process and then you can use libunwind-ptrace to
detect the remote process is running in a signal handler.
For more info, please refer to libunwind's doc [1].
As of the mechanism which libunwind use, somebody refer to sigreturn(2) [2],
but I still investigate in that so more material will be pending.
Anyway, thank you for all your patience and discussion.
[1]: http://www.nongnu.org/libunwind/docs.html
[2]: https://stackoverflow.com/questions/47503630/detect-whether-tracee-is-in-a-signal-handler-when-using-ptrace/47503853
Yubin
2017-10-18 22:18 GMT+08:00 Yubin Ruan <ablacktshirt@gmail.com>:
> Hi,
>
> I am writing to see if this is any util functions in libc that can
> help to determine it is currently running in a signal.
>
> I wrote some library and provide a function which will be used in many
> client code. However this function is not async-signal safe (it calls
> malloc(3)) so when it is called, I want to detect whether it is
> currently running in a signal handler. If it is, I can avoid calling
> those not-async-signal-safe functions which might cause deadlock.
>
> that is, I want a `in_signal_handler_context()' utility that can be
> used as this:
>
> int mylibfunc( void ) {
> if( in_signal_handler_context() ) { return(-1) }
> // rest of function goes here
> return( 0 );
> }
>
>
> Yubin