4

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,

1
  • have you tried telling the C extension to not loop endlessly - e.g. give it a parameter with the number of readings to collect? Then you won't have the signal problem. Commented Jul 19, 2021 at 15:32

1 Answer 1

4
    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)
Sign up to request clarification or add additional context in comments.

4 Comments

This is a citation of your code, as one can tell from the vertical line to the left.
I amended the answer.
Thank you a lot, it is working ! May I ask you some details on your explanation, or a link if you don't want to explain (which I can understand) ? You say Python installs a SIGINT handler, why a different signal than what I guess is default ?
I'll gladly explain, but I'm not sure how to understand your question about a different signal than what I guess. We are talking about just one signal, namely SIGINT. SIG_DFL ist not a signal, it's a special identifier denoting that the normal handling of the given signal is to be reinstated, which for SIGINT is to terminate the process.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.