Closed elonen closed 6 years ago
I don't remember it being blocked on my machine, a fork used this: https://github.com/akito45/nfc-bindings/commit/496095bbf43d629fd18fb7015442e0e00f5f6916
Thanks for the pointer! Tried the akito45 -threads
swig option, but ctrl-c still simply prints '^C', and only shows the KeyboardInterrupt stack trace after I show a tag to the reader:
$ sudo venv/bin/python quick_start_example.py
Version: debian/1.7.1-3-1-g0599c08
NFC reader: SCM Micro / SCL3711-NFC&RW opened
^C
( The execution blocks here. Showing a card to the reader, it continues with: )
Traceback (most recent call last):
File "quick_start_example.py", line 29, in <module>
ret = nfc.initiator_select_passive_target(pnd, nmMifare, 0, 0, nt)
File "/home/pi/nfc/venv/lib/python3.4/site-packages/nfc.py", line 205, in initiator_select_passive_target
return _nfc.initiator_select_passive_target(*args)
KeyboardInterrupt
The nfc-poll
example program (written in C) interrupts just fine, so it doesn't seem to be a libnfc or driver issue. I've never written a Python extension, but from what I've understood, this sounds like a GIL problem. I'm using Python 3.4.
I thought maybe the -threads
addition didn't actually do anything, so I grepped for it. The last line contains: swig2.0 -python -threads -ignoremissing
:
$ grep -r threads *
CMakeFiles/CMakeOutput.log:Configured with: ../src/configure -v --with-pkgversion='Raspbian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
CMakeFiles/CMakeOutput.log: ignore line: [Configured with: ../src/configure -v --with-pkgversion='Raspbian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf]
python/CMakeLists.txt:set (CMAKE_SWIG_FLAGS "-threads -ignoremissing")
python/CMakeFiles/_nfc.dir/build.make: cd /home/pi/nfc/nfc-bindings/python && /usr/bin/swig2.0 -python -threads -ignoremissing -outdir /home/pi/nfc/nfc-bindings/python -I/usr/include -I/home/pi/nfc/nfc-bindings/python -I/usr/include/python3.4m -o /home/pi/nfc/nfc-bindings/python/nfcPYTHON_wrap.c /home/pi/nfc/nfc-bindings/nfc.i
python/nfcPYTHON_wrap.c:# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */
Reading through the web, I next tried (without really understanding what's going on behind the scenes) adding...
%exception nfc_initiator_select_passive_target {
Py_BEGIN_ALLOW_THREADS
$action
Py_END_ALLOW_THREADS
}
int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt);
...but that resulted in immediate termination:
Version: debian/1.7.1-3-1-g0599c08
NFC reader: SCM Micro / SCL3711-NFC&RW opened
Fatal Python error: PyEval_SaveThread: NULL tstate
could you try to put this somewhere at the beginning of the generated nfc.py ? (without -threads)
# Reset the default Crtl-C behavior
import signal
try:
signal.signal(signal.SIGINT, signal.SIG_DFL)
except ValueError:
pass
Tried, no effect. Also, as I wrote earlier, the call seems to halt the whole program, even if called from a separate thread.
BTW: nfc.initiator_target_is_present()
doesn't seem to block.
are you sure you're not getting the same behavior from C, ie if you translate quick_start_example.py to c does it interrupt ?
I can't write a complete conversion right now, but at editing nfc-poll.c so that...
if ((res = nfc_initiator_poll_target(pnd, nmModulations, szModulations, uiPollNr, uiPeriod, &nt)) < 0) {
nfc_perror(pnd, "nfc_initiator_poll_target");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
...changes into:
res = nfc_initiator_select_passive_target(pnd, *nmModulations, 0, 0, &nt);
...interrupts just fine, so at least the function itself doesn't seem to be broken.
Here's the page that led me to try the Py_BEGIN_ALLOW_THREADS directive:
Has anyone managed to resolve this? I've got the same issue on a Raspberry Pi, latest version of Arch Linux ARM, libnfc 1.7.1 and Python 3.6.0.
fixed in d2582a4, feedback welcome
While testing
quick_start_example.py
(on a Raspberry PI with SCL3711 USB NFC reader), I found the example script cannot be interrupted with Ctrl-C. It only reacts after I actually show a tag.Additionally, in my own application which is using run_in_executor (multithreading) on asyncio,
initiator_select_passive_target(...)
seems to somehow block the entire program (main thread) in a similar way, not only the thread it's running in.Is this an intended behavior and/or am I perhaps using it incorrectly?