到Python ini的Linux阻塞信号

2024-06-01 01:45:26 发布

您现在位置:Python中文网/ 问答频道 /正文

{我的另一个帖子是^我的后续文章。简而言之,除非Init为特定信号安装了信号处理程序,否则Linux会阻止发送到PID 1的所有信号(包括SIGKILL);以防止有人向PID1发送终止信号时出现内核恐慌。我遇到的问题是,Python中的signal模块似乎没有以系统识别的方式安装信号处理程序。我的Python Init脚本似乎完全忽略了所有信号,因为我认为它们被阻塞了。在

我似乎找到了一个解决方案:使用ctypes在libc中安装带有signal()函数的信号处理程序(在本例中是uClibc)。下面是一个基于python的测试初始化。它在TTY2上打开了一个shell,我可以从这个shell向PID1发送信号进行测试。它似乎可以在用于测试的kvmim中工作(我愿意与感兴趣的人共享VM)

这是解决这个问题的最好办法吗?有没有更好的方法来安装没有信号模块的信号处理器?(我一点也不关心便携性)

这是Python中的bug吗?在

#!/usr/bin/python

import os
import sys
import time

from ctypes import *

def SigHUP():
    print "Caught SIGHUP"
    return 0

def SigCHLD():
    print "Caught SIGCHLD"
    return 0

SIGFUNC = CFUNCTYPE(c_int)
SigHUPFunc = SIGFUNC(SigHUP)
SigCHLDFunc = SIGFUNC(SigCHLD)

libc = cdll.LoadLibrary('libc.so.0')
libc.signal(1, SigHUPFunc) # 1 = SIGHUP
libc.signal(17, SigCHLDFunc) # 17 = SIGCHLD

print "Mounting Proc: %s" % libc.mount(None, "/proc", "proc", 0, None)

print "forking for ash"
cpid = os.fork()
if cpid == 0:
    os.closerange(0, 4)
    sys.stdin = open('/dev/tty2', 'r')
    sys.stdout = open('/dev/tty2', 'w')
    sys.stderr = open('/dev/tty2', 'w')
    os.execv('/bin/ash', ('ash',))

print "ash started on tty2"

print "sleeping"
while True:
    time.sleep(0.01)

Tags: devimport程序signal信号initossys
2条回答

我在KVM下做了一些调试,发现当信号处理程序由标准信号模块安装时,内核将信号传递到pid 1。但是,当接收到信号时,“something”会生成进程的克隆,而不是打印预期的输出。在

这是我把HUP发送到非工作状态时的strace输出初始信号-型号:

strace output

这将导致运行一个新进程(pid 23),该进程是初始信号-型号:

clone of init as pid 23

我没有时间深入调查原因,但这使事情进一步缩小。可能与Python的信号传递逻辑有关(它注册一个C钩子,在调用时调用字节码函数)。ctypes技术绕过了这个问题。相关的Python源文件是Python/pythonrun.cModules/signalmodule.c,以防您进一步了解。在

旧信息我不确定这是否能解决您的问题,但可能会让您更亲近。我 比较了信号处理程序的安装方式:

  • 通过Python的信号模块安装处理程序。在
  • 新贵的信号处理程序。在
  • 使用ctypes直接调用signal()系统调用。在
  • 一些C语言的快速测试

两个ctypes都调用了signal()系统调用和Upstart的sigaction() syscalls在注册处理程序时设置SA_RESTART标志。设置 此标志表示当进程接收到信号时 在某些系统调用中执行或阻塞(读、写、等待、, 在信号处理程序完成系统调用后 自动重新启动。应用程序不会意识到这一点。在

当Python的信号模块注册一个处理程序时,它会将sau重新启动归零 通过调用siginterrupt(signum, 1)来标记。这对系统说“当 信号处理程序完成后,系统调用被信号中断 将errno设置为EINTR并从syscall返回”。这就留给了开发者 处理此问题并决定是否重新启动系统调用。在

您可以通过以下方式注册信号来设置SA_RESTART标志:

import signal
signal.signal(signal.SIGHUP, handler)
signal.siginterrupt(signal.SIGHUP, False)

问题是在uclibc0.9.31上编译的Python与旧linux线程的兼容性问题。根据0.9.32-rc3编译并使用NPTL解决了这个问题。在

相关问题 更多 >