diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index f6da12cf..39d62d21 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -315,21 +315,29 @@ static void printP(int argc, VALUE *argv, const char *convMethod, } -RB_METHOD(mriPrint) { +RB_METHOD_GUARD(mriPrint) { RB_UNUSED_PARAM; printP(argc, argv, "to_s", ""); + shState->checkShutdown(); + shState->checkReset(); + return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mriP) { +RB_METHOD_GUARD(mriP) { RB_UNUSED_PARAM; printP(argc, argv, "inspect", "\n"); + shState->checkShutdown(); + shState->checkReset(); + return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(mkxpDelta) { RB_UNUSED_PARAM; @@ -757,15 +765,21 @@ static VALUE rgssMainRescue(VALUE arg, VALUE exc) { return Qnil; } -static void processReset() { - shState->graphics().reset(); - shState->audio().reset(); - - shState->rtData().rqReset.clear(); - shState->graphics().repaintWait(shState->rtData().rqResetFinish, false); +static bool processReset(bool rubyExc) { + const char *str = "Audio.__reset__; Graphics.__reset__;"; + + if (rubyExc) { + rb_eval_string(str); + } else { + int state; + rb_eval_string_protect(str, &state); + return state; + } + + return 0; } -RB_METHOD(mriRgssMain) { +RB_METHOD_GUARD(mriRgssMain) { RB_UNUSED_PARAM; while (true) { @@ -783,15 +797,16 @@ RB_METHOD(mriRgssMain) { break; if (rb_obj_class(exc) == getRbData()->exc[Reset]) - processReset(); + processReset(true); else rb_exc_raise(exc); } return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mriRgssStop) { +RB_METHOD_GUARD(mriRgssStop) { RB_UNUSED_PARAM; while (true) @@ -799,6 +814,7 @@ RB_METHOD(mriRgssStop) { return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(_kernelCaller) { RB_UNUSED_PARAM; @@ -1038,7 +1054,8 @@ static void runRMXPScripts(BacktraceData &btData) { if (rb_obj_class(exc) != getRbData()->exc[Reset]) break; - processReset(); + if (processReset(false)) + break; } } @@ -1247,6 +1264,6 @@ static void mriBindingExecute() { shState->rtData().rqTermAck.set(); } -static void mriBindingTerminate() { rb_raise(rb_eSystemExit, " "); } +static void mriBindingTerminate() { throw Exception(Exception::SystemExit, " "); } -static void mriBindingReset() { rb_raise(getRbData()->exc[Reset], " "); } +static void mriBindingReset() { throw Exception(Exception::Reset, " "); } diff --git a/binding/binding-util.cpp b/binding/binding-util.cpp index bd8cea84..7e5d1b73 100644 --- a/binding/binding-util.cpp +++ b/binding/binding-util.cpp @@ -58,8 +58,9 @@ RbData::~RbData() {} /* Indexed with Exception::Type */ const RbException excToRbExc[] = { - RGSS, /* RGSSError */ - ErrnoENOENT, /* NoFileError */ + RGSS, /* RGSSError */ + Reset, /* Reset/RGSSReset */ + ErrnoENOENT, /* NoFileError */ IOError, TypeError, ArgumentError, SystemExit, RuntimeError, @@ -317,3 +318,39 @@ int rb_get_args(int argc, VALUE *argv, const char *format, ...) { return 0; } + +#if RAPI_MAJOR >= 2 +#include + +typedef struct gvl_guard_args { + Exception *exc; + void *(*func)(void *); + void *args; +} gvl_guard_args; + +static void *gvl_guard(void *args) { + gvl_guard_args *gvl_args = (gvl_guard_args*)args; + try{ + return gvl_args->func(gvl_args->args); + } catch (const Exception &e) { + gvl_args->exc = new Exception(e.type, e.msg); + } + return 0; +} + +void *drop_gvl_guard(void *(*func)(void *), void *args, + rb_unblock_function_t *ubf, void *data2) { + gvl_guard_args gvl_args = {0, func, args}; + + void *ret = rb_thread_call_without_gvl(&gvl_guard, &gvl_args, ubf, data2); + + Exception *&exc = gvl_args.exc; + if (exc){ + Exception e(exc->type, exc->msg); + delete exc; + throw e; + } + return ret; +} + +#endif diff --git a/binding/binding-util.h b/binding/binding-util.h index 8fdacfb6..53a2ad72 100644 --- a/binding/binding-util.h +++ b/binding/binding-util.h @@ -78,6 +78,11 @@ struct Exception; VALUE excToRbClass(const Exception &exc); void raiseRbExc(Exception exc); +#if RAPI_MAJOR >= 2 +void *drop_gvl_guard(void *(*func)(void *), void *args, + rb_unblock_function_t *ubf, void *data2); +#endif + #if RAPI_FULL > 187 #define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type @@ -309,15 +314,6 @@ static inline void _rb_define_module_function(VALUE module, const char *name, rb_define_module_function(module, name, RUBY_METHOD_FUNC(func), -1); } -#define GUARD_EXC(exp) \ -{ \ -try { \ -exp \ -} catch (const Exception &exc) { \ -raiseRbExc(exc); \ -} \ -} - #define GFX_GUARD_EXC(exp) \ { \ GFX_LOCK; \ diff --git a/binding/graphics-binding.cpp b/binding/graphics-binding.cpp index fb0aa082..894163b6 100644 --- a/binding/graphics-binding.cpp +++ b/binding/graphics-binding.cpp @@ -26,10 +26,6 @@ #include "binding-types.h" #include "exception.h" -#if RAPI_MAJOR >= 2 -#include -#endif - RB_METHOD(graphicsDelta) { RB_UNUSED_PARAM; GFX_LOCK; @@ -38,14 +34,12 @@ RB_METHOD(graphicsDelta) { return ret; } -RB_METHOD(graphicsUpdate) +RB_METHOD_GUARD(graphicsUpdate) { RB_UNUSED_PARAM; #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void*) -> void* { - GFX_LOCK; - shState->graphics().update(); - GFX_UNLOCK; + drop_gvl_guard([](void*) -> void* { + GFX_GUARD_EXC( shState->graphics().update(); ); return 0; }, 0, 0, 0); #else @@ -53,6 +47,7 @@ RB_METHOD(graphicsUpdate) #endif return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsAverageFrameRate) { @@ -63,16 +58,28 @@ RB_METHOD(graphicsAverageFrameRate) return ret; } -RB_METHOD(graphicsFreeze) +RB_METHOD_GUARD(graphicsFreeze) { RB_UNUSED_PARAM; - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void*) -> void* { + GFX_GUARD_EXC( shState->graphics().freeze(); ); + return 0; + }, 0, 0, 0); +#else shState->graphics().freeze(); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END + +typedef struct { + int duration; + const char *filename; + int vague; +} TransitionArgs; RB_METHOD_GUARD(graphicsTransition) { @@ -84,7 +91,20 @@ RB_METHOD_GUARD(graphicsTransition) rb_get_args(argc, argv, "|izi", &duration, &filename, &vague RB_ARG_END); + TransitionArgs args = {duration, filename, vague}; + +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void *args) -> void* { + TransitionArgs &a = *((TransitionArgs*)args); + GFX_GUARD_EXC( shState->graphics().transition(a.duration, + a.filename, + a.vague + ); ); + return 0; + }, &args, 0, 0); +#else GFX_GUARD_EXC( shState->graphics().transition(duration, filename, vague); ) +#endif return Qnil; } @@ -180,17 +200,15 @@ RB_METHOD(graphicsDisplayHeight) return rb_fix_new(shState->graphics().displayHeight()); } -RB_METHOD(graphicsWait) +RB_METHOD_GUARD(graphicsWait) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void* d) -> void* { - GFX_LOCK; - shState->graphics().wait(*(int*)d); - GFX_UNLOCK; + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().wait(*(int*)d); ); return 0; }, (int*)&duration, 0, 0); #else @@ -198,34 +216,47 @@ RB_METHOD(graphicsWait) #endif return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(graphicsFadeout) +RB_METHOD_GUARD(graphicsFadeout) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().fadeout(*(int*)d); ); + return 0; + }, (int*)&duration, 0, 0); +#else shState->graphics().fadeout(duration); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(graphicsFadein) +RB_METHOD_GUARD(graphicsFadein) { RB_UNUSED_PARAM; int duration; rb_get_args(argc, argv, "i", &duration RB_ARG_END); - GFX_LOCK; +#if RAPI_MAJOR >= 2 + drop_gvl_guard([](void* d) -> void* { + GFX_GUARD_EXC( shState->graphics().fadein(*(int*)d); ); + return 0; + }, (int*)&duration, 0, 0); +#else shState->graphics().fadein(duration); - GFX_UNLOCK; +#endif return Qnil; } +RB_METHOD_GUARD_END void bitmapInitProps(Bitmap *b, VALUE self); @@ -274,16 +305,15 @@ RB_METHOD(graphicsResizeWindow) return Qnil; } -RB_METHOD(graphicsReset) +RB_METHOD_GUARD(graphicsReset) { RB_UNUSED_PARAM; - GFX_LOCK; - shState->graphics().reset(); - GFX_UNLOCK; + GFX_GUARD_EXC( shState->graphics().reset(); ); return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsCenter) { @@ -301,17 +331,17 @@ typedef struct { void *playMovieInternal(void *args) { PlayMovieArgs *a = (PlayMovieArgs*)args; - GFX_GUARD_EXC( - shState->graphics().playMovie(a->filename, a->volume, a->skippable); - - // Signals for shutdown or reset only make playMovie quit early, - // so check again - shState->graphics().update(); - ); + GFX_GUARD_EXC( shState->graphics().playMovie(a->filename, a->volume, a->skippable); ); + + // Signals for shutdown or reset only make playMovie quit early, + // so check again + shState->checkShutdown(); + shState->checkReset(); + return 0; } -RB_METHOD(graphicsPlayMovie) +RB_METHOD_GUARD(graphicsPlayMovie) { RB_UNUSED_PARAM; @@ -329,20 +359,21 @@ RB_METHOD(graphicsPlayMovie) args.volume = (volumeArg == Qnil) ? 100 : NUM2INT(volumeArg);; args.skippable = skip; #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl(playMovieInternal, &args, 0, 0); + drop_gvl_guard(playMovieInternal, &args, 0, 0); #else playMovieInternal(&args); #endif return Qnil; } +RB_METHOD_GUARD_END void graphicsScreenshotInternal(const char *filename) { GFX_GUARD_EXC(shState->graphics().screenshot(filename);); } -RB_METHOD(graphicsScreenshot) +RB_METHOD_GUARD(graphicsScreenshot) { RB_UNUSED_PARAM; @@ -351,7 +382,7 @@ RB_METHOD(graphicsScreenshot) SafeStringValue(filename); #if RAPI_MAJOR >= 2 - rb_thread_call_without_gvl([](void* fn) -> void* { + drop_gvl_guard([](void* fn) -> void* { graphicsScreenshotInternal((const char*)fn); return 0; }, (void*)RSTRING_PTR(filename), 0, 0); @@ -360,6 +391,7 @@ RB_METHOD(graphicsScreenshot) #endif return Qnil; } +RB_METHOD_GUARD_END DEF_GRA_PROP_I(FrameRate) DEF_GRA_PROP_I(FrameCount) diff --git a/binding/http-binding.cpp b/binding/http-binding.cpp index 40adfcf2..61678021 100644 --- a/binding/http-binding.cpp +++ b/binding/http-binding.cpp @@ -10,10 +10,6 @@ #include "util/json5pp.hpp" #include "binding-util.h" -#if RAPI_MAJOR >= 2 -#include -#endif - #include "net/net.h" VALUE stringMap2hash(mkxp_net::StringMap &map) { @@ -78,10 +74,8 @@ VALUE formResponse(mkxp_net::HTTPResponse &res) { void* httpGetInternal(void *req) { VALUE ret; - GUARD_EXC( - mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get(); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = ((mkxp_net::HTTPRequest*)req)->get(); + ret = formResponse(res); return (void*)ret; } @@ -102,7 +96,7 @@ RB_METHOD_GUARD(httpGet) { req.headers().insert(headers.begin(), headers.end()); } #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpGetInternal, &req, 0, 0); + return (VALUE)drop_gvl_guard(httpGetInternal, &req, 0, 0); #else return (VALUE)httpGetInternal(&req); #endif @@ -122,10 +116,8 @@ void* httpPostInternal(void *args) { mkxp_net::HTTPRequest *req = ((httpPostInternalArgs*)args)->req; mkxp_net::StringMap *postData = ((httpPostInternalArgs*)args)->postData; - GUARD_EXC( - mkxp_net::HTTPResponse res = req->post(*postData); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = req->post(*postData); + ret = formResponse(res); return (void*)ret; } @@ -149,7 +141,7 @@ RB_METHOD_GUARD(httpPost) { mkxp_net::StringMap postData = hash2StringMap(postDataHash); httpPostInternalArgs args {&req, &postData}; #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpPostInternal, &args, 0, 0); + return (VALUE)drop_gvl_guard(httpPostInternal, &args, 0, 0); #else return httpPostInternal(&args); #endif @@ -170,16 +162,14 @@ void* httpPostBodyInternal(void *args) { const char *reqbody = ((httpPostBodyInternalArgs*)args)->body; const char *reqctype = ((httpPostBodyInternalArgs*)args)->ctype; - GUARD_EXC( - mkxp_net::HTTPResponse res = req->post(reqbody, reqctype); - ret = formResponse(res); - ); + mkxp_net::HTTPResponse res = req->post(reqbody, reqctype); + ret = formResponse(res); return (void*)ret; } #endif -RB_METHOD(httpPostBody) { +RB_METHOD_GUARD(httpPostBody) { RB_UNUSED_PARAM; VALUE path, body, ctype, rheaders; @@ -197,11 +187,12 @@ RB_METHOD(httpPostBody) { httpPostBodyInternalArgs args {&req, RSTRING_PTR(body), RSTRING_PTR(ctype)}; #if RAPI_MAJOR >= 2 - return (VALUE)rb_thread_call_without_gvl(httpPostBodyInternal, &args, 0, 0); + return (VALUE)drop_gvl_guard(httpPostBodyInternal, &args, 0, 0); #else return httpPostBodyInternal(&args); #endif } +RB_METHOD_GUARD_END VALUE json2rb(json5pp::value const &v) { if (v.is_null()) diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index 0b89babc..3e20428b 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -37,13 +37,14 @@ RB_METHOD(inputDelta) { return rb_float_new(shState->input().getDelta()); } -RB_METHOD(inputUpdate) { +RB_METHOD_GUARD(inputUpdate) { RB_UNUSED_PARAM; shState->input().update(); return Qnil; } +RB_METHOD_GUARD_END static int getButtonArg(VALUE *argv) { int num; diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 102d1c35..b3598b10 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -1609,6 +1609,13 @@ void Graphics::reset() { setFrameRate(DEF_FRAMERATE); setBrightness(255); + + // Always update at least once to clear the screen + if (p->threadData->rqResetFinish) + update(); + else + repaintWait(p->threadData->rqResetFinish, false); + p->threadData->rqReset.clear(); } void Graphics::center() { diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 18dc1128..2bd3b808 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -800,7 +800,9 @@ void EventThread::showMessageBox(const char *body, int flags) SDL_PushEvent(&event); /* Keep repainting screen while box is open */ - shState->graphics().repaintWait(msgBoxDone); + try{ + shState->graphics().repaintWait(msgBoxDone); + }catch(...){} /* Prevent endless loops */ resetInputStates(); } diff --git a/src/eventthread.h b/src/eventthread.h index 6879af99..1d746bdb 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -286,7 +286,9 @@ struct RGSSThreadData scale(scalingFactor), config(newconf), glContext(ctx) - {} + { + rqResetFinish.set(); + } }; #endif // EVENTTHREAD_H diff --git a/src/util/exception.h b/src/util/exception.h index 45c28f8f..3f52fca7 100644 --- a/src/util/exception.h +++ b/src/util/exception.h @@ -31,6 +31,7 @@ struct Exception enum Type { RGSSError, + Reset, NoFileError, IOError,