diff --git a/microscript/ILibDuktape_GenericMarshal.c b/microscript/ILibDuktape_GenericMarshal.c index 42e4df4..0c74b56 100644 --- a/microscript/ILibDuktape_GenericMarshal.c +++ b/microscript/ILibDuktape_GenericMarshal.c @@ -47,6 +47,8 @@ limitations under the License. #include #endif +#define ILibDuktape_GenericMarshal_INVALID_PROMISE ((void*)(uintptr_t)0x01) + #define ILibDuktape_GenericMarshal_FuncHandler "\xFF_GenericMarshal_FuncHandler" #define ILibDuktape_GenericMarshal_VariableType "\xFF_GenericMarshal_VarType" #define ILibDuktape_GenericMarshal_GlobalSet_List "\xFF_GenericMarshal_GlobalSet_List" @@ -975,20 +977,23 @@ duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync_abort(duk_context *ctx) { if (data->waitingForResult == 0) { - // We cannot gracefully exit the thread, so let's reject the promise, and let the app layer figure it out - duk_push_heapptr(data->ctx, data->promise); // [promise] - duk_get_prop_string(data->ctx, -1, "_REJ"); // [promise][rej] - duk_swap_top(data->ctx, -2); // [rej][this] - duk_push_string(data->ctx, "ABORT"); // [rej][this][abort] + if (data->promise != ILibDuktape_GenericMarshal_INVALID_PROMISE) + { + // We cannot gracefully exit the thread, so let's reject the promise, and let the app layer figure it out + duk_push_heapptr(data->ctx, data->promise); // [promise] + duk_get_prop_string(data->ctx, -1, "_REJ"); // [promise][rej] + duk_swap_top(data->ctx, -2); // [rej][this] + duk_push_string(data->ctx, "ABORT"); // [rej][this][abort] - data->abort = 1; - duk_call_method(ctx, 1); - duk_pop(ctx); // ... + data->abort = 1; + duk_call_method(ctx, 1); + duk_pop(ctx); // ... - // - // We are purposefully not clearing the promise, becuase the hope is that the above layer - // will receive this rejection, and do a proper cleanup, which may need the promise to accomplish that. - // + // + // We are purposefully not clearing the promise, becuase the hope is that the above layer + // will receive this rejection, and do a proper cleanup, which may need the promise to accomplish that. + // + } } else { @@ -1027,11 +1032,15 @@ duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync_dataFinalizer(duk_context } #ifdef WIN32 -void __stdcall ILibDuktape_GenericMarshal_MethodInvokeAsync_Done_APC(ULONG_PTR u) +void ILibDuktape_GenericMarshal_MethodInvokeAsync_Done_chain(void *chain, void* u) { ILibDuktape_FFI_AsyncData *data = (ILibDuktape_FFI_AsyncData*)u; duk_context *ctx; if (!ILibMemory_CanaryOK(data)) { return; } + if (!ILibMemory_CanaryOK(data->ctx) || data->promise == NULL || data->promise == ILibDuktape_GenericMarshal_INVALID_PROMISE) + { + return; + } duk_push_heapptr(data->ctx, data->promise); // [promise] duk_get_prop_string(data->ctx, -1, "_RES"); // [promise][resolver] @@ -1062,10 +1071,20 @@ void __stdcall ILibDuktape_GenericMarshal_MethodInvokeAsync_APC(ULONG_PTR u) data->workAvailable = (void*)ILibDuktape_GenericMarshal_MethodInvoke_Native(varCount-1, data->fptr, var); data->lastError = (DWORD)GetLastError(); - QueueUserAPC((PAPCFUNC)ILibDuktape_GenericMarshal_MethodInvokeAsync_Done_APC, data->workFinished, (ULONG_PTR)data); + ILibChain_RunOnMicrostackThread(data->chain, ILibDuktape_GenericMarshal_MethodInvokeAsync_Done_chain, data); } #endif +duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync_promfin(duk_context *ctx) +{ + ILibDuktape_FFI_AsyncData *data = (ILibDuktape_FFI_AsyncData*)Duktape_GetPointerProperty(ctx, 0, "_data"); + void *h = duk_get_heapptr(ctx, 0); + if (ILibMemory_CanaryOK(data) && data->promise == h) + { + data->promise = ILibDuktape_GenericMarshal_INVALID_PROMISE; + } + return(0); +} duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync(duk_context *ctx) { void *redirectionPtr = NULL, *redirectionPtrName = NULL; @@ -1095,17 +1114,21 @@ duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync(duk_context *ctx) Duktape_GlobalGeneric_Data *ggd = (Duktape_GlobalGeneric_Data*)Duktape_GetPointerProperty(ctx, 0, ILibDuktape_GenericMarshal_GlobalSet_Dispatcher); redirectionPtr = NULL; - duk_eval_string(ctx, "require('promise');"); // [func][promise] - duk_push_c_function(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promise, 2); - duk_new(ctx, 1); - ggd->dispatch->promise = duk_get_heapptr(ctx, -1); data = (ILibDuktape_FFI_AsyncData*)ILibMemory_SmartAllocate(sizeof(ILibDuktape_FFI_AsyncData)); duk_push_pointer(ctx, data); duk_put_prop_string(ctx, -2, ILibDuktape_FFI_AsyncDataPtr); + duk_eval_string(ctx, "require('promise');"); // [func][promise] + duk_push_c_function(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promise, 2); + duk_new(ctx, 1); + ILibDuktape_CreateFinalizer(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promfin); + duk_push_pointer(ctx, data); duk_put_prop_string(ctx, -2, "_data"); + ggd->dispatch->promise = duk_get_heapptr(ctx, -1); + data->ctx = ctx; data->ctxnonce = duk_ctx_nonce(ctx); data->promise = ggd->dispatch->promise; + data->chain = duk_ctx_chain(ctx); duk_push_current_function(ctx); // [promise][func] data->fptr = Duktape_GetPointerProperty(ctx, -1, "_address"); @@ -1157,6 +1180,8 @@ duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync(duk_context *ctx) duk_eval_string(ctx, "require('promise');"); // [func][promise] duk_push_c_function(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promise, 2); duk_new(ctx, 1); + ILibDuktape_CreateFinalizer(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promfin); + duk_push_pointer(ctx, data); duk_put_prop_string(ctx, -2, "_data"); data->promise = duk_get_heapptr(ctx, -1); } data->vars = (PTRSIZE*)ILibMemory_AllocateA(sizeof(PTRSIZE)*parms); diff --git a/microstack/ILibProcessPipe.c b/microstack/ILibProcessPipe.c index dbe8e70..800556e 100644 --- a/microstack/ILibProcessPipe.c +++ b/microstack/ILibProcessPipe.c @@ -181,6 +181,7 @@ typedef struct ILibProcessPipe_WaitHandle_APC HANDLE ev; ILibWaitHandle_ErrorStatus status; ILibProcessPipe_WaitHandle_Handler callback; + void *chain; void *user; }ILibProcessPipe_WaitHandle_APC; HANDLE ILibProcessPipe_Manager_GetWorkerThread(ILibProcessPipe_Manager mgr) @@ -204,6 +205,7 @@ void __stdcall ILibProcessPipe_WaitHandle_Remove_APC(ULONG_PTR obj) if (node != NULL) { waiter = (ILibProcessPipe_WaitHandle*)ILibLinkedList_GetDataFromNode(node); + if (waiter->callback != NULL) { waiter->callback(waiter->event, ILibWaitHandle_ErrorStatus_REMOVED, waiter->user); } free(waiter); ILibLinkedList_Remove(node); SetEvent(manager->updateEvent); @@ -256,7 +258,7 @@ void ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(ILibProcessPipe_Manager m ILibProcessPipe_WaitHandle_AddEx(mgr, waitHandle); } -void __stdcall ILibProcessPipe_WaitHandle_Add2_apcsink(ULONG_PTR obj) +void ILibProcessPipe_WaitHandle_Add2_chainsink(void *chain, void *obj) { if (ILibMemory_CanaryOK((void*)obj)) { @@ -269,7 +271,14 @@ BOOL ILibProcessPipe_WaitHandle_Add2_sink(HANDLE event, ILibWaitHandle_ErrorStat { if (ILibMemory_CanaryOK(user)) { - QueueUserAPC((PAPCFUNC)ILibProcessPipe_WaitHandle_Add2_apcsink, ((ILibProcessPipe_WaitHandle_APC*)user)->callingThread, (ULONG_PTR)user); + if (status == ILibWaitHandle_ErrorStatus_REMOVED || ILibWaitHandle_ErrorStatus_MANAGER_EXITING) + { + ILibMemory_Free(user); + } + else + { + ILibChain_RunOnMicrostackThread(((ILibProcessPipe_WaitHandle_APC*)user)->chain, ILibProcessPipe_WaitHandle_Add2_chainsink, user); + } } return(FALSE); } @@ -279,9 +288,9 @@ void ILibProcessPipe_WaitHandle_Add2_WithNonZeroTimeout(ILibProcessPipe_Manager DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &apcState->callingThread, THREAD_SET_CONTEXT, FALSE, 0); apcState->callback = callback; apcState->user = user; + apcState->chain = ((ILibProcessPipe_Manager_Object*)mgr)->ChainLink.ParentChain; ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(mgr, event, milliseconds, apcState, ILibProcessPipe_WaitHandle_Add2_sink); } - void ILibProcessPipe_Manager_WindowsRunLoopEx(void *arg) { ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)arg; diff --git a/microstack/ILibProcessPipe.h b/microstack/ILibProcessPipe.h index c9233e0..16f89ab 100644 --- a/microstack/ILibProcessPipe.h +++ b/microstack/ILibProcessPipe.h @@ -106,7 +106,9 @@ typedef enum ILibWaitHandle_ErrorStatus { ILibWaitHandle_ErrorStatus_NONE = 0, ILibWaitHandle_ErrorStatus_INVALID_HANDLE = 1, - ILibWaitHandle_ErrorStatus_TIMEOUT = 2 + ILibWaitHandle_ErrorStatus_TIMEOUT = 2, + ILibWaitHandle_ErrorStatus_REMOVED = 3, + ILibWaitHandle_ErrorStatus_MANAGER_EXITING = 4 }ILibWaitHandle_ErrorStatus; typedef BOOL(*ILibProcessPipe_WaitHandle_Handler)(HANDLE event, ILibWaitHandle_ErrorStatus status, void* user); @@ -116,7 +118,7 @@ void ILibProcessPipe_WaitHandle_Remove(ILibProcessPipe_Manager mgr, HANDLE event void ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(ILibProcessPipe_Manager mgr, HANDLE event, int milliseconds, void *user, ILibProcessPipe_WaitHandle_Handler callback); #define ILibProcessPipe_WaitHandle_Add(processPipeManager, eventHandle, user, callback) ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(processPipeManager, eventHandle, 0, user, callback) -// These methods will use an APC to context switch to the calling thread when dispatching +// These methods will context switch to the chain thread when dispatching void ILibProcessPipe_WaitHandle_Add2_WithNonZeroTimeout(ILibProcessPipe_Manager mgr, HANDLE event, int milliseconds, void *user, ILibProcessPipe_WaitHandle_Handler callback); #define ILibProcessPipe_WaitHandle_Add2(processPipeManager, eventHandle, user, callback) ILibProcessPipe_WaitHandle_Add2_WithNonZeroTimeout(processPipeManager, eventHandle, 0, user, callback)