{我的另一个帖子是^我的后续文章。简而言之,除非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)
我在KVM下做了一些调试,发现当信号处理程序由标准信号模块安装时,内核将信号传递到pid 1。但是,当接收到信号时,“something”会生成进程的克隆,而不是打印预期的输出。在
这是我把HUP发送到非工作状态时的strace输出初始信号-型号:
这将导致运行一个新进程(pid 23),该进程是初始信号-型号:
我没有时间深入调查原因,但这使事情进一步缩小。可能与Python的信号传递逻辑有关(它注册一个C钩子,在调用时调用字节码函数)。ctypes技术绕过了这个问题。相关的Python源文件是Python/pythonrun.c和Modules/signalmodule.c,以防您进一步了解。在
旧信息我不确定这是否能解决您的问题,但可能会让您更亲近。我 比较了信号处理程序的安装方式:
signal()
系统调用。在两个ctypes都调用了
signal()
系统调用和Upstart的sigaction()
syscalls在注册处理程序时设置SA_RESTART
标志。设置 此标志表示当进程接收到信号时 在某些系统调用中执行或阻塞(读、写、等待、, 在信号处理程序完成系统调用后 自动重新启动。应用程序不会意识到这一点。在当Python的信号模块注册一个处理程序时,它会将sau重新启动归零 通过调用
siginterrupt(signum, 1)
来标记。这对系统说“当 信号处理程序完成后,系统调用被信号中断 将errno设置为EINTR并从syscall返回”。这就留给了开发者 处理此问题并决定是否重新启动系统调用。在您可以通过以下方式注册信号来设置SA_RESTART标志:
问题是在uclibc0.9.31上编译的Python与旧linux线程的兼容性问题。根据0.9.32-rc3编译并使用NPTL解决了这个问题。在
相关问题 更多 >
编程相关推荐