Is it possible to find out the process id of the process which has caused some signal. In my scenario, I have multiple children of a process running, and I want to know which one of them sent the signal.
4 Answers
It is (finally!) very simple with python 3.
The following is tested with python 3.3.3:
#! /usr/bin/python3
import signal
import time, os
def callme(num, frame):
pass
# register the callback:
signal.signal(signal.SIGUSR1, callme)
print("py: Hi, I'm %d, talk to me with 'kill -SIGUSR1 %d'"
% (os.getpid(),os.getpid()))
# wait for signal info:
while True:
siginfo = signal.sigwaitinfo({signal.SIGUSR1})
print("py: got %d from %d by user %d\n" % (siginfo.si_signo,
siginfo.si_pid,
siginfo.si_uid))

- 7,930
- 3
- 42
- 45
-
1Is there any way to get the siginfo inside the signal handler? My use case is in trying to debug an unexpected KeyboardInterrupt coming from some other completely unknown process (and not actually the keyboard). – szmoore Aug 28 '20 at 12:40
-
@szmoore I don't know of any unfortunately... but unless I'm wrong you should be able to use ``signal.sigwaitinfo`` (as opposed to ``signal.signal``) from an ad hoc thread, and this should allow you to debug the interrupt without disrupting your main thread. – Pietro Battiston Aug 29 '20 at 08:24
POSIX Linux does provide this information, check man sigaction(2): http://linux.die.net/man/2/sigaction
In C, I managed to get it running easily:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
static void my_handler(int signum, siginfo_t *siginfo, void *context) {
printf("Got signal '%d' from process '%d' of user '%d'\n",
signum, siginfo->si_pid, siginfo->si_uid);
}
int main(void) {
struct sigaction act;
memset(&act, '\0', sizeof(act));
act.sa_sigaction = &my_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &act, NULL);
printf("Hi, my pid is %d\ntalk to me with 'kill -SIGUSR1 %d'\n", getpid(), getpid());
while(1)
sleep(1000);
return 0;
}
Works pretty well with my 3.1.6 vanilla kernel and gcc 4.4.5 -- but I could not find any support for it in python.
So i started to try and build something on my own (but since I never did C/Python-Interaction before, it's probably somehow twisted up...)
I'm more or less keeping close to the example at http://docs.python.org/extending/extending.html and building the module according to http://docs.python.org/extending/building.html#building
sigpidmodule.c
#include <Python.h>
#include <signal.h>
static PyObject *callback = NULL;
static void direct_handler(int signum, siginfo_t *siginfo, void *context) {
int pid = (int) siginfo->si_pid;
printf("c: Signal reached c handler: signum=%d, pid=%d, handler=%p\n",
signum, pid, callback);
if ( callback != NULL ) {
PyObject *arglist = Py_BuildValue("(i,i)", signum, pid);
printf("c: calling python callback\n");
PyObject *result = PyObject_CallObject(callback, arglist);
// decrease reference counter
Py_DECREF(arglist);
Py_DECREF(result);
}
}
static PyObject *sigpid_register(PyObject *self, PyObject *args) {
PyObject *result = NULL;
PyObject *temp;
if ( PyArg_ParseTuple(args, "O:set_callback", &temp) ) {
if ( !PyCallable_Check(temp) ) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return NULL;
}
}
Py_XINCREF(temp); // inc refcount on new callback
Py_XDECREF(callback); // dec refcount on old callback
callback = temp; // replace old callback with new
printf("c: callback now: %p\n", (void *) callback);
// return None
Py_RETURN_NONE;
}
static PyObject *sigpid_ping(PyObject *self, PyObject *args) {
if ( callback != NULL ) {
PyObject *arglist = Py_BuildValue("(i,i)", 42, 23);
printf("c: calling callback...\n");
PyObject *result = PyObject_CallObject(callback, arglist);
// decrease ref counters
Py_DECREF(arglist);
Py_DECREF(result);
}
// return None:
Py_RETURN_NONE;
}
static PyMethodDef SigPidMethods[] = {
{"register", sigpid_register, METH_VARARGS, "Register callback for SIGUSR1"},
{"ping", sigpid_ping, METH_VARARGS, "Test if callback is working"},
{NULL, NULL, 0, NULL},
};
PyMODINIT_FUNC initsigpid(void) {
// initialize module:
(void) Py_InitModule("sigpid", SigPidMethods);
// set sighandler:
struct sigaction act;
memset(&act, '\0', sizeof(act));
act.sa_sigaction = &direct_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &act, NULL);
}
setup.py for building the module:
from distutils.core import setup, Extension
module1 = Extension('sigpid', sources= ['sigpidmodule.c'])
setup (name='SigPid', version='1.0',
description='SigPidingStuff',
ext_modules = [module1])
building the module with
python setup.py build
So, what's still missing is the python script using the module: test.py
import sigpid
import time, os
def callme(num, pid):
'''
Callback function to be called from c module
'''
print "py: got %d from %d\n" % (num, pid)
# register the callback:
sigpid.register(callme)
print "py: Hi, I'm %d, talk to me with 'kill -SIGUSR1 %d'" %(os.getpid(),os.getpid())
# wait for signal while doing nothing:
while True:
time.sleep(1)
Everything works very well... up to:
python test.py
or as I have to actually call it to get the lib right:
PYTHONPATH=build/lib.linux-i686-2.6 python test.py
output:
c: callback now: 0xb744f534
py: Hi, I'm 2255, talk to me with 'kill -SIGUSR1 2255'
(from other term: kill -SIGUSR1 2255)
c: Signal reached c handler: signum=10, pid=2948, handler=0xb744f534
c: calling python callback
Segmentation fault
I don't know why I get this segfault, and I'm running out of ideas to fix it. I guess it must have something to do with how c and python interact (I can think of some reasons, but it's all only guessing). Maybe someone with more experience in c-python-interaction can help here (or at least explain, what's the problem exactly). We might have a way to solve the problem there, at least on linux.

- 7,354
- 4
- 36
- 61
It's a non-blocking method to get a child PID which has triggered SIGCHLD signal in Unix:
import os
import signal
def sigchld_handler(_sig, _frame):
try:
child_pid, _ = os.waitpid(-1, os.WNOHANG)
except OSError:
return
print(child_pid)
signal.signal(signal.SIGCHLD, sigchld_handler)

- 1,787
- 1
- 29
- 45
I believe it is not possible - the OS just does not pass this information to the target process.

- 43,216
- 11
- 77
- 90
-
That's not true, of course OS provides this info. Here is an example C program that shows how to do it. https://github.com/vjardin/siginfo_t – Vlad Jul 19 '20 at 03:14