2828#include " threads/waitforcardthread.hpp"
2929
3030#include " utils/utils.hpp"
31+
3132#include " inputoutputmode.hpp"
3233#include " writeresponse.hpp"
3334
@@ -44,19 +45,11 @@ const QString RESP_USER_CANCEL = QStringLiteral("ERR_WEBEID_USER_CANCELLED");
4445
4546QVariantMap makeErrorObject (const QString& errorCode, const QString& errorMessage)
4647{
47- const auto errorBody = QVariantMap {
48- {QStringLiteral (" code" ), errorCode},
49- {QStringLiteral (" message" ), errorMessage},
50- };
51- return {{QStringLiteral (" error" ), errorBody}};
52- }
53-
54- void interruptThread (QThread* thread)
55- {
56- qDebug () << " Interrupting thread" << uintptr_t (thread);
57- thread->disconnect ();
58- thread->requestInterruption ();
59- ControllerChildThread::waitForControllerNotify.wakeAll ();
48+ return {{QStringLiteral (" error" ),
49+ QVariantMap {
50+ {QStringLiteral (" code" ), errorCode},
51+ {QStringLiteral (" message" ), errorMessage},
52+ }}};
6053}
6154
6255} // namespace
@@ -111,11 +104,14 @@ void Controller::startCommandExecution()
111104 REQUIRE_NON_NULL (commandHandler)
112105
113106 // Reader monitor thread setup.
114- WaitForCardThread* waitForCardThread = new WaitForCardThread (this );
107+ auto * waitForCardThread = new WaitForCardThread (this );
108+ connect (this , &Controller::stopCardEventMonitorThread, waitForCardThread,
109+ &WaitForCardThread::requestInterruption);
115110 connect (waitForCardThread, &WaitForCardThread::statusUpdate, this , &Controller::statusUpdate);
116111 connect (waitForCardThread, &WaitForCardThread::cardsAvailable, this ,
117112 &Controller::onCardsAvailable);
118- saveChildThreadPtrAndConnectFailureFinish (waitForCardThread);
113+ connect (waitForCardThread, &ControllerChildThread::failure, this ,
114+ &Controller::onCriticalFailure);
119115
120116 // UI setup.
121117 window = WebEidUI::createAndShowDialog (commandHandler->commandType ());
@@ -126,33 +122,6 @@ void Controller::startCommandExecution()
126122 waitForCardThread->start ();
127123}
128124
129- void Controller::saveChildThreadPtrAndConnectFailureFinish (ControllerChildThread* childThread)
130- {
131- REQUIRE_NON_NULL (childThread)
132- // Save the thread pointer in child thread tracking map to request interruption and wait for
133- // it to quit in waitForChildThreads().
134- childThreads[uintptr_t (childThread)] = childThread;
135-
136- connect (childThread, &ControllerChildThread::failure, this , &Controller::onCriticalFailure);
137-
138- // When the thread is finished, remove the pointer from the tracking map and call deleteLater()
139- // on it to free the thread object. Although the thread objects are freed through the Qt object
140- // tree ownership system anyway, it is better to delete them immediately when they finish.
141- connect (childThread, &ControllerChildThread::finished, this , [this , childThread]() {
142- QScopedPointer<ControllerChildThread, QScopedPointerDeleteLater> deleteLater {childThread};
143-
144- const auto threadPtrAddress = uintptr_t (childThread);
145- if (childThreads.count (threadPtrAddress) && childThreads[threadPtrAddress]) {
146- childThreads[threadPtrAddress] = nullptr ;
147- childThread->wait ();
148- qDebug () << " Thread" << threadPtrAddress << " finished" ;
149- } else {
150- qWarning () << " Controller child thread" << childThread
151- << " is missing or null in finish slot" ;
152- }
153- });
154- }
155-
156125void Controller::connectOkCancelWaitingForPinPad ()
157126{
158127 REQUIRE_NON_NULL (window)
@@ -192,9 +161,10 @@ void Controller::onCardsAvailable(
192161void Controller::runCommandHandler (const std::vector<ElectronicID::ptr>& availableEids)
193162{
194163 try {
195- CommandHandlerRunThread * commandHandlerRunThread =
164+ auto * commandHandlerRunThread =
196165 new CommandHandlerRunThread (this , *commandHandler, availableEids);
197- saveChildThreadPtrAndConnectFailureFinish (commandHandlerRunThread);
166+ connect (commandHandlerRunThread, &ControllerChildThread::failure, this ,
167+ &Controller::onCriticalFailure);
198168 connectRetry (commandHandlerRunThread);
199169
200170 // When the command handler run thread retrieves certificates successfully, call
@@ -213,51 +183,32 @@ void Controller::runCommandHandler(const std::vector<ElectronicID::ptr>& availab
213183
214184void Controller::onCertificatesLoaded ()
215185{
216- CardEventMonitorThread* cardEventMonitorThread =
217- new CardEventMonitorThread (this , std::string (commandType ()));
218- saveChildThreadPtrAndConnectFailureFinish (cardEventMonitorThread);
219- cardEventMonitorThreadKey = uintptr_t (cardEventMonitorThread);
186+ auto * cardEventMonitorThread = new CardEventMonitorThread (this , commandType ());
187+ connect (cardEventMonitorThread, &ControllerChildThread::failure, this ,
188+ &Controller::onCriticalFailure);
189+ connect (this , &Controller::stopCardEventMonitorThread, cardEventMonitorThread,
190+ &WaitForCardThread::requestInterruption);
220191 connect (cardEventMonitorThread, &CardEventMonitorThread::cardEvent, this , &Controller::onRetry);
221192 cardEventMonitorThread->start ();
222193}
223194
224- void Controller::stopCardEventMonitorThread ()
225- {
226- if (cardEventMonitorThreadKey) {
227- try {
228- auto cardEventMonitorThread = childThreads.at (cardEventMonitorThreadKey);
229- cardEventMonitorThreadKey = 0 ;
230- if (cardEventMonitorThread) {
231- interruptThread (cardEventMonitorThread);
232- }
233- } catch (const std::out_of_range&) {
234- qWarning () << " Card event monitor thread" << cardEventMonitorThreadKey
235- << " is missing from childThreads map in stopCardEventMonitorThread()" ;
236- cardEventMonitorThreadKey = 0 ;
237- }
238- }
239- }
240-
241195void Controller::disposeUI ()
242196{
243- if (window) {
244- window->disconnect ();
245- // As the Qt::WA_DeleteOnClose flag is set, the dialog is deleted automatically.
246- window->close ();
247- window = nullptr ;
248- }
197+ delete window;
198+ window = nullptr ;
249199}
250200
251201void Controller::onConfirmCommandHandler (const EidCertificateAndPinInfo& certAndPinInfo)
252202{
253- stopCardEventMonitorThread ();
203+ emit stopCardEventMonitorThread ();
254204
255205 try {
256- CommandHandlerConfirmThread * commandHandlerConfirmThread =
206+ auto * commandHandlerConfirmThread =
257207 new CommandHandlerConfirmThread (this , *commandHandler, window, certAndPinInfo);
258208 connect (commandHandlerConfirmThread, &CommandHandlerConfirmThread::completed, this ,
259209 &Controller::onCommandHandlerConfirmCompleted);
260- saveChildThreadPtrAndConnectFailureFinish (commandHandlerConfirmThread);
210+ connect (commandHandlerConfirmThread, &ControllerChildThread::failure, this ,
211+ &Controller::onCriticalFailure);
261212 connectRetry (commandHandlerConfirmThread);
262213
263214 commandHandlerConfirmThread->start ();
@@ -373,18 +324,15 @@ void Controller::exit()
373324
374325void Controller::waitForChildThreads ()
375326{
376- // Waiting for child threads must not happen in destructor.
377- // See https://tombarta.wordpress.com/2008/07/10/gcc-pure-virtual-method-called/ for details.
378- for (const auto & childThread : childThreads) {
379- auto thread = childThread.second ;
380- if (thread) {
381- interruptThread (thread);
382- // Waiting for PIN input on PIN pad may take a long time, call processEvents() so that
383- // the UI doesn't freeze.
384- while (thread->isRunning ()) {
385- thread->wait (100 ); // in milliseconds
386- QCoreApplication::processEvents ();
387- }
327+ for (auto * thread : findChildren<QThread*>()) {
328+ qDebug () << " Interrupting thread" << uintptr_t (thread);
329+ thread->disconnect ();
330+ thread->requestInterruption ();
331+ ControllerChildThread::waitForControllerNotify.wakeAll ();
332+ // Call processEvents() so that the UI doesn't freeze.
333+ while (thread->isRunning ()) {
334+ thread->wait (100ms);
335+ QCoreApplication::processEvents ();
388336 }
389337 }
390338}
0 commit comments