Skip to content
Advertisement

Interrupting a Python C-extension with Ctrl-C using ctypes

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,

Advertisement

Answer

    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)
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement