【问题标题】:Get pid of the process which has triggered some signal获取触发某些信号的进程的pid
【发布时间】:2011-02-11 21:16:21
【问题描述】:

是否有可能找出导致某些信号的进程的进程 ID。在我的场景中,我有一个进程的多个子进程正在运行,我想知道它们中的哪一个发送了信号。

【问题讨论】:

    标签: python signals


    【解决方案1】:

    (终于!)使用 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))
    

    【讨论】:

    • 有没有办法在信号处理程序中获取 siginfo?我的用例是尝试调试来自其他一些完全未知的进程(实际上不是键盘)的意外 KeyboardInterrupt。
    • @szmoore 不幸的是我不知道...但除非我错了,否则您应该可以在临时线程中使用signal.sigwaitinfo(而不是signal.signal),这应该允许您在不中断主线程的情况下调试中断。
    【解决方案2】:

    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
    

    或者因为我必须实际调用它才能获得正确的库:

    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 上是这样。

    【讨论】:

      【解决方案3】:

      这是一种非阻塞方法来获取触发了SIGCHLD信号在Unix中的子PID:

      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)
      

      【讨论】:

        【解决方案4】:

        我认为这是不可能的 - 操作系统只是不将此信息传递给目标进程。

        【讨论】:

        • 这不是真的,当然操作系统提供了这个信息。这是一个示例 C 程序,展示了如何执行此操作。 github.com/vjardin/siginfo_t
        猜你喜欢
        • 1970-01-01
        • 2015-05-11
        • 2011-09-13
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        • 2021-08-08
        • 2016-01-31
        相关资源
        最近更新 更多