Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell in Linux which process sent my process a signal

Tags:

linux

signals

I have a java application that got SIG TERM. I want to know the pid of the process that sent this signal.
Is that possible?

like image 326
oshai Avatar asked Dec 04 '11 19:12

oshai


People also ask

How do you find the PID of a process that sent signal?

A good choice is options=SA_RESTART . To know the PID of the process which sent a signal, set options=SA_SIGINFO , and use a sa_sigaction callback instead of sa_handler ; it will receive a siginfo_t struct, having a si_pid field. You can associate a data to the signal using sigqueue .

Which command is used to signal processes Linux?

As noted above, the kill command sends a signal to terminate a process in Linux. By default, it will send a TERM signal, if no other signal is defined. That signal will try to stop the process gracefully in the Linux operating system.

Which command is used to signal processes?

In Unix and Unix-like operating systems, kill is a command used to send a signal to a process. By default, the message sent is the termination signal, which requests that the process exit. But kill is something of a misnomer; the signal sent may have nothing to do with process killing.

How are signals sent to a process?

The SIGINT signal is sent to a process by its controlling terminal when a user wishes to interrupt the process. This is typically initiated by pressing Ctrl + C , but on some systems, the "delete" character or "break" key can be used. The SIGKILL signal is sent to a process to cause it to terminate immediately (kill).


2 Answers

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 a struct sigaction which has the desired signal handler in sa_sigaction and the SA_SIGINFO flag in sa_flags set. With this flag, your signal handler will receive three arguments, one of which is a siginfo_t structure containing the sender's PID and UID.

  • Call signalfd() and read signalfd_siginfo structures from it (usually in some kind of a select/poll loop). The contents will be similar to siginfo_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.

like image 119
user1686 Avatar answered Sep 20 '22 22:09

user1686


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).

like image 21
user218867 Avatar answered Sep 19 '22 22:09

user218867