mirror of https://github.com/mgba-emu/mgba.git
Script: Add mScriptContextInvoke for context-specific invocation and thread handling
This commit is contained in:
parent
5534d23690
commit
09b7eea127
|
@ -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
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue