是否有可能找出导致某些信号的过程的进程ID。在我的场景中,我有一个进程正在运行的多个子节点,我想知道它们中的哪一个发送了信号。
答案 0 :(得分:6)
使用python 3(#终于!)非常简单。
以下是使用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))
答案 1 :(得分:5)
POSIX Linux 提供此信息,请查看man sigaction(2):http://linux.die.net/man/2/sigaction
在C中,我设法让它轻松运行:
#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;
}
与我的3.1.6 vanilla内核和gcc 4.4.5一起工作得很好 - 但我在python中找不到任何支持。
所以我开始尝试自己构建一些东西(但是因为我以前从未做过C / Python-Interaction,所以它可能在某种程度上扭曲了......)
我或多或少地接近http://docs.python.org/extending/extending.html的示例并根据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用于构建模块:
from distutils.core import setup, Extension
module1 = Extension('sigpid', sources= ['sigpidmodule.c'])
setup (name='SigPid', version='1.0',
description='SigPidingStuff',
ext_modules = [module1])
使用
构建模块python setup.py build
所以,仍然缺少的是使用模块的python脚本: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)
一切都很顺利......直到:
python test.py
或者我必须实际调用它以使lib正确:
PYTHONPATH=build/lib.linux-i686-2.6 python test.py
输出:
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
我不知道为什么我会遇到这个段错误,而且我的想法已经用完了。我想它必须与c和python的交互方式有关(我可以想到一些原因,但这只是猜测)。也许在c-python-interaction方面有更多经验的人可以在这里提供帮助(或至少解释一下,究竟是什么问题)。我们可能有办法在那里解决问题,至少在linux上。
答案 2 :(得分:0)
这是一种获取子PID的非阻塞方法,该子PID在Unix中已触发 SIGCHLD 信号 :
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)
答案 3 :(得分:-2)
不,这是不可能的,OS(可能是* nix)根本不提供此信息。您需要使用其他类型的IPC来从您的子进程通信到父进程。如果你还没有使用它,你应该查看subprocess模块,它可以让这些事情变得简单。
例如,如果您将子进程中的管道设置为父级,则可以让孩子在之前发送信号时向管道写入消息。您的父进程可以使用select调用等待,直到它收到来自其中一个子进程的消息。
这只是解决IPC问题的一种方法;除了其他方法之外,您还可以使用sockets或multiprocessing模块。如果不了解您正在尝试做的事情,就很难再给出更多建议。
答案 4 :(得分:-3)
我认为这是不可能的 - 操作系统不会将此信息传递给目标进程。