使用 sigaction
来完成信号量触发的分析
sigaction
注册普通 signal handler
使用的是 sa_handler
,此时参数只有一个 signo
使用 Flag SA_SIGINFO
需要使用 sa_sigaction
,此时参数有三个
- An int, for the signal number (just like signal)
- A siginfo_t *, which is a structure containing all sorts of information about the source of the signal, including the pid of the sender if applicable. (It also includes some information about the cause of the signal for automatic signals like SIGSEGV.)
- A ucontext_t *, which has to do with which thread got the signal. Mostly ignorable.
void (*sa_sigaction)(int, siginfo_t *, void *)
相关结构体
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
int si_band; /* Band event */
int si_fd; /* File descriptor */
}
注册
struct sigaction pipe_act;
pipe_act.sa_flags = SA_SIGINFO;
pipe_act.sa_sigaction = sigpipehandler
sigaction(SIGPIPE, &pipe_act, NULL);
Example of using sigaction
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
static void hdl (int sig, siginfo_t *siginfo, void *context)
{
printf ("Sending PID: %ld, UID: %ld\n",
(long)siginfo->si_pid, (long)siginfo->si_uid);
}
int main (int argc, char *argv[])
{
struct sigaction act;
memset (&act, '\0', sizeof(act));
/* Use the sa_sigaction field because the handles has two additional parameters */
act.sa_sigaction = &hdl;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGTERM, &act, NULL) < 0) {
perror ("sigaction");
return 1;
}
while (1)
sleep (10);
return 0;
}
Using Extended Information
The context information contains details about the machine state: the values of current registers, pointers to the stack, and so on. So it is possible to produce a rudimentary profiling infrastructure using the timers and the machine context information.
第三个参数为 ucontext_t *context = (ucontext_t*)vcontext;
Contexts may be used via the makecontext()/setcontext()/getcontext()/swapcontext() functions to implement user-space threads.
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ucontext.h>
struct itimerval timeout={0};
static void handle_prof_signal(int sig_no, siginfo_t* info, void *vcontext)
{
char output[100];
ucontext_t *context = (ucontext_t*)vcontext;
unsigned long pc = context->uc_mcontext.gregs[REG_PC];
snprintf(output,100,"Sample at %lx\n",pc);
write(1,output,strlen(output)+1);
setitimer(ITIMER_PROF, &timeout, 0);
}
void main()
{
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_sigaction = handle_prof_signal;
sig_action.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sig_action.sa_mask);
sigaction(SIGPROF, &sig_action, 0);
timeout.it_value.tv_sec=1;
setitimer(ITIMER_PROF, &timeout, 0);
volatile int i=0;
do { i++; } while(1);
}
kernel support
主要的结构体为 struct sigframe
需要内核支持,例如在内核 2.6 中
i386
,文件 arch/um/sys-i386/signal.c
,函数 setup_signal_stack_si
stack_top &= -8UL;
frame = (struct rt_sigframe __user *) stack_top - 1;
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return 1;
restorer = frame->retcode;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
/* See comment above about why this is here */
PT_REGS_SP(regs) = (unsigned long) frame;
err |= __put_user(restorer, &frame->pretcode);
err |= __put_user(sig, &frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
save_sp);
arm
,文件 arch/arm/kernel/signal.c
,函数 setup_sigframe
Ref
- How to find out the source of a POSIX signal
- Linux C: upon receiving a signal, is it possible to know the PID of the sender?
- Using the third parameter context of a sigaction handler with SIG_INFO results in a Segmentation Fault
- How to Write Advanced Signal Handlers in UNIX
- sigaction(7): semantics of siginfo_t’s si_code member