diff --git a/microscript/ILibDuktape_ChildProcess.c b/microscript/ILibDuktape_ChildProcess.c index 5c0f5cc..0831049 100644 --- a/microscript/ILibDuktape_ChildProcess.c +++ b/microscript/ILibDuktape_ChildProcess.c @@ -24,6 +24,7 @@ limitations under the License. #include "ILibDuktape_ReadableStream.h" #include "ILibDuktape_WritableStream.h" #include "ILibDuktape_EventEmitter.h" +#include "ILibDuktape_ScriptContainer.h" #define ILibDuktape_ChildProcess_Process "\xFF_ChildProcess_Process" #define ILibDuktape_ChildProcess_MemBuf "\xFF_ChildProcess_MemBuf" @@ -112,8 +113,17 @@ void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sen p->exitCode = exitCode; p->childProcess = NULL; - duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] - + duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] + +#ifdef _POSIX + if (duk_has_prop_string(p->ctx, -1, "_sigsink")) + { + ILibDuktape_EventEmitter_SetupRemoveListener(p->ctx, ILibDuktape_GetProcessObject(p->ctx), "SIGCHLD"); //......][remove][process][SIGCHLD] + duk_get_prop_string(p->ctx, -4, "_sigsink"); // [childProcess][remove][process][SIGCHLD][func] + duk_pcall_method(p->ctx, 2); duk_pop(p->ctx); // [childProcess] + } +#endif + if (Duktape_GetIntPropertyValue(p->ctx, -1, "\xFF_WaitExit", 0) != 0) { ILibChain_EndContinue(Duktape_GetChain(p->ctx)); @@ -153,11 +163,9 @@ void ILibDuktape_ChildProcess_SubProcess_SendOK(ILibProcessPipe_Process sender, duk_ret_t ILibDuktape_ChildProcess_Kill(duk_context *ctx) { duk_push_this(ctx); - duk_get_prop_string(ctx, -1, ILibDuktape_ChildProcess_MemBuf); - ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBuffer(ctx, -1, NULL); - - ILibProcessPipe_Process_SoftKill(p->childProcess); + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_ChildProcess_MemBuf); + if (p != NULL) { ILibProcessPipe_Process_SoftKill(p->childProcess); } return(0); } duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx) @@ -180,14 +188,14 @@ duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx) duk_push_int(ctx, 1); // [spawnedProcess][flag] duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess] - void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager) }; + void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager), ILibDuktape_Process_GetSignalListener(ctx) }; #ifdef WIN32 HANDLE handles[] = { NULL, NULL, NULL, NULL, NULL }; ILibProcessPipe_Process p = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Process); ILibProcessPipe_Process_GetWaitHandles(p, &(handles[0]), &(handles[1]), &(handles[2]), &(handles[3])); ILibChain_Continue(chain, (ILibChain_Link**)mods, 2, timeout, (HANDLE**)handles); #else - ILibChain_Continue(chain, (ILibChain_Link**)mods, 2, timeout); + ILibChain_Continue(chain, (ILibChain_Link**)mods, 3, timeout); #endif return(0); @@ -226,19 +234,61 @@ duk_ret_t ILibDuktape_SpawnedProcess_descriptorSetter(duk_context *ctx) { duk_push_this(ctx); ILibDuktape_ChildProcess_SubProcess *retVal = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_ChildProcess_MemBuf); - duk_push_string(ctx, ILibProcessPipe_Process_GetMetadata(retVal->childProcess)); // [string] - duk_get_prop_string(ctx, -1, "split"); // [string][split] - duk_swap_top(ctx, -2); // [split][this] - duk_push_string(ctx, " [EXIT]"); // [split][this][delim] - duk_call_method(ctx, 1); // [array] - duk_get_prop_string(ctx, -1, "shift"); // [array][shift] - duk_swap_top(ctx, -2); // [shift][this] - duk_call_method(ctx, 0); // [string] - duk_push_sprintf(ctx, "%s, %s", duk_get_string(ctx, -1), duk_require_string(ctx, 0)); // [string][newVal] + if (retVal != NULL) + { + duk_push_string(ctx, ILibProcessPipe_Process_GetMetadata(retVal->childProcess)); // [string] + duk_get_prop_string(ctx, -1, "split"); // [string][split] + duk_swap_top(ctx, -2); // [split][this] + duk_push_string(ctx, " [EXIT]"); // [split][this][delim] + duk_call_method(ctx, 1); // [array] + duk_get_prop_string(ctx, -1, "shift"); // [array][shift] + duk_swap_top(ctx, -2); // [shift][this] + duk_call_method(ctx, 0); // [string] + duk_push_sprintf(ctx, "%s, %s", duk_get_string(ctx, -1), duk_require_string(ctx, 0)); // [string][newVal] - ILibProcessPipe_Process_ResetMetadata(retVal->childProcess, (char*)duk_get_string(ctx, -1)); + ILibProcessPipe_Process_ResetMetadata(retVal->childProcess, (char*)duk_get_string(ctx, -1)); + } return(0); } + +#ifdef _POSIX +extern void ILibProcessPipe_Process_Destroy(void *p); +duk_ret_t ILibDuktape_SpawnedProcess_SIGCHLD_sink(duk_context *ctx) +{ + int statusCode = duk_require_int(ctx, 1); + int pid = duk_require_int(ctx, 2); + duk_push_current_function(ctx); // [func] + duk_get_prop_string(ctx, -1, "_child"); // [func][child] + void *child = duk_get_heapptr(ctx, -1); + + if (Duktape_GetIntPropertyValue(ctx, -1, "pid", -1) == pid) + { + // This SIGCHLD is for us. Let's unhook from SIGCHLD + ILibDuktape_EventEmitter_SetupRemoveListener(ctx, duk_get_heapptr(ctx, -1), "SIGCHLD"); // [remove][this][SIGCHLD] + duk_push_current_function(ctx); // [remove][this][SIGCHLD][func] + duk_pcall_method(ctx, 2); + + // If we got this far, this means the process died without breaking the pipes. + // This will happen if the process was spawned as detached, otherwise this is + // pretty rare, but can happen if you spawn a login shell, then sudo su, then kill the parent. + ILibDuktape_EventEmitter_SetupEmit(ctx, child, "exit"); // [child][emit][this][exit] + duk_push_int(ctx, statusCode); // [child][emit][this][exit][code] + duk_push_null(ctx); // [child][emit][this][exit][code][null] + duk_call_method(ctx, 3); duk_pop(ctx); // ... + + duk_push_heapptr(ctx, child); // [child] + void *mProcess = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Process); + if (mProcess != NULL) + { + duk_del_prop_string(ctx, -1, ILibDuktape_ChildProcess_Process); + duk_del_prop_string(ctx, -1, ILibDuktape_ChildProcess_MemBuf); + ILibProcessPipe_Process_Destroy(mProcess); + } + } + + return(0); +} +#endif ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUSH(duk_context *ctx, ILibProcessPipe_Process mProcess, void *callback) { duk_push_object(ctx); // [ChildProcess] @@ -309,6 +359,16 @@ ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUS if (callback != NULL) { ILibDuktape_EventEmitter_AddOnce(emitter, "exit", callback); } } +#ifdef _POSIX + ILibDuktape_EventEmitter_SetupOn(ctx, ILibDuktape_GetProcessObject(ctx), "SIGCHLD"); // [child][on][process][SIGCHLD] + duk_push_c_function(ctx, ILibDuktape_SpawnedProcess_SIGCHLD_sink, DUK_VARARGS); // [child][on][process][SIGCHLD][func] + duk_dup(ctx, -5); // [child][on][process][SIGCHLD][func][child] + duk_put_prop_string(ctx, -2, "_child"); // [child][on][process][SIGCHLD][func] + duk_dup(ctx, -1); // [child][on][process][SIGCHLD][func][func] + duk_put_prop_string(ctx, -6, "_sigsink"); // [child][on][process][SIGCHLD][func] + duk_pcall_method(ctx, 2); duk_pop(ctx); // [child] +#endif + ILibDuktape_CreateEventWithSetterEx(ctx, "descriptorMetadata", ILibDuktape_SpawnedProcess_descriptorSetter); return(retVal); } diff --git a/microscript/ILibDuktape_EventEmitter.h b/microscript/ILibDuktape_EventEmitter.h index d040788..0971d25 100644 --- a/microscript/ILibDuktape_EventEmitter.h +++ b/microscript/ILibDuktape_EventEmitter.h @@ -62,6 +62,7 @@ int ILibDuktape_EventEmitter_HasListeners2(ILibDuktape_EventEmitter *emitter, ch #define ILibDuktape_EventEmitter_SetupEmit(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "emit");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName) #define ILibDuktape_EventEmitter_SetupOn(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "on");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName) #define ILibDuktape_EventEmitter_SetupPrependOnce(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "prependOnceListener");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName) +#define ILibDuktape_EventEmitter_SetupRemoveListener(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "removeListener");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName) #define ILibDuktape_EventEmitter_GetEmitReturn(ctx, heapptr, eventName) duk_push_heapptr((ctx), heapptr);duk_get_prop_string((ctx), -1, "emit_returnValue");duk_swap_top((ctx), -2);duk_push_string((ctx), eventName);if(duk_pcall_method(ctx, 1)!=0){duk_push_null(ctx);} int ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler diff --git a/microscript/ILibDuktape_ScriptContainer.c b/microscript/ILibDuktape_ScriptContainer.c index d1d18df..171c56d 100644 --- a/microscript/ILibDuktape_ScriptContainer.c +++ b/microscript/ILibDuktape_ScriptContainer.c @@ -136,6 +136,41 @@ char exeJavaScriptGuid[] = "B996015880544A19B7F7E9BE44914C18"; }; #endif + char *SIGTABLE[] = + { + "INVALID" , + "SIGHUP" , + "SIGINT" , + "SIGQUIT" , + "SIGILL" , + "SIGTRAP" , + "SIGIOT" , + "SIGBUS" , + "SIGFPE" , + "SIGKILL" , + "SIGUSR1" , + "SIGSEGV" , + "SIGUSR2" , + "SIGPIPE" , + "SIGALRM" , + "SIGTERM" , + "SIGSTKFLT" , + "SIGCHLD" , + "SIGCONTv" , + "SIGSTOP" , + "SIGTSTP" , + "SIGTTIN" , + "SIGTTOU" , + "SIGURG" , + "SIGXCPU" , + "SIGXFSZ" , + "SIGVTALRM" , + "SIGPROF" , + "SIGWINCH" , + "SIGIO" , + "SIGPWR" + }; + extern void ILibDuktape_MemoryStream_Init(duk_context *ctx); extern void ILibDuktape_NetworkMonitor_Init(duk_context *ctx); extern int GenerateSHA384FileHash(char *filePath, char *fileHash); @@ -945,6 +980,7 @@ void ILibDuktape_ScriptContainer_Process_SignalListener_PreSelect(void* object, } void ILibDuktape_ScriptContainer_Process_SignalListener_PostSelect(void* object, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset) { + int s; int bytesRead = 0; char sigbuffer[255]; ILibChain_Link *link = (ILibChain_Link*)object; @@ -959,15 +995,20 @@ void ILibDuktape_ScriptContainer_Process_SignalListener_PostSelect(void* object, switch (((int*)sigbuffer)[1]) { case SIGTERM: - ILibDuktape_EventEmitter_SetupEmit(ctx, h, "SIGTERM"); - if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting SIGTERM: "); } + ILibDuktape_EventEmitter_SetupEmit(ctx, h, "SIGTERM"); // [emit][this][SIGTERM] + duk_push_string(ctx, SIGTABLE[((int*)sigbuffer)[1]]); // [emit][this][SIGTERM][name] + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting SIGTERM: "); } duk_pop(ctx); break; case SIGCHLD: + s = 0; + waitpid(((pid_t*)sigbuffer)[2], &s, 0); ILibDuktape_EventEmitter_SetupEmit(ctx, h, "SIGCHLD"); // [emit][this][SIGCHLD] - duk_push_int(ctx, ((pid_t*)sigbuffer)[2]); // [emit][this][SIGCHLD][pid] - duk_push_uint(ctx, ((uid_t*)sigbuffer)[3]); // [emit][this][SIGCHLD][pid][uid] - if (duk_pcall_method(ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting SIGCHLD: "); } + duk_push_string(ctx, SIGTABLE[((int*)sigbuffer)[1]]); // [emit][this][SIGTERM][name] + duk_push_int(ctx, s); // [emit][this][SIGCHLD][name][code] + duk_push_int(ctx, ((pid_t*)sigbuffer)[2]); // [emit][this][SIGCHLD][name][code][pid] + duk_push_uint(ctx, ((uid_t*)sigbuffer)[3]); // [emit][this][SIGCHLD][name][code][pid][uid] + if (duk_pcall_method(ctx, 5) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting SIGCHLD: "); } duk_pop(ctx); break; default: @@ -1398,7 +1439,15 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) } } #endif - +} +void* ILibDuktape_Process_GetSignalListener(duk_context *ctx) +{ + void *ret = NULL; + duk_push_global_object(ctx); // [g] + duk_get_prop_string(ctx, -1, "process"); // [g][p] + ret = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Signal_ListenerPtr); + duk_pop_2(ctx); // ... + return(ret); } void ILibDuktape_ScriptContainer_ExecTimeout_Finalizer(duk_context *ctx, void *timeoutKey) { diff --git a/microscript/ILibDuktape_ScriptContainer.h b/microscript/ILibDuktape_ScriptContainer.h index 217a7ca..b94e784 100644 --- a/microscript/ILibDuktape_ScriptContainer.h +++ b/microscript/ILibDuktape_ScriptContainer.h @@ -161,4 +161,6 @@ int ILibDuktape_ScriptContainer_CompileJavaScriptEx(duk_context *ctx, char *payl #define ILibDuktape_ScriptContainer_CompileJavaScript(ctx, payload, payloadLen) ILibDuktape_ScriptContainer_CompileJavaScriptEx(ctx, payload, payloadLen, NULL, 0) int ILibDuktape_ScriptContainer_ExecuteByteCode(duk_context *ctx); +void* ILibDuktape_Process_GetSignalListener(duk_context *ctx); + #endif