From 3efdc2747880265dd32181e0dbaefc828db6f193 Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Tue, 23 Jul 2019 16:16:53 -0700 Subject: [PATCH] 1. Updated so that APCs are used for thread dispatching for Read/Exit on Windows 2. Updated to add support for child_process.waitExit() on Windows. --- microscript/ILibDuktape_ChildProcess.c | 28 +++++++++++++++++++----- microscript/ILibDuktape_ReadableStream.c | 20 +++++++++++++++++ microstack/ILibProcessPipe.c | 12 +++++++++- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/microscript/ILibDuktape_ChildProcess.c b/microscript/ILibDuktape_ChildProcess.c index 4ce6686..dbad6b9 100644 --- a/microscript/ILibDuktape_ChildProcess.c +++ b/microscript/ILibDuktape_ChildProcess.c @@ -99,10 +99,19 @@ void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sen p->childProcess = NULL; duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] + +#ifdef WIN32 + HANDLE exitptr = (HANDLE)Duktape_GetPointerProperty(p->ctx, -1, "\xFF_WaitExit"); + if (exitptr != NULL) + { + SetEvent(exitptr); + } +#else if (Duktape_GetIntPropertyValue(p->ctx, -1, "\xFF_WaitExit", 0) != 0) { ILibChain_EndContinue(Duktape_GetChain(p->ctx)); } +#endif duk_get_prop_string(p->ctx, -1, "emit"); // [childProcess][emit] duk_swap_top(p->ctx, -2); // [emit][this] duk_push_string(p->ctx, "exit"); // [emit][this][exit] @@ -153,16 +162,26 @@ duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx) } duk_push_this(ctx); // [spawnedProcess] - duk_push_int(ctx, 1); // [spawnedProcess][flag] - duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess] - if (!ILibChain_IsLinkAlive(Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager))) { return(ILibDuktape_Error(ctx, "Cannot waitExit() because JS Engine is exiting")); } +#ifdef WIN32 + HANDLE eptr = CreateEventA(NULL, TRUE, FALSE, NULL); + duk_push_pointer(ctx, (void*)eptr); +#else + duk_push_int(ctx, 1); // [spawnedProcess][flag] +#endif + duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess] + +#ifdef WIN32 + while (WaitForSingleObjectEx(eptr, INFINITE, TRUE) != WAIT_OBJECT_0); + CloseHandle(eptr); +#else void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager) }; ILibChain_Continue(chain, (ILibChain_Link**)mods, 2, -1); +#endif return(0); } @@ -195,10 +214,7 @@ ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUS ILibDuktape_EventEmitter_CreateEventEx(emitter, "error"); ILibDuktape_EventEmitter_PrependOnce(ctx, -1, "~", ILibDuktape_ChildProcess_SpawnedProcess_Finalizer); ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ChildProcess_Kill, 0); - -#ifndef WIN32 ILibDuktape_CreateInstanceMethod(ctx, "waitExit", ILibDuktape_ChildProcess_waitExit, 0); -#endif if (ILibProcessPipe_Process_IsDetached(mProcess) == 0) { diff --git a/microscript/ILibDuktape_ReadableStream.c b/microscript/ILibDuktape_ReadableStream.c index feccf12..b96e69f 100644 --- a/microscript/ILibDuktape_ReadableStream.c +++ b/microscript/ILibDuktape_ReadableStream.c @@ -271,6 +271,14 @@ void ILibDuktape_readableStream_WriteDataEx_Chain(void *chain, void *user) } free(data); } +#ifdef WIN32 +void __stdcall ILibDuktape_readableStream_WriteData_OnData_ChainThread_APC(ULONG_PTR obj) +{ + ILibDuktape_readableStream_bufferedData *data = (ILibDuktape_readableStream_bufferedData*)obj; + void *chain = ((void**)ILibMemory_GetExtraMemory((void*)obj, sizeof(ILibDuktape_readableStream_bufferedData) + data->bufferLen))[0]; + ILibDuktape_readableStream_WriteData_OnData_ChainThread(chain, (void*)obj); +} +#endif int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, int streamReserved, char* buffer, int bufferLen) { @@ -399,13 +407,25 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i else { // Need to PAUSE, and context switch to Chain Thread, so we can dispatch into JavaScript +#ifdef WIN32 + ILibDuktape_readableStream_bufferedData *tmp = (ILibDuktape_readableStream_bufferedData*)ILibMemory_Allocate(sizeof(ILibDuktape_readableStream_bufferedData) + bufferLen, sizeof(void*), NULL, NULL); +#else ILibDuktape_readableStream_bufferedData *tmp = (ILibDuktape_readableStream_bufferedData*)ILibMemory_Allocate(sizeof(ILibDuktape_readableStream_bufferedData) + bufferLen, 0, NULL, NULL); +#endif tmp->bufferLen = bufferLen; tmp->Reserved = streamReserved; tmp->Next = (ILibDuktape_readableStream_bufferedData*)stream; memcpy_s(tmp->buffer, bufferLen, buffer, bufferLen); needPause = 1; +#ifdef WIN32 + // We are going to PAUSE first, do the APC, then exit, to prevent a race condition. We don't want to PAUSE after the APC completes. + if (stream->paused == 0 && stream->PauseHandler != NULL) { stream->paused = 1; stream->PauseHandler(stream, stream->user); } + ((void**)ILibMemory_GetExtraMemory(tmp, sizeof(ILibDuktape_readableStream_bufferedData) + bufferLen))[0] = stream->chain; + QueueUserAPC((PAPCFUNC)ILibDuktape_readableStream_WriteData_OnData_ChainThread_APC, ILibChain_GetMicrostackThreadHandle(stream->chain), (ULONG_PTR)tmp); + return(stream->paused); +#else ILibChain_RunOnMicrostackThread(stream->chain, ILibDuktape_readableStream_WriteData_OnData_ChainThread, tmp); +#endif } } else if (stream->PauseHandler != NULL && ILibDuktape_EventEmitter_HasListeners(stream->emitter, "end") == 0) diff --git a/microstack/ILibProcessPipe.c b/microstack/ILibProcessPipe.c index 4df6a3c..59305f4 100644 --- a/microstack/ILibProcessPipe.c +++ b/microstack/ILibProcessPipe.c @@ -1551,6 +1551,12 @@ void ILibProcessPipe_Process_OnExit_ChainSink(void *chain, void *user) // We can't destroy this now, because we're on the MicrostackThread. We must destroy this on the WindowsRunLoop Thread. QueueUserAPC((PAPCFUNC)ILibProcessPipe_Process_OnExit_ChainSink_DestroySink, j->parent->workerThread, (ULONG_PTR)j); } +#ifdef WIN32 +void __stdcall ILibProcessPipe_Process_OnExit_ChainSink_APC(ULONG_PTR obj) +{ + ILibProcessPipe_Process_OnExit_ChainSink(NULL, (void*)obj); +} +#endif BOOL ILibProcessPipe_Process_OnExit(HANDLE event, ILibWaitHandle_ErrorStatus errors, void* user) { ILibProcessPipe_Process_Object* j = (ILibProcessPipe_Process_Object*)user; @@ -1566,8 +1572,12 @@ BOOL ILibProcessPipe_Process_OnExit(HANDLE event, ILibWaitHandle_ErrorStatus err { if (j->exitHandler != NULL) { - // Everyone's lifes is made easier, by context switching to chain thread before making this call + // Everyone's lives will be made easier, by context switching to chain thread before making this call +#ifdef WIN32 + QueueUserAPC((PAPCFUNC)ILibProcessPipe_Process_OnExit_ChainSink_APC, ILibChain_GetMicrostackThreadHandle(j->parent->ChainLink.ParentChain), (ULONG_PTR)user); +#else ILibChain_RunOnMicrostackThread(j->parent->ChainLink.ParentChain, ILibProcessPipe_Process_OnExit_ChainSink, user); +#endif } else {