From 0c5e07e0e54dbc2b3015d2b29712b011582b7ae8 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 8 Aug 2014 16:30:12 +0200 Subject: [PATCH] src: migrate pthreads to uv_threads - So it can be compatible in every platform supported by libuv. - Use attached threads instead of detached. - Remove all CardReader 'status' listeners before emitting the 'end' event. --- lib/pcsclite.js | 6 +++- src/addon.cpp | 2 -- src/cardreader.cpp | 84 +++++++++++++++++++++++++++++----------------- src/cardreader.h | 9 ++--- src/pcsclite.cpp | 63 +++++++++++++++++++++++----------- src/pcsclite.h | 9 ++--- 6 files changed, 112 insertions(+), 61 deletions(-) diff --git a/lib/pcsclite.js b/lib/pcsclite.js index 32e54c0..2c73df8 100644 --- a/lib/pcsclite.js +++ b/lib/pcsclite.js @@ -59,6 +59,11 @@ module.exports = function() { r.state = state; }); + r.on('_end', function() { + r.removeAllListeners('status'); + r.emit('end'); + }); + p.emit('reader', r); }); }); @@ -102,7 +107,6 @@ CardReader.prototype.disconnect = function(disposition, cb) { }; CardReader.prototype.transmit = function(data, res_len, protocol, cb) { - if (!this.connected) { return cb(new Error("Card Reader not connected")); } diff --git a/src/addon.cpp b/src/addon.cpp index 06a4422..7addfa6 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -1,5 +1,3 @@ -#include - #include "pcsclite.h" #include "cardreader.h" diff --git a/src/cardreader.cpp b/src/cardreader.cpp index 9e58242..6661152 100644 --- a/src/cardreader.cpp +++ b/src/cardreader.cpp @@ -61,21 +61,22 @@ void CardReader::init(Handle target) { CardReader::CardReader(const std::string &reader_name): m_card_context(0), m_card_handle(0), - m_name(reader_name) { - pthread_mutex_init(&m_mutex, NULL); + m_name(reader_name), + m_state(0) { + assert(uv_mutex_init(&m_mutex) == 0); + assert(uv_cond_init(&m_cond) == 0); } CardReader::~CardReader() { + SCardCancel(m_card_context); + int ret = uv_thread_join(&m_status_thread); + assert(ret == 0); if (m_card_context) { SCardReleaseContext(m_card_context); } - if (m_status_card_context) { - SCardCancel(m_status_card_context); - } - - pthread_mutex_destroy(&m_mutex); + uv_mutex_destroy(&m_mutex); } NAN_METHOD(CardReader::New) { @@ -104,8 +105,8 @@ NAN_METHOD(CardReader::GetStatus) { async_baton->reader = obj; uv_async_init(uv_default_loop(), &async_baton->async, (uv_async_cb)HandleReaderStatusChange); - pthread_create(&obj->m_status_thread, NULL, HandlerFunction, async_baton); - pthread_detach(obj->m_status_thread); + int ret = uv_thread_create(&obj->m_status_thread, HandlerFunction, async_baton); + assert(ret == 0); NanReturnUndefined(); } @@ -298,10 +299,23 @@ NAN_METHOD(CardReader::Close) { NanScope(); + LONG result = SCARD_S_SUCCESS; CardReader* obj = ObjectWrap::Unwrap(args.This()); - LONG result = SCardCancel(obj->m_status_card_context); - obj->m_status_card_context = 0; + uv_mutex_lock(&obj->m_mutex); + if (obj->m_state == 0) { + obj->m_state = 1; + do { + result = SCardCancel(obj->m_status_card_context); + } while (uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000) != 0); + } + + uv_mutex_unlock(&obj->m_mutex); + uv_mutex_destroy(&obj->m_mutex); + uv_cond_destroy(&obj->m_cond); + + assert(uv_thread_join(&obj->m_status_thread) == 0); + obj->m_status_thread = 0; NanReturnValue(NanNew(result)); } @@ -318,7 +332,7 @@ void CardReader::HandleReaderStatusChange(uv_async_t *handle, int status) { /* Emit end event */ Handle argv[1] = { - NanNew("end"), // event name + NanNew("_end"), // event name }; NanMakeCallback(NanObjectWrapHandle(async_baton->reader), "emit", 1, argv); @@ -343,27 +357,39 @@ void CardReader::HandleReaderStatusChange(uv_async_t *handle, int status) { } } -void* CardReader::HandlerFunction(void* arg) { +void CardReader::HandlerFunction(void* arg) { AsyncBaton* async_baton = static_cast(arg); CardReader* reader = async_baton->reader; async_baton->async_result = new AsyncResult(); async_baton->async_result->do_exit = false; - /* Lock mutex */ - pthread_mutex_lock(&reader->m_mutex); LONG result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &reader->m_status_card_context); - /* Unlock the mutex */ - pthread_mutex_unlock(&reader->m_mutex); SCARD_READERSTATE card_reader_state = SCARD_READERSTATE(); card_reader_state.szReader = reader->m_name.c_str(); card_reader_state.dwCurrentState = SCARD_STATE_UNAWARE; - while(result == SCARD_S_SUCCESS && - !((card_reader_state.dwCurrentState & SCARD_STATE_UNKNOWN) || - (card_reader_state.dwCurrentState & SCARD_STATE_UNAVAILABLE))) { + bool keep_watching(result == SCARD_S_SUCCESS); + while (keep_watching) { + result = SCardGetStatusChange(reader->m_status_card_context, INFINITE, &card_reader_state, 1); + keep_watching = ((result == SCARD_S_SUCCESS) && + (!reader->m_state) && + (!((card_reader_state.dwCurrentState & SCARD_STATE_UNKNOWN) || + (card_reader_state.dwCurrentState & SCARD_STATE_UNAVAILABLE)))); + + uv_mutex_lock(&reader->m_mutex); + if (reader->m_state == 1) { + uv_cond_signal(&reader->m_cond); + } + + if (!keep_watching) { + reader->m_state = 2; + } + + uv_mutex_unlock(&reader->m_mutex); + 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); @@ -374,8 +400,6 @@ void* CardReader::HandlerFunction(void* arg) { async_baton->async_result->do_exit = true; uv_async_send(&async_baton->async); - - return NULL; } void CardReader::DoConnect(uv_work_t* req) { @@ -388,7 +412,7 @@ void CardReader::DoConnect(uv_work_t* req) { CardReader* obj = baton->reader; /* Lock mutex */ - pthread_mutex_lock(&obj->m_mutex); + uv_mutex_lock(&obj->m_mutex); /* Is context established */ if (!obj->m_card_context) { result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &obj->m_card_context); @@ -405,7 +429,7 @@ void CardReader::DoConnect(uv_work_t* req) { } /* Unlock the mutex */ - pthread_mutex_unlock(&obj->m_mutex); + uv_mutex_unlock(&obj->m_mutex); ConnectResult *cr = new ConnectResult(); cr->result = result; @@ -456,7 +480,7 @@ void CardReader::DoDisconnect(uv_work_t* req) { CardReader* obj = baton->reader; /* Lock mutex */ - pthread_mutex_lock(&obj->m_mutex); + uv_mutex_lock(&obj->m_mutex); /* Connect */ if (obj->m_card_handle) { result = SCardDisconnect(obj->m_card_handle, *disposition); @@ -466,7 +490,7 @@ void CardReader::DoDisconnect(uv_work_t* req) { } /* Unlock the mutex */ - pthread_mutex_unlock(&obj->m_mutex); + uv_mutex_unlock(&obj->m_mutex); baton->result = reinterpret_cast(new LONG(result)); } @@ -515,7 +539,7 @@ void CardReader::DoTransmit(uv_work_t* req) { LONG result = SCARD_E_INVALID_HANDLE; /* Lock mutex */ - pthread_mutex_lock(&obj->m_mutex); + uv_mutex_lock(&obj->m_mutex); /* Connected? */ if (obj->m_card_handle) { SCARD_IO_REQUEST send_pci = { ti->card_protocol, sizeof(SCARD_IO_REQUEST) }; @@ -524,7 +548,7 @@ void CardReader::DoTransmit(uv_work_t* req) { } /* Unlock the mutex */ - pthread_mutex_unlock(&obj->m_mutex); + uv_mutex_unlock(&obj->m_mutex); tr->result = result; @@ -575,7 +599,7 @@ void CardReader::DoControl(uv_work_t* req) { LONG result = SCARD_E_INVALID_HANDLE; /* Lock mutex */ - pthread_mutex_lock(&obj->m_mutex); + uv_mutex_lock(&obj->m_mutex); /* Connected? */ if (obj->m_card_handle) { result = SCardControl(obj->m_card_handle, @@ -588,7 +612,7 @@ void CardReader::DoControl(uv_work_t* req) { } /* Unlock the mutex */ - pthread_mutex_unlock(&obj->m_mutex); + uv_mutex_unlock(&obj->m_mutex); cr->result = result; diff --git a/src/cardreader.h b/src/cardreader.h index bfa0605..f643314 100644 --- a/src/cardreader.h +++ b/src/cardreader.h @@ -4,7 +4,6 @@ #include #include #include -#include #ifdef __APPLE__ #include #include @@ -100,7 +99,7 @@ class CardReader: public node::ObjectWrap { static NAN_METHOD(Close); static void HandleReaderStatusChange(uv_async_t *handle, int status); - static void* HandlerFunction(void* arg); + static void HandlerFunction(void* arg); static void DoConnect(uv_work_t* req); static void DoDisconnect(uv_work_t* req); static void DoTransmit(uv_work_t* req); @@ -120,8 +119,10 @@ class CardReader: public node::ObjectWrap { SCARDCONTEXT m_status_card_context; SCARDHANDLE m_card_handle; std::string m_name; - pthread_t m_status_thread; - pthread_mutex_t m_mutex; + uv_thread_t m_status_thread; + uv_mutex_t m_mutex; + uv_cond_t m_cond; + int m_state; }; #endif /* CARDREADER_H */ diff --git a/src/pcsclite.cpp b/src/pcsclite.cpp index 570a521..173fe38 100644 --- a/src/pcsclite.cpp +++ b/src/pcsclite.cpp @@ -24,9 +24,10 @@ void PCSCLite::init(Handle target) { PCSCLite::PCSCLite(): m_card_context(0), m_card_reader_state(), m_status_thread(0), - m_closing(false) { + m_state(0) { - pthread_mutex_init(&m_mutex, NULL); + assert(uv_mutex_init(&m_mutex) == 0); + assert(uv_cond_init(&m_cond) == 0); LONG result = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, @@ -51,13 +52,14 @@ PCSCLite::PCSCLite(): m_card_context(0), } PCSCLite::~PCSCLite() { - if (m_card_context) { - SCardReleaseContext(m_card_context); + + if (m_status_thread) { + int ret = uv_thread_join(&m_status_thread); + assert(ret == 0); } - pthread_mutex_destroy(&m_mutex); - if (m_status_thread) { - pthread_cancel(m_status_thread); + if (m_card_context) { + SCardReleaseContext(m_card_context); } } @@ -81,8 +83,8 @@ NAN_METHOD(PCSCLite::Start) { async_baton->pcsclite = obj; uv_async_init(uv_default_loop(), &async_baton->async, (uv_async_cb)HandleReaderStatusChange); - pthread_create(&obj->m_status_thread, NULL, HandlerFunction, async_baton); - pthread_detach(obj->m_status_thread); + int ret = uv_thread_create(&obj->m_status_thread, HandlerFunction, async_baton); + assert(ret == 0); NanReturnUndefined(); } @@ -95,11 +97,24 @@ NAN_METHOD(PCSCLite::Close) { LONG result = SCARD_S_SUCCESS; if (obj->m_pnp) { - result = SCardCancel(obj->m_card_context); + uv_mutex_lock(&obj->m_mutex); + if (obj->m_state == 0) { + obj->m_state = 1; + do { + result = SCardCancel(obj->m_card_context); + } while (uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000) != 0); + } + + uv_mutex_unlock(&obj->m_mutex); + uv_mutex_destroy(&obj->m_mutex); + uv_cond_destroy(&obj->m_cond); } else { - obj->m_closing = true; + obj->m_state = 1; } + assert(uv_thread_join(&obj->m_status_thread) == 0); + obj->m_status_thread = 0; + NanReturnValue(NanNew(result)); } @@ -108,7 +123,6 @@ void PCSCLite::HandleReaderStatusChange(uv_async_t *handle, int status) { NanScope(); AsyncBaton* async_baton = static_cast(handle->data); - PCSCLite* pcsclite = async_baton->pcsclite; AsyncResult* ar = async_baton->async_result; if (ar->do_exit) { @@ -137,19 +151,16 @@ void PCSCLite::HandleReaderStatusChange(uv_async_t *handle, int status) { ar->readers_name = NULL; ar->readers_name_length = 0; ar->result = SCARD_S_SUCCESS; - /* Unlock the mutex */ - pthread_mutex_unlock(&pcsclite->m_mutex); } -void* PCSCLite::HandlerFunction(void* arg) { +void PCSCLite::HandlerFunction(void* arg) { LONG result = SCARD_S_SUCCESS; AsyncBaton* async_baton = static_cast(arg); PCSCLite* pcsclite = async_baton->pcsclite; async_baton->async_result = new AsyncResult(); - while (!pcsclite->m_closing && (result == SCARD_S_SUCCESS)) { - /* Lock mutex. It'll be unlocked after the callback has been sent */ - pthread_mutex_lock(&pcsclite->m_mutex); + + while (!pcsclite->m_state && (result == SCARD_S_SUCCESS)) { /* Get card readers */ result = pcsclite->get_card_readers(pcsclite, async_baton->async_result); if (result == SCARD_E_NO_READERS_AVAILABLE) { @@ -160,12 +171,26 @@ void* PCSCLite::HandlerFunction(void* arg) { async_baton->async_result->result = result; /* Notify the nodejs thread */ uv_async_send(&async_baton->async); + if (pcsclite->m_pnp) { + /* Set current status */ + pcsclite->m_card_reader_state.dwCurrentState = + pcsclite->m_card_reader_state.dwEventState; /* Start checking for status change */ result = SCardGetStatusChange(pcsclite->m_card_context, INFINITE, &pcsclite->m_card_reader_state, 1); + uv_mutex_lock(&pcsclite->m_mutex); + if (pcsclite->m_state) { + uv_cond_signal(&pcsclite->m_cond); + } + + if (result != SCARD_S_SUCCESS) { + pcsclite->m_state = 2; + } + + uv_mutex_unlock(&pcsclite->m_mutex); } else { /* If PnP is not supported, just wait for 1 second */ sleep(1); @@ -174,8 +199,6 @@ void* PCSCLite::HandlerFunction(void* arg) { async_baton->async_result->do_exit = true; uv_async_send(&async_baton->async); - - return NULL; } void PCSCLite::CloseCallback(uv_handle_t *handle) { diff --git a/src/pcsclite.h b/src/pcsclite.h index 7651ac6..267d423 100644 --- a/src/pcsclite.h +++ b/src/pcsclite.h @@ -41,7 +41,7 @@ class PCSCLite: public node::ObjectWrap { static NAN_METHOD(Close); static void HandleReaderStatusChange(uv_async_t *handle, int status); - static void* HandlerFunction(void* arg); + static void HandlerFunction(void* arg); static void CloseCallback(uv_handle_t *handle); LONG get_card_readers(PCSCLite* pcsclite, AsyncResult* async_result); @@ -50,10 +50,11 @@ class PCSCLite: public node::ObjectWrap { SCARDCONTEXT m_card_context; SCARD_READERSTATE m_card_reader_state; - pthread_t m_status_thread; - pthread_mutex_t m_mutex; + uv_thread_t m_status_thread; + uv_mutex_t m_mutex; + uv_cond_t m_cond; bool m_pnp; - bool m_closing; + int m_state; }; #endif /* PCSCLITE_H */