Script: Add mScriptContextInvoke for context-specific invocation and thread handling

This commit is contained in:
Vicki Pfau 2023-08-02 23:41:40 -07:00
parent 5534d23690
commit 09b7eea127
4 changed files with 89 additions and 7 deletions

View File

@ -36,6 +36,7 @@ struct mScriptContext {
uint32_t nextCallbackId; uint32_t nextCallbackId;
struct mScriptValue* constants; struct mScriptValue* constants;
struct Table docstrings; struct Table docstrings;
int threadDepth;
}; };
struct mScriptEngine2 { struct mScriptEngine2 {
@ -110,6 +111,12 @@ struct VFile;
bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf); bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf);
bool mScriptContextLoadFile(struct mScriptContext*, const char* path); bool mScriptContextLoadFile(struct mScriptContext*, const char* path);
struct mScriptContext* mScriptActiveContext(void);
bool mScriptContextActivate(struct mScriptContext*);
void mScriptContextDeactivate(struct mScriptContext*);
bool mScriptContextInvoke(struct mScriptContext*, const struct mScriptValue* fn, struct mScriptFrame* frame);
bool mScriptInvoke(const struct mScriptValue* fn, struct mScriptFrame* frame); bool mScriptInvoke(const struct mScriptValue* fn, struct mScriptFrame* frame);
CXX_GUARD_END CXX_GUARD_END

View File

@ -761,7 +761,7 @@ static int64_t _addCallbackToBreakpoint(struct mScriptDebugger* debugger, struct
return cbid; return cbid;
} }
static void _runCallbacks(struct mScriptBreakpoint* point) { static void _runCallbacks(struct mScriptDebugger* debugger, struct mScriptBreakpoint* point) {
struct TableIterator iter; struct TableIterator iter;
if (!HashTableIteratorStart(&point->callbacks, &iter)) { if (!HashTableIteratorStart(&point->callbacks, &iter)) {
return; return;
@ -770,7 +770,7 @@ static void _runCallbacks(struct mScriptBreakpoint* point) {
struct mScriptValue* fn = HashTableIteratorGetValue(&point->callbacks, &iter); struct mScriptValue* fn = HashTableIteratorGetValue(&point->callbacks, &iter);
struct mScriptFrame frame; struct mScriptFrame frame;
mScriptFrameInit(&frame); mScriptFrameInit(&frame);
mScriptInvoke(fn, &frame); mScriptContextInvoke(debugger->p->context, fn, &frame);
mScriptFrameDeinit(&frame); mScriptFrameDeinit(&frame);
} while (HashTableIteratorNext(&point->callbacks, &iter)); } while (HashTableIteratorNext(&point->callbacks, &iter));
} }
@ -812,7 +812,7 @@ static void _scriptDebuggerEntered(struct mDebuggerModule* debugger, enum mDebug
default: default:
return; return;
} }
_runCallbacks(point); _runCallbacks(scriptDebugger, point);
debugger->isPaused = false; debugger->isPaused = false;
} }
@ -1085,7 +1085,7 @@ static bool _callRotationCb(struct mScriptCoreAdapter* adapter, const char* cbNa
if (context) { if (context) {
mScriptValueWrap(context, mScriptListAppend(&frame.arguments)); mScriptValueWrap(context, mScriptListAppend(&frame.arguments));
} }
bool ok = mScriptInvoke(cb, &frame); bool ok = mScriptContextInvoke(adapter->context, cb, &frame);
if (ok && out && mScriptListSize(&frame.returnValues) == 1) { if (ok && out && mScriptListSize(&frame.returnValues) == 1) {
if (!mScriptCast(mSCRIPT_TYPE_MS_F32, mScriptListGetPointer(&frame.returnValues, 0), out)) { if (!mScriptCast(mSCRIPT_TYPE_MS_F32, mScriptListGetPointer(&frame.returnValues, 0), out)) {
ok = false; ok = false;
@ -1154,7 +1154,7 @@ static uint8_t _readLuminance(struct GBALuminanceSource* luminance) {
if (adapter->luminanceCb) { if (adapter->luminanceCb) {
struct mScriptFrame frame; struct mScriptFrame frame;
mScriptFrameInit(&frame); mScriptFrameInit(&frame);
bool ok = mScriptInvoke(adapter->luminanceCb, &frame); bool ok = mScriptContextInvoke(adapter->context, adapter->luminanceCb, &frame);
struct mScriptValue out = {0}; struct mScriptValue out = {0};
if (ok && mScriptListSize(&frame.returnValues) == 1) { if (ok && mScriptListSize(&frame.returnValues) == 1) {
if (!mScriptCast(mSCRIPT_TYPE_MS_U8, mScriptListGetPointer(&frame.returnValues, 0), &out)) { if (!mScriptCast(mSCRIPT_TYPE_MS_U8, mScriptListGetPointer(&frame.returnValues, 0), &out)) {

View File

@ -7,6 +7,27 @@
#ifdef USE_LUA #ifdef USE_LUA
#include <mgba/internal/script/lua.h> #include <mgba/internal/script/lua.h>
#endif #endif
#include <mgba-util/threading.h>
static ThreadLocal _threadContext;
#ifdef USE_PTHREADS
static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT;
static void _createTLS(void) {
ThreadLocalInitKey(&_threadContext);
}
#elif _WIN32
static INIT_ONCE _contextOnce = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) {
UNUSED(once);
UNUSED(param);
UNUSED(context);
ThreadLocalInitKey(&_threadContext);
return TRUE;
}
#endif
#define KEY_NAME_MAX 128 #define KEY_NAME_MAX 128
@ -74,6 +95,11 @@ static void _freeTable(void* data) {
} }
void mScriptContextInit(struct mScriptContext* context) { void mScriptContextInit(struct mScriptContext* context) {
#ifdef USE_PTHREADS
pthread_once(&_contextOnce, _createTLS);
#elif _WIN32
InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0);
#endif
HashTableInit(&context->rootScope, 0, (void (*)(void*)) mScriptValueDeref); HashTableInit(&context->rootScope, 0, (void (*)(void*)) mScriptValueDeref);
HashTableInit(&context->engines, 0, _engineContextDestroy); HashTableInit(&context->engines, 0, _engineContextDestroy);
mScriptListInit(&context->refPool, 0); mScriptListInit(&context->refPool, 0);
@ -84,6 +110,7 @@ void mScriptContextInit(struct mScriptContext* context) {
context->nextCallbackId = 1; context->nextCallbackId = 1;
context->constants = NULL; context->constants = NULL;
HashTableInit(&context->docstrings, 0, NULL); HashTableInit(&context->docstrings, 0, NULL);
context->threadDepth = 0;
} }
void mScriptContextDeinit(struct mScriptContext* context) { void mScriptContextDeinit(struct mScriptContext* context) {
@ -241,7 +268,7 @@ void mScriptContextTriggerCallback(struct mScriptContext* context, const char* c
if (args) { if (args) {
mScriptListCopy(&frame.arguments, args); mScriptListCopy(&frame.arguments, args);
} }
mScriptInvoke(fn, &frame); mScriptContextInvoke(context, fn, &frame);
mScriptFrameDeinit(&frame); mScriptFrameDeinit(&frame);
} }
@ -407,6 +434,48 @@ bool mScriptContextLoadFile(struct mScriptContext* context, const char* path) {
return ret; return ret;
} }
struct mScriptContext* mScriptActiveContext(void) {
return ThreadLocalGetValue(_threadContext);
}
bool mScriptContextActivate(struct mScriptContext* context) {
struct mScriptContext* threadContext = ThreadLocalGetValue(_threadContext);
if (threadContext && threadContext != context) {
return false;
}
if (!threadContext && context->threadDepth) {
return false;
}
++context->threadDepth;
if (!threadContext) {
ThreadLocalSetKey(_threadContext, context);
}
return true;
}
void mScriptContextDeactivate(struct mScriptContext* context) {
#ifndef NDEBUG
struct mScriptContext* threadContext = ThreadLocalGetValue(_threadContext);
if (threadContext != context) {
abort();
}
#endif
--context->threadDepth;
if (!context->threadDepth) {
ThreadLocalSetKey(_threadContext, NULL);
}
}
bool mScriptContextInvoke(struct mScriptContext* context, const struct mScriptValue* fn, struct mScriptFrame* frame) {
if (!mScriptContextActivate(context)) {
return false;
}
bool res = mScriptInvoke(fn, frame);
mScriptContextDeactivate(context);
return res;
}
bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) { bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) {
if (val->type->base != mSCRIPT_TYPE_FUNCTION) { if (val->type->base != mSCRIPT_TYPE_FUNCTION) {
return false; return false;

View File

@ -1098,7 +1098,12 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame*
luaContext->lastError = NULL; luaContext->lastError = NULL;
} }
if (!mScriptContextActivate(luaContext->d.context)) {
return false;
}
if (frame && !_luaPushFrame(luaContext, &frame->arguments)) { if (frame && !_luaPushFrame(luaContext, &frame->arguments)) {
mScriptContextDeactivate(luaContext->d.context);
return false; return false;
} }
@ -1114,6 +1119,7 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame*
luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1)); luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1));
lua_pop(luaContext->lua, 1); lua_pop(luaContext->lua, 1);
} }
mScriptContextDeactivate(luaContext->d.context);
if (ret) { if (ret) {
return false; return false;
} }
@ -1172,7 +1178,7 @@ int _luaThunk(lua_State* lua) {
struct mScriptValue* fn = lua_touserdata(lua, lua_upvalueindex(1)); struct mScriptValue* fn = lua_touserdata(lua, lua_upvalueindex(1));
_autofreeFrame(luaContext->d.context, &frame.arguments); _autofreeFrame(luaContext->d.context, &frame.arguments);
if (!fn || !mScriptInvoke(fn, &frame)) { if (!fn || !mScriptContextInvoke(luaContext->d.context, fn, &frame)) {
mScriptContextDrainPool(luaContext->d.context); mScriptContextDrainPool(luaContext->d.context);
mScriptFrameDeinit(&frame); mScriptFrameDeinit(&frame);
luaL_traceback(lua, lua, "Error calling function (invoking failed)", 1); luaL_traceback(lua, lua, "Error calling function (invoking failed)", 1);