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() {
SCardCancel(m_card_context);
int ret = uv_thread_join(&m_status_thread);
assert(ret == 0);
if (m_status_thread) {
SCardCancel(m_card_context);
assert(uv_thread_join(&m_status_thread) == 0);
}
if (m_card_context) {
SCardReleaseContext(m_card_context);
}
uv_cond_destroy(&m_cond);
uv_mutex_destroy(&m_mutex);
}
@@ -302,21 +304,23 @@ NAN_METHOD(CardReader::Close) {
LONG result = SCARD_S_SUCCESS;
CardReader* obj = Nan::ObjectWrap::Unwrap<CardReader>(info.This());
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);
if (obj->m_status_thread) {
uv_mutex_lock(&obj->m_mutex);
if (obj->m_state == 0) {
int ret;
int times = 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));
}

View File

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