问题描述
我已经尝试使用 sigaction 和 ctypes 设置信号处理程序.(我知道它可以在 python 中使用信号模块,但我想尝试学习.)
当我将 SIGTERM 发送到此进程,但它不调用我设置的处理程序时,只打印已终止".为什么它不调用处理程序?
我使用 Ubuntu 19.10 和 Python 3.7.5 x64.
import ctypes从 ctypes 导入 *从 ctypes.util 导入 *从 os 导入 getpid类 sigset_t(结构):__字段__ = [("__val", c_ulong*16)]类 sigval_t(联合):__字段__ = [("sival_int", c_int),("sival_ptr", c_void_p)]类 siginfo_t(结构):__字段__ = [("si_signo", c_int),("si_errno", c_int),("si_code", c_int),("si_trapno", c_int),("si_pid", c_uint),("si_status", c_int),("si_utime", c_long),("si_stime", c_long),("si_value", sigval_t),("si_int", c_int),("si_ptr", c_void_p),("si_overrun", c_int),("si_timerid", c_int),("si_addr", c_void_p),("si_band", c_long),("si_fd", c_int),("si_addr_lsb", c_short),("si_call_addr", c_void_p),("si_syscall", c_int),(si_arch",c_uint)]sa_handler_functype = CFUNCTYPE(无,c_int)sigaction_functype = CFUNCTYPE(无,c_int,siginfo_t,c_void_p)类SIGACTION(结构):__字段__ = [(sa_handler",sa_handler_functype),("sa_sigaction", sigaction_functype),(sa_mask",sigset_t),("sa_flags", c_int),]def p(sig): # 信号处理函数libc.puts("再见")libc_path = find_library("c")libc = CDLL(libc_path)libc.sigaction.restype = c_intlibc.sigaction.argtypes = [c_int, POINTER(SIGACTION), POINTER(SIGACTION)]行为 = SIGACTION(sa_handler=sa_handler_functype(p))打印(行为)res = libc.sigaction(15, act, None)打印(资源)print("pid:", getpid()) # 显示pidwhile True: # 等待直到收到 sigterm 信号经过
Listing [Python 3.Docs]: ctypes - Python 的外部函数库.
代码有问题:
- ctypes.Structure 后代需要定义_fields_(而不是 __fields__).相应地改变了结构
- 将
struct sigaction *
(指针)作为参数传递给 sigaction - 根据 /usr/include/bits 中文件的内容修改结构定义(在我的 Ubtu 16 x64 VM 上)
- 为任何使用的函数(puts)定义了argtypes和restype.检查 [SO]:C 函数调用从 Python 通过 ctypes 返回不正确的值(@CristiFati 的回答) 了解更多详情
- 其他(次要)变化
code00.py:
#!/usr/bin/env python3导入系统导入操作系统导入时间从 ctypes 导入结构、联合、指针、CFUNCTYPE、CDLL、byref、sizeof、\c_short、c_int、c_uint、c_long、c_ulong、c_char_p、c_void_pSIGTERM = 15类 sigset_t(结构):_字段_ = [("__val", c_ulong * (1024//(8 * sizeof (c_long)))),]'''类 sigval_t(联合):_字段_ = [("sival_int", c_int),("sival_ptr", c_void_p),]类 siginfo_t(结构):_字段_ = [("si_signo", c_int),("si_errno", c_int),("si_code", c_int),("_pad", c_int * 29),]sa_sigaction_functype = CFUNCTYPE(无,c_int,指针(siginfo_t),c_void_p)'''sa_handler_functype = CFUNCTYPE(无,c_int,use_errno=True)类SIGACTION(结构):_字段_ = [(sa_handler",sa_handler_functype),(sa_mask",sigset_t),("sa_flags", c_int),("sa_restorer", c_void_p),]libc = CDLL(无)def sighhandler(sig): # 信号处理函数libc.puts.argtypes = [c_char_p]libc.puts.restype = c_intlibc.puts("自定义信号处理程序调用信号{0:d}".format(sig).encode())def main(*argv):libc.sigaction.argtypes = [c_int, POINTER(SIGACTION), POINTER(SIGACTION)]libc.sigaction.restype = c_int信号编号 = SIGTERM行为 = SIGACTION(sa_handler=sa_handler_functype(sighandler))#打印(行为)res = libc.sigaction(signal_number, byref(act), None)print("sigaction 结果:{0:d}".format(res))打印(PId {0:d}等待SIG {1:d}...".格式(os.getpid(),signal_number))而 1:时间.睡眠(0.1)如果 __name__ == "__main__":print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 如果 sys.maxsize > 0x100000000 否则 32, sys.platform))main(*sys.argv[1:])打印(\n完成.")
输出(程序运行时,发送两次SIGTERM,然后从另一个终端发送SIGKILL):
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q059521251]>用户名 -mx86_64[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q059521251]>cat/etc/lsb-release |语法描述DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q059521251]>python3 code00.pyPython 3.5.2(默认,2019 年 10 月 8 日,13:06:37)[GCC 5.4.0 20160609] 64 位 Linux签名结果:0PId 20050 等待 SIG 15...自定义信号处理程序调用信号 15自定义信号处理程序调用信号 15被杀
I have tried set signal handler with sigaction and ctypes. (I know it is able to do with signal module in python, but I want to try it for learn.)
When I sent SIGTERM to this process, but it does not call handler that I set, only print "Terminated".Why it does not invoke the handler?
I using Ubuntu 19.10 and Python 3.7.5 x64.
import ctypes
from ctypes import *
from ctypes.util import *
from os import getpid
class sigset_t(Structure):
__fields__ = [
("__val", c_ulong*16)
]
class sigval_t(Union):
__fields__ = [
("sival_int", c_int),
("sival_ptr", c_void_p)
]
class siginfo_t(Structure):
__fields__ = [
("si_signo", c_int),
("si_errno", c_int),
("si_code", c_int),
("si_trapno", c_int),
("si_pid", c_uint),
("si_status", c_int),
("si_utime", c_long),
("si_stime", c_long),
("si_value", sigval_t),
("si_int", c_int),
("si_ptr", c_void_p),
("si_overrun", c_int),
("si_timerid", c_int),
("si_addr", c_void_p),
("si_band", c_long),
("si_fd", c_int),
("si_addr_lsb", c_short),
("si_call_addr", c_void_p),
("si_syscall", c_int),
("si_arch", c_uint)
]
sa_handler_functype = CFUNCTYPE(None, c_int)
sigaction_functype = CFUNCTYPE(None, c_int, siginfo_t, c_void_p)
class SIGACTION(Structure):
__fields__ = [
("sa_handler", sa_handler_functype),
("sa_sigaction", sigaction_functype),
("sa_mask", sigset_t),
("sa_flags", c_int),
]
def p(sig): # signal handler function
libc.puts("bye")
libc_path = find_library("c")
libc = CDLL(libc_path)
libc.sigaction.restype = c_int
libc.sigaction.argtypes = [c_int, POINTER(SIGACTION), POINTER(SIGACTION)]
act = SIGACTION(sa_handler=sa_handler_functype(p))
print(act)
res = libc.sigaction(15, act, None)
print(res)
print("pid:", getpid()) # show pid
while True: # wait until receive sigterm signal
pass
Listing [Python 3.Docs]: ctypes - A foreign function library for Python.
There are some problems with the code:
- ctypes.Structure descendants need to define _fields_ (and not __fields__). Changed the structures accordingly
- Passed a
struct sigaction *
(pointer) as argument to sigaction - Modified structures definitions based on contents from files in /usr/include/bits (on my Ubtu 16 x64 VM)
- Defined argtypes and restype for any used function (puts). Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for more details
- Other (minor) changes
code00.py:
#!/usr/bin/env python3
import sys
import os
import time
from ctypes import Structure, Union, POINTER, CFUNCTYPE, CDLL, byref, sizeof, \
c_short, c_int, c_uint, c_long, c_ulong, c_char_p, c_void_p
SIGTERM = 15
class sigset_t(Structure):
_fields_ = [
("__val", c_ulong * (1024 // (8 * sizeof (c_long)))),
]
'''
class sigval_t(Union):
_fields_ = [
("sival_int", c_int),
("sival_ptr", c_void_p),
]
class siginfo_t(Structure):
_fields_ = [
("si_signo", c_int),
("si_errno", c_int),
("si_code", c_int),
("_pad", c_int * 29),
]
sa_sigaction_functype = CFUNCTYPE(None, c_int, POINTER(siginfo_t), c_void_p)
'''
sa_handler_functype = CFUNCTYPE(None, c_int, use_errno=True)
class SIGACTION(Structure):
_fields_ = [
("sa_handler", sa_handler_functype),
("sa_mask", sigset_t),
("sa_flags", c_int),
("sa_restorer", c_void_p),
]
libc = CDLL(None)
def sighandler(sig): # Signal handler function
libc.puts.argtypes = [c_char_p]
libc.puts.restype = c_int
libc.puts("Custom signal handler called for signal {0:d}".format(sig).encode())
def main(*argv):
libc.sigaction.argtypes = [c_int, POINTER(SIGACTION), POINTER(SIGACTION)]
libc.sigaction.restype = c_int
signal_number = SIGTERM
act = SIGACTION(sa_handler=sa_handler_functype(sighandler))
#print(act)
res = libc.sigaction(signal_number, byref(act), None)
print("sigaction result: {0:d}".format(res))
print("PId {0:d} waiting for SIG {1:d}...".format(os.getpid(), signal_number))
while 1:
time.sleep(0.1)
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main(*sys.argv[1:])
print("\nDone.")
Output (while program running, sent SIGTERM twice then SIGKILL from another terminal):
这篇关于尽管我在 python ctypes 中设置了信号处理程序,但不会调用它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!