src: multiple thread synchronization improvements

- Allow up to 4 the number of times SCardCancel is called before waiting for
  the status `thread` to finish.
- Destroy the mutexes and conds only in the destructors.
- Check that the thread handles are still valid before calling join on them.
This commit is contained in:
Santiago Gimeno
2015-12-22 14:56:03 +01:00
parent 06d31638e2
commit 0bcf3d8436
2 changed files with 42 additions and 30 deletions

View File

@@ -68,14 +68,16 @@ CardReader::CardReader(const std::string &reader_name): m_card_context(0),
} }
CardReader::~CardReader() { CardReader::~CardReader() {
SCardCancel(m_card_context); if (m_status_thread) {
int ret = uv_thread_join(&m_status_thread); SCardCancel(m_card_context);
assert(ret == 0); assert(uv_thread_join(&m_status_thread) == 0);
}
if (m_card_context) { if (m_card_context) {
SCardReleaseContext(m_card_context); SCardReleaseContext(m_card_context);
} }
uv_cond_destroy(&m_cond);
uv_mutex_destroy(&m_mutex); uv_mutex_destroy(&m_mutex);
} }
@@ -302,21 +304,23 @@ NAN_METHOD(CardReader::Close) {
LONG result = SCARD_S_SUCCESS; LONG result = SCARD_S_SUCCESS;
CardReader* obj = Nan::ObjectWrap::Unwrap<CardReader>(info.This()); CardReader* obj = Nan::ObjectWrap::Unwrap<CardReader>(info.This());
uv_mutex_lock(&obj->m_mutex); if (obj->m_status_thread) {
if (obj->m_state == 0) { uv_mutex_lock(&obj->m_mutex);
obj->m_state = 1; if (obj->m_state == 0) {
do { int ret;
result = SCardCancel(obj->m_status_card_context); int times = 0;
} while (uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000) != 0); obj->m_state = 1;
do {
result = SCardCancel(obj->m_status_card_context);
ret = uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000);
} while ((ret != 0) && (++ times < 5));
}
assert(uv_thread_join(&obj->m_status_thread) == 0);
obj->m_status_thread = 0;
uv_mutex_unlock(&obj->m_mutex);
} }
assert(uv_thread_join(&obj->m_status_thread) == 0);
obj->m_status_thread = 0;
uv_mutex_unlock(&obj->m_mutex);
uv_mutex_destroy(&obj->m_mutex);
uv_cond_destroy(&obj->m_cond);
info.GetReturnValue().Set(Nan::New<Number>(result)); info.GetReturnValue().Set(Nan::New<Number>(result));
} }

View File

@@ -53,13 +53,16 @@ PCSCLite::PCSCLite(): m_card_context(0),
PCSCLite::~PCSCLite() { PCSCLite::~PCSCLite() {
if (m_status_thread) { if (m_status_thread) {
int ret = uv_thread_join(&m_status_thread); SCardCancel(m_card_context);
assert(ret == 0); assert(uv_thread_join(&m_status_thread) == 0);
} }
if (m_card_context) { if (m_card_context) {
SCardReleaseContext(m_card_context); SCardReleaseContext(m_card_context);
} }
uv_cond_destroy(&m_cond);
uv_mutex_destroy(&m_mutex);
} }
NAN_METHOD(PCSCLite::New) { NAN_METHOD(PCSCLite::New) {
@@ -96,23 +99,28 @@ NAN_METHOD(PCSCLite::Close) {
LONG result = SCARD_S_SUCCESS; LONG result = SCARD_S_SUCCESS;
if (obj->m_pnp) { if (obj->m_pnp) {
uv_mutex_lock(&obj->m_mutex); if (obj->m_status_thread) {
if (obj->m_state == 0) { uv_mutex_lock(&obj->m_mutex);
obj->m_state = 1; if (obj->m_state == 0) {
do { int ret;
result = SCardCancel(obj->m_card_context); int times = 0;
} while (uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000) != 0); obj->m_state = 1;
} do {
result = SCardCancel(obj->m_card_context);
ret = uv_cond_timedwait(&obj->m_cond, &obj->m_mutex, 10000000);
} while ((ret != 0) && (++ times < 5));
}
uv_mutex_unlock(&obj->m_mutex); uv_mutex_unlock(&obj->m_mutex);
uv_mutex_destroy(&obj->m_mutex); }
uv_cond_destroy(&obj->m_cond);
} else { } else {
obj->m_state = 1; obj->m_state = 1;
} }
assert(uv_thread_join(&obj->m_status_thread) == 0); if (obj->m_status_thread) {
obj->m_status_thread = 0; assert(uv_thread_join(&obj->m_status_thread) == 0);
obj->m_status_thread = 0;
}
info.GetReturnValue().Set(Nan::New<Number>(result)); info.GetReturnValue().Set(Nan::New<Number>(result));
} }