Obtener pid del proceso que ha activado alguna señal.

¿Es posible averiguar el identificador de proceso del proceso que ha causado alguna señal? En mi caso, tengo varios hijos de un proceso en ejecución, y quiero saber cuál de ellos envió la señal.

Es (¡por fin!) Muy simple con python 3.

Lo siguiente se prueba con 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)) 

POSIX Linux proporciona esta información, verifique man sigaction (2): http://linux.die.net/man/2/sigaction

En C, logré que funcionara fácilmente:

 #include  #include  #include  #include  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; } 

Funciona bastante bien con mi kernel de vainilla 3.1.6 y gcc 4.4.5, pero no pude encontrar ningún soporte para ella en Python.

Así que comencé a intentar y construir algo por mi cuenta (pero como nunca antes había hecho C / Python-Interaction, es probable que de alguna manera esté torcido …)

Estoy más o menos cerca del ejemplo en http://docs.python.org/extending/extending.html y construyendo el módulo de acuerdo con http://docs.python.org/extending/building.html#building

sigpidmodule.c

 #include  #include  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 para construir el módulo:

 from distutils.core import setup, Extension module1 = Extension('sigpid', sources= ['sigpidmodule.c']) setup (name='SigPid', version='1.0', description='SigPidingStuff', ext_modules = [module1]) 

construyendo el modulo con

 python setup.py build 

Entonces, lo que todavía falta es la secuencia de comandos de python que utiliza el módulo: 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) 

Todo funciona muy bien … hasta

 python test.py 

o como tengo que llamarlo para obtener la liberación correcta:

 PYTHONPATH=build/lib.linux-i686-2.6 python test.py 

salida:

 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 

No sé por qué obtengo este fallo de seguridad, y me estoy quedando sin ideas para solucionarlo. Supongo que debe tener algo que ver con la forma en que interactúan c y python (puedo pensar en algunas razones, pero es solo adivinar). Tal vez alguien con más experiencia en la interacción c-python puede ayudar aquí (o al menos explicar, cuál es el problema exactamente). Podríamos tener una manera de resolver el problema allí, al menos en Linux.

No, no es posible, el sistema operativo (probablemente a * nix) simplemente no proporciona esta información. Deberá usar algún otro tipo de IPC para comunicarse desde los procesos secundarios a los padres. Si aún no lo está utilizando, debe revisar el módulo de subproceso , que facilita este tipo de cosas.

Por ejemplo, si configura tuberías desde sus procesos secundarios a sus padres, puede hacer que el niño escriba un mensaje en la tubería cuando anteriormente hubiera enviado una señal. El proceso de los padres puede usar una llamada de selección para esperar hasta que reciba un mensaje de uno de los hijos.

Esta es solo una de las formas en que puede abordar el problema de IPC; También puede trabajar con sockets , o el módulo de multiprocesamiento , entre otros enfoques. Sin saber más sobre lo que estás tratando de hacer, es difícil darte más consejos.

Creo que no es posible: el sistema operativo simplemente no pasa esta información al proceso objective.