2011-02-11 18 views

Respuesta

6

Es muy simple con Python 3.

La siguiente es probado con Python 3.3.3 (por fin!):

#! /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)) 
-3

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

+0

Gracias por la aclaración. –

-2

No, no es posible, el sistema operativo (presumiblemente a * nix) simplemente no proporciona esta información. Tendrá que usar algún otro tipo de IPC para comunicarse desde los procesos de su hijo al padre. Si aún no lo está utilizando, debería verificar el módulo subprocess, que facilita este tipo de cosas.

Por ejemplo, si configura las canalizaciones de sus procesos secundarios a su padre, puede hacer que el niño escriba un mensaje en el conducto cuando ya habría enviado una señal. El proceso principal puede usar una llamada select para esperar hasta que reciba un mensaje de uno de los hijos.

Esta es solo una forma de abordar el problema del IPC; también puede trabajar con sockets, o el módulo multiprocessing, entre otros enfoques. Sin saber más acerca de lo que intentas hacer, es difícil darte más consejos.

+0

gracias ... Ya estoy usando el módulo de subproceso. Estoy usando esperar() para esperar. Pero quería usar signal.pause() que podría hacer que el proceso padre durmiera hasta que uno de los hijos muera. Esto ahorrará ciclos de CPU. –

5

POSIX Linux no proporcionar esta información, compruebe sigaction hombre (2): http://linux.die.net/man/2/sigaction

En C, logré hacerlo funcionar fácilmente:

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

funciona bastante bien con mi 3.1 .6 vainilla kernel y gcc 4.4.5 - pero no pude encontrar ningún soporte para ello en python.

así que empecé a tratar de construir algo por mi cuenta (pero ya que nunca hice C/Python-Interacción antes, es probable que de algún modo torcido ...)

estoy más o menos manteniéndose cerca de el ejemplo de la http://docs.python.org/extending/extending.html y construir el módulo de acuerdo con 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 para la construcción del 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]) 

la construcción del módulo con

python setup.py build 

Por lo tanto, lo que aún falta es la secuencia de comandos de Python usando 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 realmente llamarlo para obtener el derecho lib:

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

de 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é me sale esto segfault, y me estoy quedando sin ideas para arreglarlo. Supongo que debe tener algo que ver con cómo c y Python interactúan (puedo pensar en algunas razones, pero todo es solo adivinar). Tal vez alguien con más experiencia en c-python-interaction pueda ayudar aquí (o al menos explicar, cuál es el problema exactamente). Es posible que tengamos una forma de resolver el problema allí, al menos en Linux.

Cuestiones relacionadas