1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-14 15:23:39 +00:00

1. Updated WaitHandle_Add2 to no use APC to dispatch to event loop, becuase winsock is not re-entrant, and don't want to risk corruption

2. Updated memory handling for async methods in Generic Marshal
This commit is contained in:
Bryan Roe
2020-04-18 13:53:38 -07:00
parent df752bdc70
commit 743a38eeeb
3 changed files with 59 additions and 23 deletions

View File

@@ -47,6 +47,8 @@ limitations under the License.
#include <dlfcn.h> #include <dlfcn.h>
#endif #endif
#define ILibDuktape_GenericMarshal_INVALID_PROMISE ((void*)(uintptr_t)0x01)
#define ILibDuktape_GenericMarshal_FuncHandler "\xFF_GenericMarshal_FuncHandler" #define ILibDuktape_GenericMarshal_FuncHandler "\xFF_GenericMarshal_FuncHandler"
#define ILibDuktape_GenericMarshal_VariableType "\xFF_GenericMarshal_VarType" #define ILibDuktape_GenericMarshal_VariableType "\xFF_GenericMarshal_VarType"
#define ILibDuktape_GenericMarshal_GlobalSet_List "\xFF_GenericMarshal_GlobalSet_List" #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) if (data->waitingForResult == 0)
{ {
// We cannot gracefully exit the thread, so let's reject the promise, and let the app layer figure it out if (data->promise != ILibDuktape_GenericMarshal_INVALID_PROMISE)
duk_push_heapptr(data->ctx, data->promise); // [promise] {
duk_get_prop_string(data->ctx, -1, "_REJ"); // [promise][rej] // We cannot gracefully exit the thread, so let's reject the promise, and let the app layer figure it out
duk_swap_top(data->ctx, -2); // [rej][this] duk_push_heapptr(data->ctx, data->promise); // [promise]
duk_push_string(data->ctx, "ABORT"); // [rej][this][abort] 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; data->abort = 1;
duk_call_method(ctx, 1); duk_call_method(ctx, 1);
duk_pop(ctx); // ... duk_pop(ctx); // ...
// //
// We are purposefully not clearing the promise, becuase the hope is that the above layer // 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. // will receive this rejection, and do a proper cleanup, which may need the promise to accomplish that.
// //
}
} }
else else
{ {
@@ -1027,11 +1032,15 @@ duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync_dataFinalizer(duk_context
} }
#ifdef WIN32 #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; ILibDuktape_FFI_AsyncData *data = (ILibDuktape_FFI_AsyncData*)u;
duk_context *ctx; duk_context *ctx;
if (!ILibMemory_CanaryOK(data)) { return; } 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_push_heapptr(data->ctx, data->promise); // [promise]
duk_get_prop_string(data->ctx, -1, "_RES"); // [promise][resolver] 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->workAvailable = (void*)ILibDuktape_GenericMarshal_MethodInvoke_Native(varCount-1, data->fptr, var);
data->lastError = (DWORD)GetLastError(); 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 #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) duk_ret_t ILibDuktape_GenericMarshal_MethodInvokeAsync(duk_context *ctx)
{ {
void *redirectionPtr = NULL, *redirectionPtrName = NULL; 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); Duktape_GlobalGeneric_Data *ggd = (Duktape_GlobalGeneric_Data*)Duktape_GetPointerProperty(ctx, 0, ILibDuktape_GenericMarshal_GlobalSet_Dispatcher);
redirectionPtr = NULL; 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)); data = (ILibDuktape_FFI_AsyncData*)ILibMemory_SmartAllocate(sizeof(ILibDuktape_FFI_AsyncData));
duk_push_pointer(ctx, data); duk_push_pointer(ctx, data);
duk_put_prop_string(ctx, -2, ILibDuktape_FFI_AsyncDataPtr); 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->ctx = ctx;
data->ctxnonce = duk_ctx_nonce(ctx); data->ctxnonce = duk_ctx_nonce(ctx);
data->promise = ggd->dispatch->promise; data->promise = ggd->dispatch->promise;
data->chain = duk_ctx_chain(ctx);
duk_push_current_function(ctx); // [promise][func] duk_push_current_function(ctx); // [promise][func]
data->fptr = Duktape_GetPointerProperty(ctx, -1, "_address"); 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_eval_string(ctx, "require('promise');"); // [func][promise]
duk_push_c_function(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promise, 2); duk_push_c_function(ctx, ILibDuktape_GenericMarshal_MethodInvokeAsync_promise, 2);
duk_new(ctx, 1); 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->promise = duk_get_heapptr(ctx, -1);
} }
data->vars = (PTRSIZE*)ILibMemory_AllocateA(sizeof(PTRSIZE)*parms); data->vars = (PTRSIZE*)ILibMemory_AllocateA(sizeof(PTRSIZE)*parms);

View File

@@ -181,6 +181,7 @@ typedef struct ILibProcessPipe_WaitHandle_APC
HANDLE ev; HANDLE ev;
ILibWaitHandle_ErrorStatus status; ILibWaitHandle_ErrorStatus status;
ILibProcessPipe_WaitHandle_Handler callback; ILibProcessPipe_WaitHandle_Handler callback;
void *chain;
void *user; void *user;
}ILibProcessPipe_WaitHandle_APC; }ILibProcessPipe_WaitHandle_APC;
HANDLE ILibProcessPipe_Manager_GetWorkerThread(ILibProcessPipe_Manager mgr) HANDLE ILibProcessPipe_Manager_GetWorkerThread(ILibProcessPipe_Manager mgr)
@@ -204,6 +205,7 @@ void __stdcall ILibProcessPipe_WaitHandle_Remove_APC(ULONG_PTR obj)
if (node != NULL) if (node != NULL)
{ {
waiter = (ILibProcessPipe_WaitHandle*)ILibLinkedList_GetDataFromNode(node); waiter = (ILibProcessPipe_WaitHandle*)ILibLinkedList_GetDataFromNode(node);
if (waiter->callback != NULL) { waiter->callback(waiter->event, ILibWaitHandle_ErrorStatus_REMOVED, waiter->user); }
free(waiter); free(waiter);
ILibLinkedList_Remove(node); ILibLinkedList_Remove(node);
SetEvent(manager->updateEvent); SetEvent(manager->updateEvent);
@@ -256,7 +258,7 @@ void ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(ILibProcessPipe_Manager m
ILibProcessPipe_WaitHandle_AddEx(mgr, waitHandle); 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)) if (ILibMemory_CanaryOK((void*)obj))
{ {
@@ -269,7 +271,14 @@ BOOL ILibProcessPipe_WaitHandle_Add2_sink(HANDLE event, ILibWaitHandle_ErrorStat
{ {
if (ILibMemory_CanaryOK(user)) 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); return(FALSE);
} }
@@ -279,9 +288,9 @@ void ILibProcessPipe_WaitHandle_Add2_WithNonZeroTimeout(ILibProcessPipe_Manager
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &apcState->callingThread, THREAD_SET_CONTEXT, FALSE, 0); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &apcState->callingThread, THREAD_SET_CONTEXT, FALSE, 0);
apcState->callback = callback; apcState->callback = callback;
apcState->user = user; apcState->user = user;
apcState->chain = ((ILibProcessPipe_Manager_Object*)mgr)->ChainLink.ParentChain;
ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(mgr, event, milliseconds, apcState, ILibProcessPipe_WaitHandle_Add2_sink); ILibProcessPipe_WaitHandle_Add_WithNonZeroTimeout(mgr, event, milliseconds, apcState, ILibProcessPipe_WaitHandle_Add2_sink);
} }
void ILibProcessPipe_Manager_WindowsRunLoopEx(void *arg) void ILibProcessPipe_Manager_WindowsRunLoopEx(void *arg)
{ {
ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)arg; ILibProcessPipe_Manager_Object *manager = (ILibProcessPipe_Manager_Object*)arg;

View File

@@ -106,7 +106,9 @@ typedef enum ILibWaitHandle_ErrorStatus
{ {
ILibWaitHandle_ErrorStatus_NONE = 0, ILibWaitHandle_ErrorStatus_NONE = 0,
ILibWaitHandle_ErrorStatus_INVALID_HANDLE = 1, ILibWaitHandle_ErrorStatus_INVALID_HANDLE = 1,
ILibWaitHandle_ErrorStatus_TIMEOUT = 2 ILibWaitHandle_ErrorStatus_TIMEOUT = 2,
ILibWaitHandle_ErrorStatus_REMOVED = 3,
ILibWaitHandle_ErrorStatus_MANAGER_EXITING = 4
}ILibWaitHandle_ErrorStatus; }ILibWaitHandle_ErrorStatus;
typedef BOOL(*ILibProcessPipe_WaitHandle_Handler)(HANDLE event, ILibWaitHandle_ErrorStatus status, void* user); 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); 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) #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); 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) #define ILibProcessPipe_WaitHandle_Add2(processPipeManager, eventHandle, user, callback) ILibProcessPipe_WaitHandle_Add2_WithNonZeroTimeout(processPipeManager, eventHandle, 0, user, callback)