Reputation: 47
I am creating a Python wrapper for a C-extension which is a driver for a sensor. I need to pass the Ctrl-C interrupt signal with Python to the driver so it ends the current acquisition phase and does not start a new one. I found these two related subjects : Allowing Ctrl-C to interrupt a python C-extension Allowing Ctrl-C to interrupt a python C-extension However they do not answer my question as I am using Ctypes (see below). Is there a way to interupt the C-extension using Python's threads or ctypes. I would like to avoid any change on the C code. Goal would be to stop the endless loop function
Python code:
import signal
import ctypes
import os
import sys
if __name__ == "__main__" :
libname = os.path.abspath(os.path.join(os.path.dirname(__file__),"clib.so"))
LIBC = ctypes.CDLL(libname)
LIBC.main.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p),]
args=(ctypes.c_char_p * (len(sys.argv)-1))(str.encode(sys.argv[1]))
LIBC.main(len(args),args)
signal.signal(signal.SIGINT, lambda s,f:os.kill(os.getpid(), signal.SIGTERM))
C Code :
#include <stdlib.h>
#include <stdio.h>
#incluse <string.h>
void endless_loop()
{
while(1){printf("Can't stop me ! \n");}
}
int main(int argc, char* argv[])
{
endless_loop();
return 0 ;
}
Makefile:
all: test
clean:
rm -f *.o *.so *.html
clib.so: clib.o
gcc -shared -o clib.so clib.c -fPIC
clib.o: clib.c
gcc -Wall -Werror clib.c -fPIC
test: clib.so
chmod 777 pyclib.py
python pyclib.py 2
Thankfully,
Upvotes: 4
Views: 673
Reputation: 19375
LIBC.main(len(args),args) signal.signal(signal.SIGINT, lambda s,f:os.kill(os.getpid(), signal.SIGTERM))
If you want the signal handler to be invoked while LIBC.main
is running, you must install it (via signal.signal
) before LIBC.main
is called, not after it returns.
But, as you noticed: It still does't work. That's because a Python signal handler doesn't get executed while the C-extension is running, and since Python on its own initiative installs a SIGINT handler, by default Ctrl-C doesn't work under this condition. In order to make it interrupt the program, restore the default signal behavior:
signal.signal(signal.SIGINT, signal.SIG_DFL)
LIBC.main(len(args), args)
Upvotes: 4