diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index 3baddb8..ea9b3f4 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -1595,13 +1595,14 @@ duk_ret_t ILibDuktape_MeshAgent_eval(duk_context *ctx) } duk_context* ScriptEngine_Stop(MeshAgentHostContainer *agent, char *contextGUID); +int dumpcount = 0; void ILibDuktape_MeshAgent_dumpCoreModuleEx(void *chain, void *user) { MeshAgentHostContainer* agentHost = (MeshAgentHostContainer*)user; char *CoreModule; ScriptEngine_Stop((MeshAgentHostContainer*)user, MeshAgent_JavaCore_ContextGuid); - printf("CoreModule was manually dumped, restarting!\n"); + printf("CoreModule was manually dumped %d times, restarting!\n", ++dumpcount); int CoreModuleLen = ILibSimpleDataStore_Get(agentHost->masterDb, "CoreModule", NULL, 0); if (CoreModuleLen > 0) diff --git a/microscript/ILibDuktape_ChildProcess.c b/microscript/ILibDuktape_ChildProcess.c index af96035..6dfbebf 100644 --- a/microscript/ILibDuktape_ChildProcess.c +++ b/microscript/ILibDuktape_ChildProcess.c @@ -94,12 +94,34 @@ void ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler(ILibDuktape_WritableSt ILibProcessPipe_Process_CloseStdIn(p->childProcess); } } +void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user); +void ILibDuktape_ChildProcess_SubProcess_ExitHandler_sink1(void *chain, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + if (!ILibMemory_CanaryOK(p)) { return; } + ILibDuktape_ChildProcess_SubProcess_ExitHandler(NULL, p->exitCode, p); +} void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user) { ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; if (!ILibMemory_CanaryOK(p)) { return; } +#ifdef WIN32 + if (duk_ctx_context_data(p->ctx)->apc_flags == 0) + { + // This method was called with an APC, but this thread was running an unknown alertable method when it was interrupted + // So we must unwind the stack, and use a non-apc method to re-dispatch to this thread, becuase we can't risk + // calling a winsock method, in case this thread was inside winsock when it was interrupted, because otherwise, it + // will corrupt memory, resulting in a possible crash. + // + // We had to do the APC first, becuase otherwise child_process.waitExit() will not work, becuase that method is blocking + // the event loop thread with an alertable wait object, so APC is the only way to propagate this event + p->exitCode = exitCode; + Duktape_RunOnEventLoop(p->chain, duk_ctx_nonce(p->ctx), p->ctx, ILibDuktape_ChildProcess_SubProcess_ExitHandler_sink1, NULL, p); + } +#endif + p->exitCode = exitCode; p->childProcess = NULL; duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] @@ -181,8 +203,13 @@ duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx) duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess] #ifdef WIN32 + duk_thread_state ts; + duk_suspend(ctx, &ts); + duk_ctx_context_data(ctx)->apc_flags = 1; while ((result=WaitForSingleObjectEx(eptr, duk_is_number(ctx, 0) ? duk_require_int(ctx, 0) : INFINITE, TRUE)) != WAIT_OBJECT_0 && result != WAIT_TIMEOUT); + duk_ctx_context_data(ctx)->apc_flags = 0; CloseHandle(eptr); + duk_resume(ctx, &ts); if (result == WAIT_TIMEOUT) { return(ILibDuktape_Error(ctx, "timeout")); } #else void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager) }; diff --git a/microscript/ILibDuktape_Helpers.h b/microscript/ILibDuktape_Helpers.h index 8adf105..84c87ea 100644 --- a/microscript/ILibDuktape_Helpers.h +++ b/microscript/ILibDuktape_Helpers.h @@ -50,6 +50,9 @@ typedef struct ILibDuktape_ContextData { uintptr_t nonce; uint32_t flags; +#ifdef WIN32 + uint32_t apc_flags; +#endif void *chain; void *user; }ILibDuktape_ContextData; diff --git a/microscript/ILibDuktape_Polyfills.c b/microscript/ILibDuktape_Polyfills.c index ef5b177..0b45bad 100644 --- a/microscript/ILibDuktape_Polyfills.c +++ b/microscript/ILibDuktape_Polyfills.c @@ -1645,7 +1645,7 @@ void ILibDuktape_Stream_Init(duk_context *ctx, void *chain) } void ILibDuktape_Polyfills_debugGC2(duk_context *ctx, void ** args, int argsLen) { - if (duk_ctx_is_alive((duk_context*)args[1]) && duk_ctx_is_valid((uintptr_t)args[2], ctx)) + if (duk_ctx_is_alive((duk_context*)args[1]) && duk_ctx_is_valid((uintptr_t)args[2], ctx) && duk_ctx_shutting_down(ctx)==0) { if (g_displayFinalizerMessages) { printf("=> GC();\n"); } duk_gc(ctx, 0); diff --git a/microscript/ILibDuktape_ReadableStream.c b/microscript/ILibDuktape_ReadableStream.c index 95ac7e7..bc178c5 100644 --- a/microscript/ILibDuktape_ReadableStream.c +++ b/microscript/ILibDuktape_ReadableStream.c @@ -279,9 +279,9 @@ void __stdcall ILibDuktape_readableStream_WriteData_OnData_ChainThread_APC(ULONG ILibDuktape_readableStream_bufferedData *data = (ILibDuktape_readableStream_bufferedData*)obj; void *chain = ((void**)ILibMemory_GetExtraMemory((void*)obj, sizeof(ILibDuktape_readableStream_bufferedData) + data->bufferLen))[0]; - if (ILibChain_SelectInterrupted(chain) != 0) + if (duk_ctx_context_data(data->ctx)->apc_flags == 0) { - // This APC interrupted a winsock (select) call, so we must unroll the callstack to continue, + // This APC interrupted an unknown alertable method, so we must unroll the callstack to continue, // because winsock is not re-entrant, so we cannot risk making another winsock call directly. // Duktape_RunOnEventLoop(chain, duk_ctx_nonce(data->ctx), data->ctx, ILibDuktape_readableStream_WriteData_OnData_ChainThread, NULL, (void*)obj);