How can I tell in Linux which process sent my process a signal
I also needed to identify the signal sender in a program, so I took grawity's answer, and used it in my program, it works well.
Here's the sample code:
send_signal_raise.c
// send signal to self test - raise()
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
static int int_count = 0, max_int = 5;
static struct sigaction siga;
static void multi_handler(int sig, siginfo_t *siginfo, void *context) {
// get pid of sender,
pid_t sender_pid = siginfo->si_pid;
if(sig == SIGINT) {
int_count++;
printf("INT(%d), from [%d]\n", int_count, (int)sender_pid);
return;
} else if(sig == SIGQUIT) {
printf("Quit, bye, from [%d]\n", (int)sender_pid);
exit(0);
}
return;
}
int raise_test() {
// print pid
printf("process [%d] started.\n", (int)getpid());
// prepare sigaction
siga.sa_sigaction = *multi_handler;
siga.sa_flags |= SA_SIGINFO; // get detail info
// change signal action,
if(sigaction(SIGINT, &siga, NULL) != 0) {
printf("error sigaction()");
return errno;
}
if(sigaction(SIGQUIT, &siga, NULL) != 0) {
printf("error sigaction()");
return errno;
}
// use "ctrl + c" to send SIGINT, and "ctrl + \" to send SIGQUIT,
int sig;
while(1) {
if(int_count < max_int) {
sig = SIGINT;
} else {
sig = SIGQUIT;
}
raise(sig); // send signal to itself,
sleep(1); // sleep a while, note that: SIGINT will interrupt this, and make program wake up,
}
return 0;
}
int main(int argc, char *argv[]) {
raise_test();
return 0;
}
Compile:
gcc -pthread -Wall send_signal_raise.c
Execute:
./a.out
What it does:
The program sends SIGINT
to itself 10 times, before sending SIGQUIT
to terminate itself.
Also, during its execution, press CTRL+C to send SIGINT
, or CTRL+\ to send SIGQUIT
which would terminate the program by hand.
The program could successfully identify who sent the signal(s).
BCC includes the killsnoop
utility. It requires a kernel with BPF support.
Excerpt from killsnoop (8) man-page:
killsnoop traces the kill() syscall, to show signals sent via this method. This may be
useful to troubleshoot failing applications, where an unknown mechanism is sending
signals.
This works by tracing the kernel sys_kill() function using dynamic tracing, and will need
updating to match any changes to this function.
This makes use of a Linux 4.5 feature (bpf_perf_event_output()); for kernels older than
4.5, see the version under tools/old, which uses an older mechanism.
Since this uses BPF, only the root user can use this tool.
Two Linux-specific methods are SA_SIGINFO
and signalfd()
, which allows programs to receive very detailed information about signals sent, including the sender's PID.
Call
sigaction()
and pass to it astruct sigaction
which has the desired signal handler insa_sigaction
and theSA_SIGINFO
flag insa_flags
set. With this flag, your signal handler will receive three arguments, one of which is asiginfo_t
structure containing the sender's PID and UID.Call
signalfd()
and readsignalfd_siginfo
structures from it (usually in some kind of a select/poll loop). The contents will be similar tosiginfo_t
.
Which one to use depends on how your application is written; they probably won't work well outside plain C, and I wouldn't have any hope of getting them work in Java. They are also unportable outside Linux. They also likely are the Very Wrong Way of doing what you are trying to achieve.