From 77834337fd846626bb9171e85bd8f5053b00d78b Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Thu, 26 Nov 2020 11:30:23 -0800 Subject: [PATCH] 1. Fixed process HANDLE leak on windows 2. Replaced semaphore with spinlock on event emitter object. --- microscript/ILibDuktape_EventEmitter.h | 2 +- microscript/ILibDuktape_ScriptContainer.c | 42 +++++++++++++++++++++++ microscript/ILibduktape_EventEmitter.c | 11 +++--- microstack/ILibParsers.c | 3 ++ microstack/ILibParsers.h | 42 +++++++++++++++++------ microstack/ILibProcessPipe.c | 3 ++ 6 files changed, 85 insertions(+), 18 deletions(-) diff --git a/microscript/ILibDuktape_EventEmitter.h b/microscript/ILibDuktape_EventEmitter.h index 17c173b..25d1b37 100644 --- a/microscript/ILibDuktape_EventEmitter.h +++ b/microscript/ILibDuktape_EventEmitter.h @@ -37,7 +37,7 @@ typedef struct ILibDuktape_EventEmitter unsigned int *totalListeners; const char *listenerCountTable; size_t listenerCountTableLength; - sem_t listenerCountTableLock; + ILibSpinLock listenerCountTableLock; ILibDuktape_EventEmitter_Types eventType; }ILibDuktape_EventEmitter; typedef void(*ILibDuktape_EventEmitter_HookHandler)(ILibDuktape_EventEmitter *sender, char *eventName, void *hookedCallback); diff --git a/microscript/ILibDuktape_ScriptContainer.c b/microscript/ILibDuktape_ScriptContainer.c index 2754249..e422f53 100644 --- a/microscript/ILibDuktape_ScriptContainer.c +++ b/microscript/ILibDuktape_ScriptContainer.c @@ -1167,7 +1167,48 @@ duk_ret_t ILibDuktape_Process_Exitting(duk_context *ctx) duk_push_boolean(ctx, (duk_bool_t)duk_ctx_shutting_down(ctx)); return(1); } +void ILibDuktape_Process_SemaphoreTracking_sink(char *source, void *user, int init) +{ + duk_context *ctx = user; + if (ctx != NULL && duk_ctx_is_alive(ctx) != 0 && duk_ctx_shutting_down(ctx) == 0) + { + duk_push_heap_stash(ctx); // [stash] + int v = Duktape_GetIntPropertyValue(ctx, -1, "_SemTrack", 0); + duk_push_int(ctx, init ? (++v) : (--v)); // [stash][int] + duk_put_prop_string(ctx, -2, "_SemTrack"); // [stash] + duk_pop(ctx); // ... + duk_push_global_object(ctx); // [g] + duk_get_prop_string(ctx, -1, "console"); // [g][console] + duk_prepare_method_call(ctx, -1, "log"); // [g][console][log][this] + duk_push_sprintf(ctx, "[%d] Semaphore <<%s>> (%s)", v, source, init ? "INIT" : "DESTROY"); // [g][console][log][this][string] + duk_pcall_method(ctx, 1); // [g][console][val] + duk_pop_3(ctx); // ... + } + else + { + ILibSemaphoreTrack_user = NULL; + ILibSemaphoreTrack_func = NULL; + } +} +duk_ret_t ILibDuktape_Process_SemaphoreTracking(duk_context *ctx) +{ + if (duk_require_boolean(ctx, 0) != 0) + { + duk_push_heap_stash(ctx); // [stash] + duk_push_int(ctx, 0); // [stash][int] + duk_put_prop_string(ctx, -2, "_SemTrack"); // [stash] + duk_pop(ctx); // ... + ILibSemaphoreTrack_user = ctx; + ILibSemaphoreTrack_func = ILibDuktape_Process_SemaphoreTracking_sink; + } + else + { + ILibSemaphoreTrack_user = NULL; + ILibSemaphoreTrack_func = NULL; + } + return(0); +} void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) { int i = 0; @@ -1183,6 +1224,7 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) ILibDuktape_CreateEventWithGetter(ctx, "env", ILibDuktape_ScriptContainer_Process_env); ILibDuktape_CreateInstanceMethod(ctx, "cwd", ILibDuktape_Process_cwd, 0); ILibDuktape_CreateInstanceMethod(ctx, "setenv", ILibDuktape_Process_setenv, 2); + ILibDuktape_CreateEventWithSetterEx(ctx, "_SemaphoreTracking", ILibDuktape_Process_SemaphoreTracking); ILibDuktape_CreateEventWithGetterAndSetterEx(ctx, "coreDumpLocation", ILibDuktape_ScriptContainer_Process_coreDumpLocation_getter, ILibDuktape_ScriptContainer_Process_coreDumpLocation_setter); #ifndef WIN32 ILibDuktape_CreateEventWithGetter(ctx, "rlimit", ILibDuktape_ScriptContainer_Process_rlimit_getter); diff --git a/microscript/ILibduktape_EventEmitter.c b/microscript/ILibduktape_EventEmitter.c index 96646e5..d6e6656 100644 --- a/microscript/ILibduktape_EventEmitter.c +++ b/microscript/ILibduktape_EventEmitter.c @@ -133,7 +133,7 @@ int ILibDuktape_EventEmitter_HasListeners2(ILibDuktape_EventEmitter *emitter, ch int retVal = defaultValue; if (emitter != NULL && ILibMemory_CanaryOK(emitter) && duk_ctx_is_alive(emitter->ctx)) { - sem_wait(&(emitter->listenerCountTableLock)); + ILibSpinLock_Lock(&(emitter->listenerCountTableLock)); if (emitter->listenerCountTableLength > 2 && emitter->listenerCountTableLength < INT32_MAX) { size_t eventNameLen = strnlen_s(eventName, ILibDuktape_EventEmitter_MaxEventNameLen); @@ -169,7 +169,7 @@ int ILibDuktape_EventEmitter_HasListeners2(ILibDuktape_EventEmitter *emitter, ch } ILibDestructParserResults(pr); } - sem_post(&(emitter->listenerCountTableLock)); + ILibSpinLock_UnLock(&(emitter->listenerCountTableLock)); } return(retVal); } @@ -541,7 +541,6 @@ duk_ret_t ILibDuktape_EventEmitter_EmbeddedFinalizer(duk_context *ctx) ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error in Finalizer (%s): [Invalid C function means you forgot to return 0] ", meta); } - sem_destroy(&(data->listenerCountTableLock)); return(0); } duk_ret_t ILibDuktape_EventEmitter_emitReturnValue(duk_context *ctx) @@ -653,7 +652,7 @@ duk_ret_t ILibDuktape_EventEmitter_listeners_tableinit(duk_context *ctx) duk_push_this(ctx); ILibDuktape_EventEmitter *emitter = (ILibDuktape_EventEmitter*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_EventEmitter_Data); - sem_wait(&(emitter->listenerCountTableLock)); + ILibSpinLock_Lock(&(emitter->listenerCountTableLock)); duk_push_global_object(ctx); // [g] duk_get_prop_string(ctx, -1, "JSON"); // [g][JSON] duk_prepare_method_call(ctx, -1, "parse"); // [g][JSON][parse][this] @@ -712,7 +711,7 @@ duk_ret_t ILibDuktape_EventEmitter_listeners_tableinit(duk_context *ctx) } } } - sem_post(&(emitter->listenerCountTableLock)); + ILibSpinLock_UnLock(&(emitter->listenerCountTableLock)); return(0); } @@ -738,7 +737,7 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx) duk_push_object(ctx); retVal->retValTable = duk_get_heapptr(ctx, -1); duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_LastRetValueTable); - sem_init(&(retVal->listenerCountTableLock), 0, 1); + ILibSpinLock_Init(&(retVal->listenerCountTableLock)); retVal->listenerCountTable = (char*)"[]"; retVal->listenerCountTableLength = 2; diff --git a/microstack/ILibParsers.c b/microstack/ILibParsers.c index 6182d6c..7c9b9a4 100644 --- a/microstack/ILibParsers.c +++ b/microstack/ILibParsers.c @@ -131,6 +131,9 @@ char ILibScratchPad[4096]; // General buffer char ILibScratchPad2[65536]; // Often used for UDP packet processing void* gILibChain = NULL; // Global Chain Instance used for Remote Logging when a chain instance isn't otherwise exposed +ILibSemaphoreTrack_Handler ILibSemaphoreTrack_func = NULL; +void* ILibSemaphoreTrack_user = NULL; + #define ILibChain_SIGMAX 32 ILibLinkedList g_signalHandlers[ILibChain_SIGMAX] = { NULL }; typedef struct ILibChain_SignalHandlerData diff --git a/microstack/ILibParsers.h b/microstack/ILibParsers.h index c67b754..b31dab2 100644 --- a/microstack/ILibParsers.h +++ b/microstack/ILibParsers.h @@ -112,6 +112,32 @@ struct sockaddr_in6; #include #endif +#ifndef WIN32 +#include +#endif + +#ifdef WIN32 + typedef volatile long ILibSpinLock; +#else + typedef volatile int ILibSpinLock; +#endif +static inline void ILibSpinLock_Init(ILibSpinLock *lock) { *lock = 0; } +static inline void ILibSpinLock_UnLock(ILibSpinLock *lock) { *lock = 0; } +static inline void ILibSpinLock_Lock(ILibSpinLock *lock) +{ +#ifdef WIN32 + while (!InterlockedCompareExchange(lock, 1, 0)) + { + YieldProcessor(); + } +#else + while (!__sync_bool_compare_and_swap(lock, 0, 1)) + { + sched_yield(); + } +#endif +} + #ifdef WIN32 #define ILIB_CURRENT_THREAD (unsigned int)GetCurrentThreadId() #else @@ -170,6 +196,9 @@ static inline void ignore_result(uintptr_t result) { (void)result; } #define PRINTERROR() #endif +typedef void(*ILibSemaphoreTrack_Handler)(char *source, void *user, int init); +extern ILibSemaphoreTrack_Handler ILibSemaphoreTrack_func; +extern void* ILibSemaphoreTrack_user; int ILib_atoi_uint64_ex(uint64_t *val, const char *instr, size_t instrLen, uint64_t MAX); int ILib_atoi_uint32_ex(uint32_t *val, const char *instr, size_t instrLen, uint64_t MAX); @@ -238,21 +267,12 @@ long ILibGetTimeStamp(); // Implemented in Windows using events. #define sem_t HANDLE -#define sem_init(x,pShared,InitValue) *x=CreateSemaphore(NULL,InitValue,SEM_MAX_COUNT,NULL) -#define sem_destroy(x) (CloseHandle(*x)==0?1:0) +#define sem_init(x,pShared,InitValue) *x=CreateSemaphore(NULL,InitValue,SEM_MAX_COUNT,NULL);if(ILibSemaphoreTrack_func!=NULL){char tmp[512];sprintf_s(tmp, sizeof(tmp), "(%p) %s:%d",(void*)(x),__FILE__,__LINE__);ILibSemaphoreTrack_func(tmp,ILibSemaphoreTrack_user,1);} +#define sem_destroy(x) (CloseHandle(*x)==0?1:0);if(ILibSemaphoreTrack_func!=NULL){char tmp[512];sprintf_s(tmp, sizeof(tmp), "(%p) %s:%d",(void*)(x),__FILE__,__LINE__);ILibSemaphoreTrack_func(tmp,ILibSemaphoreTrack_user,0);} #define sem_wait(x) WaitForSingleObject(*x,INFINITE) #define sem_trywait(x) ((WaitForSingleObject(*x,0)==WAIT_OBJECT_0)?0:1) #define sem_post(x) ReleaseSemaphore(*x,1,NULL) - -//// Implemented in Windows using critical section. -//#define sem_t CRITICAL_SECTION -//#define sem_init(x,pShared,InitValue) InitializeCriticalSection(x); -//#define sem_destroy(x) (DeleteCriticalSection(x)) -//#define sem_wait(x) EnterCriticalSection(x) -//#define sem_trywait(x) TryEnterCriticalSection(x) -//#define sem_post(x) LeaveCriticalSection(x) - #define strncasecmp(x,y,z) _strnicmp(x,y,z) #define strcasecmp(x,y) _stricmp(x,y) #define gettimeofday(tp,tzp) ILibGetTimeOfDay(tp) diff --git a/microstack/ILibProcessPipe.c b/microstack/ILibProcessPipe.c index 69fd1ae..d958b62 100644 --- a/microstack/ILibProcessPipe.c +++ b/microstack/ILibProcessPipe.c @@ -451,6 +451,9 @@ void ILibProcessPipe_Process_Destroy(ILibProcessPipe_Process_Object *p) if (p->stdOut != NULL) { ILibProcessPipe_FreePipe(p->stdOut); } if (p->stdErr != NULL) { ILibProcessPipe_FreePipe(p->stdErr); } if (p->metadata != NULL) { ILibMemory_Free(p->metadata); } +#ifdef WIN32 + if (p->hProcess != NULL) { CloseHandle(p->hProcess); } +#endif ILibMemory_Free(p); } #ifndef WIN32