Possible deadlock in DispatchWorker
EvenAR opened this issue · comments
The DispatchWorker, which is a subclass of Nan::AsyncWorker (runs on a separate thread), some times stops receiving data. Not very often - it happens like 1 out of 50 times after I start example.js
The DispatchWorker
has an infinite loop where it reads data from the active connection (if any) and notifies the main thread once it receieves something interesting (data or an NT_ERROR
). The main thread is notified using uv_async_send
(libuv), which later at some time wakes up the messageReceiver
which extracts the data received from SimConnect. A SimConnect dispatch contains pointers and data which only lives until the next dispatch is loaded. Therefore, after DispatcWorker
has notified the main thread, it must wait for the main thread to signal that it has finished reading the data before it proceeds with receiving dispatces.
It looks like the while(true)
-loop stops running, as VS no longer stops if I set a breakpoint in the loop.
I'm not too experienced with multithreading, so if anyone have an idea of what is wrong, I'll be very thankful! I suspect there is a deadlock which is caused by uv_cond_signal(&cv)
not being called. Some possible reasons I can think of:
- Something wrong is going on in the extraction of the dispatch data (
messageReceiver
). The strange thing is, there are no errors or exceptions that I can see. I am running the debug-version of Node.JS through Visual Studio. - The mutex and condition variable is used incorrectly.
- The V8 SDK is used incorrectly, which causes a break before
uv_cond_signal(&cv)
is called. Still, I have no indication from Visual Studio about any errors.
I have pasted a short version of the code below. Full code here
class DispatchWorker : public Nan::AsyncWorker {
public:
DispatchWorker(Nan::Callback *callback) : AsyncWorker(callback) {
}
~DispatchWorker() {}
void Execute() {
uv_async_init(loop, &async, messageReceiver); // Must be called from worker thread
while (true) {
if (ghSimConnect) {
SIMCONNECT_RECV* pData;
DWORD cbData;
HRESULT hr = SimConnect_GetNextDispatch(ghSimConnect, &pData, &cbData);
if (SUCCEEDED(hr))
{
CallbackData data;
data.pData = pData;
data.cbData = cbData;
data.ntstatus = STATUS_SUCCESS;
async.data = &data;
uv_mutex_lock(&mutex);
uv_async_send(&async);
// Wait for main thread to process the dispatch
uv_cond_wait(&cv, &mutex);
}
else if (NT_ERROR(hr)) {
CallbackData data;
data.ntstatus = (NTSTATUS)hr;
async.data = &data;
uv_mutex_lock(&mutex);
uv_async_send(&async);
// Wait for main thread to process the dispatch
uv_cond_wait(&cv, &mutex);
}
}
else {
Sleep(10);
}
}
}
};
Runs on main thread (some time) after uv_async_send() is called
void messageReceiver(uv_async_t* handle) {
Nan::HandleScope scope;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
CallbackData* data = (CallbackData*)handle->data;
// ..... extract data ....
// The dispatch-worker can now continue
uv_mutex_unlock(&mutex);
uv_cond_signal(&cv);
}
Ok, so using a semaphore instead now (7961518) and I have not been able to trigger the issue yet (🤞). I will wait a few days before I close this issue.