From 06d31638e241467c061f3688f1697fcce24b410a Mon Sep 17 00:00:00 2001 From: Florian Ramillien Date: Tue, 22 Dec 2015 10:58:35 +0100 Subject: [PATCH] src: handle last event before exit status threads - Avoid 2 consecutive calls to uv_async_send when exiting the cardreader.cpp check status thread. - Fix mutex unlock location in cardreader.cpp check status thread. PR-URL: https://github.com/santigimeno/node-pcsclite/pull/46 Reviewed-By: Santiago Gimeno --- src/cardreader.cpp | 44 ++++++++++++++++++++++++-------------------- src/pcsclite.cpp | 25 +++++++++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/cardreader.cpp b/src/cardreader.cpp index e858808..4f2ab89 100644 --- a/src/cardreader.cpp +++ b/src/cardreader.cpp @@ -333,16 +333,10 @@ void CardReader::HandleReaderStatusChange(uv_async_t *handle, int status) { AsyncResult* ar = async_baton->async_result; - if (ar->do_exit) { - uv_close(reinterpret_cast(&async_baton->async), CloseCallback); // necessary otherwise UV will block - - /* Emit end event */ - Local argv[1] = { - Nan::New("_end").ToLocalChecked(), // event name - }; - - Nan::MakeCallback(async_baton->reader->handle(), "emit", 1, argv); - } else { + if (reader->m_state == 1) { + // Swallow events : Listening thread was cancelled by user. + } else if ((ar->result == SCARD_S_SUCCESS) || + (ar->result == (LONG)SCARD_E_NO_READERS_AVAILABLE)) { // Card reader was unplugged, it's not an error if (ar->result == SCARD_S_SUCCESS) { const unsigned argc = 3; Local argv[argc] = { @@ -361,6 +355,17 @@ void CardReader::HandleReaderStatusChange(uv_async_t *handle, int status) { } } + if (ar->do_exit) { + uv_close(reinterpret_cast(&async_baton->async), CloseCallback); // necessary otherwise UV will block + + /* Emit end event */ + Local argv[1] = { + Nan::New("_end").ToLocalChecked(), // event name + }; + + Nan::MakeCallback(async_baton->reader->handle(), "emit", 1, argv); + } + if (reader->m_status_thread) { uv_mutex_unlock(&reader->m_mutex); } @@ -379,33 +384,32 @@ void CardReader::HandlerFunction(void* arg) { card_reader_state.szReader = reader->m_name.c_str(); card_reader_state.dwCurrentState = SCARD_STATE_UNAWARE; - bool keep_watching(result == SCARD_S_SUCCESS); - while (keep_watching) { + while (!reader->m_state) { result = SCardGetStatusChange(reader->m_status_card_context, INFINITE, &card_reader_state, 1); - keep_watching = (result == SCARD_S_SUCCESS) && (!reader->m_state); uv_mutex_lock(&reader->m_mutex); if (reader->m_state == 1) { + // Exit requested by user. Notify close method about SCardStatusChange was interrupted. uv_cond_signal(&reader->m_cond); - } - - if (!keep_watching) { + } else if (result != (LONG)SCARD_S_SUCCESS) { + // Exit this loop due to errors reader->m_state = 2; } - uv_mutex_unlock(&reader->m_mutex); - + async_baton->async_result->do_exit = (reader->m_state != 0); async_baton->async_result->result = result; async_baton->async_result->status = card_reader_state.dwEventState; memcpy(async_baton->async_result->atr, card_reader_state.rgbAtr, card_reader_state.cbAtr); async_baton->async_result->atrlen = card_reader_state.cbAtr; + + uv_mutex_unlock(&reader->m_mutex); + uv_async_send(&async_baton->async); card_reader_state.dwCurrentState = card_reader_state.dwEventState; } - async_baton->async_result->do_exit = true; - uv_async_send(&async_baton->async); + // Exit flag set in keepwatching and handled in following uv_async_send } void CardReader::DoConnect(uv_work_t* req) { diff --git a/src/pcsclite.cpp b/src/pcsclite.cpp index a53b850..bc4af83 100644 --- a/src/pcsclite.cpp +++ b/src/pcsclite.cpp @@ -124,12 +124,10 @@ void PCSCLite::HandleReaderStatusChange(uv_async_t *handle, int status) { AsyncBaton* async_baton = static_cast(handle->data); AsyncResult* ar = async_baton->async_result; - if (ar->do_exit) { - uv_close(reinterpret_cast(&async_baton->async), CloseCallback); // necessary otherwise UV will block - return; - } - - if ((ar->result == SCARD_S_SUCCESS) || (ar->result == (LONG)SCARD_E_NO_READERS_AVAILABLE)) { + if (async_baton->pcsclite->m_state == 1) { + // Swallow events : Listening thread was cancelled by user. + } else if ((ar->result == SCARD_S_SUCCESS) || + (ar->result == (LONG)SCARD_E_NO_READERS_AVAILABLE)) { const unsigned argc = 2; Local argv[argc] = { Nan::Undefined(), // argument @@ -145,6 +143,13 @@ void PCSCLite::HandleReaderStatusChange(uv_async_t *handle, int status) { Nan::Callback(Nan::New(async_baton->callback)).Call(argc, argv); } + // Do exit, after throwing last events + if (ar->do_exit) { + // necessary otherwise UV will block + uv_close(reinterpret_cast(&async_baton->async), CloseCallback); + return; + } + /* reset AsyncResult */ delete [] ar->readers_name; ar->readers_name = NULL; @@ -159,7 +164,7 @@ void PCSCLite::HandlerFunction(void* arg) { PCSCLite* pcsclite = async_baton->pcsclite; async_baton->async_result = new AsyncResult(); - while (!pcsclite->m_state && (result == SCARD_S_SUCCESS)) { + while (!pcsclite->m_state) { /* Get card readers */ result = pcsclite->get_card_readers(pcsclite, async_baton->async_result); if (result == (LONG)SCARD_E_NO_READERS_AVAILABLE) { @@ -180,6 +185,7 @@ void PCSCLite::HandlerFunction(void* arg) { INFINITE, &pcsclite->m_card_reader_state, 1); + uv_mutex_lock(&pcsclite->m_mutex); if (pcsclite->m_state) { uv_cond_signal(&pcsclite->m_cond); @@ -190,9 +196,12 @@ void PCSCLite::HandlerFunction(void* arg) { } uv_mutex_unlock(&pcsclite->m_mutex); - } else { + } else if (result == SCARD_S_SUCCESS) { /* If PnP is not supported, just wait for 1 second */ Sleep(1000); + } else { + /* Error on last card access and no PnP, stop monitoring */ + pcsclite->m_state = 2; } }