I have a Qt application that connects to a card reader using various pcsc
implementations under GNU/Linux, MacOS, and Windows. All communication with the card runs in a worker thread.
In one scenario, the user starts an operation requiring communication with the card via a card reader. The card reader has a keyboard and during the authentication procedure the user must enter their PIN on the reader's keyboard.
This operation is implemented by a call to SCardControl()
(see e.g. the Microsoft documentation). As long as the user is working with the reader, the call to SCardControl()
does not terminate and the worker thread is blocked by it.
At this point, the user might decide to close the application while the operation is still pending. Closing the application at this point causes the application to crash (on Linux with signal SIGABRT
) because:
- The worker thread is blocked waiting for
SCardControl()
to return. - The main thread cannot stop the blocked thread: neither
quit()
norterminate()
cause the thread to finish. - When the application is exited, the
QThread
object for the worker thread is destroyed and, since the thread is still running state, it throws a signal to indicate an error.
I have tried several solutions.
- Subclass
QThread
and create a worker thread which callssetTerminationEnabled(true);
to allow termination throughQThread::terminate()
. This does not work onMacOS
: whenQThread
is destroyed, the thread is still in a running state and the signalSIGABRT
is emitted. - Handle signal
SIGABRT
on shutdown and ignore it. This did not seem to be a good idea but I wanted to try it out before discarding it. After ignoring signalSIGABRT
, a signalSIGSEGV
is received and the application crashes. I had adapted the approach described here. - Try to unblock the thread by sending a command to the card reader from the main thread. I tried
SCardCancel()
,SCardDisconnect()
andSCardReleaseContext()
but none of these commands has any effect on the blocked thread.
I find it quite strange that it is not possible to cleanly shutdown an application when a thread is blocked on some function call, but all the solutions I have tried have not worked and I have run out of ideas. Did I overlook something? Does anybody have any useful hint?
EDIT
I looked into the Qt source code for QThread
and found out that on Unix-like platforms QThread::terminate()
uses pthread_cancel()
internally. But apparently pthread_cancel()
does not work / does nothing on Darwin
, see e.g. here and here.
So, maybe I will really have to go with the option of showing a dialog to the user asking to remove the card from the reader.