Signal handler does not be invoked despite I have set it in python ctypes

Asked
Active3 hr before
Viewed126 times

5 Answers

handler
90%

Making statements based on opinion; back them up with references or personal experience.,Thanks for contributing an answer to Stack Overflow!, Is there any kind of biological mechanism that would allow a species with a naturally short lifespan to live longer through cannibalism? ,Connect and share knowledge within a single location that is structured and easy to search.

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.")
[cfati @cfati - ubtu16x64 - 0: ~/Work/Dev / StackOverflow / q059521251] > uname - m
x86_64
   [cfati @cfati - ubtu16x64 - 0: ~/Work/Dev / StackOverflow / q059521251] > cat / etc / lsb - release | grep DESCR
DISTRIB_DESCRIPTION = "Ubuntu 16.04.6 LTS" [cfati @cfati - ubtu16x64 - 0: ~/Work/Dev / StackOverflow / q059521251] > python3 code00.py
Python 3.5 .2(
   default, Oct 8 2019, 13: 06: 37)[GCC 5.4 .0 20160609] 64 bit on linux

sigaction result: 0
PId 20050 waiting
for SIG 15...
Custom signal handler called
for signal 15
Custom signal handler called
for signal 15
Killed
load more v
88%

Summary: A thread uses signals to the MainThread to signal an abnormal condition. The main thread is expected to get that signal, invoke the signal handler, and raise an exception. In combination with 'ctypes' calls, that does not happen.


Consider the following code:

------------------------------------------------
#!/usr/bin/env python

import multiprocessing as mp
import threading as mt
import signal
import time
import os

# from uuid.py line 400
import ctypes, ctypes.util
lib = ctypes.CDLL(ctypes.util.find_library('uuid'))

def sigusr2_handler(signum, frame):
raise RuntimeError('caught sigusr2')
signal.signal(signal.SIGUSR2, sigusr2_handler)

def sub(pid):
time.sleep(1)
os.kill(pid, signal.SIGUSR2)

try:
# p = mp.Process(target=sub, args=[os.getpid()])
# p.start()
t = mt.Thread(target=sub, args=[os.getpid()])
t.start()
time.sleep(3)
except Exception as e:
print 'except: %s' % e
else:
print 'unexcepted'
finally:
# p.join()
t.join()
------------------------------------------------

With Python 2.7 I would expect the output:
------------------------------------------------
except: caught sigusr2
------------------------------------------------

but I get:
------------------------------------------------
Traceback (most recent call last):
File "./bug.py", line 29, in <module>
   print 'unexcepted'
   File "./bug.py", line 13, in sigusr2_handler
   raise RuntimeError('caught sigusr2')
   File "./bug.py", line 29, in <module>
      print 'unexcepted'
      File "./bug.py", line 13, in sigusr2_handler
      raise RuntimeError('caught sigusr2')
      RuntimeError: caught sigusr2
      ------------------------------------------------


      most of the time. The problem only happens when the 'ctypes.CDLL' line is enabled -- commenting it out results in the expected behavior. That line is copied from uuid.py -- importing uuid.py triggers the same unexpected behavior, which is ultimately why I am stuck.

      Note that the problem only occurs when a *thread* sends the signal -- it does *not* happen if the signal is sent by the main thread or by a different process (switch to the multiprocessing code path for confirmation).

      Interestingly, the problem also disappears when a 'print' statement is added after the 'time.sleep(3)', which may (or may not) indicate a timing issue.

      I would welcome any suggestion on how to further triage this.
load more v
72%

On Windows, ctypes uses win32 structured exception handling to prevent crashes from general protection faults when functions are called with invalid argument values:,Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the stdcall calling convention, and are assumed to return int by default.,The returned function prototype creates functions that use the Python calling convention. The function will not release the GIL during the call.,Both of these factory functions are called with the result type as first argument, and the callback functions expected argument types as the remaining arguments.

>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32' , handle ... at ...>
   >>> print(cdll.msvcrt)
   <CDLL 'msvcrt' , handle ... at ...>
      >>> libc = cdll.msvcrt
      >>>
load more v
65%

windll does not try to select one of them by magic, you must access the version you need by specifying GetModuleHandleA or GetModuleHandleW explicitly, and then call it with bytes or string objects respectively.,This exception is raised when a foreign function call cannot convert one of the passed arguments.,arguments is a tuple containing the parameters originally passed to the function call, this allows to specialize the behavior on the arguments used.,For these cases, the cast() function is handy.

>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32' , handle ... at ...>
   >>> print(cdll.msvcrt)
   <CDLL 'msvcrt' , handle ... at ...>
      >>> libc = cdll.msvcrt
      >>>
load more v
75%

Be very careful: as the signal(7) page is telling, only very few functions (the "async-signal-safe" ones, see signal-safety(7) for more) can be (directly or indirectly) called inside signal handlers. Mutex related functions probably should not be called in signal handlers. See also pthreads(7),Installing a handler via Python's signal module.,a). Manually unblock SIGUSR before calling execl in sighandler:,Old Info -- I'm not sure this will solve your problem, but might get you closer. I compared these different ways signal handlers are installed:

You can set the SA_RESTART flag by registering your signal this way:

import signal
signal.signal(signal.SIGHUP, handler)
signal.siginterrupt(signal.SIGHUP, False)
load more v

Other "handler-undefined" queries related to "Signal handler does not be invoked despite I have set it in python ctypes"