Skip to content

Commit 99ad4fa

Browse files
committed
Throw exceptions for Resets and Exits instead of directly raising.
While this does close small memory leaks, this is mostly for threading reasons. We're not supposed to call rb_raise with the gvl released, and calling rb_raise prevents GFX_UNLOCK from being called, which would cause problems for any games that want to call graphical operations in multiple threads should the user reset. We're also now calling Graphics.__reset__ and Audio.__reset__ via eval instead of directly calling the functions, in case a game wants to hook them.
1 parent 2622a84 commit 99ad4fa

10 files changed

+172
-86
lines changed

binding/binding-mri.cpp

+31-14
Original file line numberDiff line numberDiff line change
@@ -315,21 +315,29 @@ static void printP(int argc, VALUE *argv, const char *convMethod,
315315
}
316316

317317

318-
RB_METHOD(mriPrint) {
318+
RB_METHOD_GUARD(mriPrint) {
319319
RB_UNUSED_PARAM;
320320

321321
printP(argc, argv, "to_s", "");
322322

323+
shState->checkShutdown();
324+
shState->checkReset();
325+
323326
return Qnil;
324327
}
328+
RB_METHOD_GUARD_END
325329

326-
RB_METHOD(mriP) {
330+
RB_METHOD_GUARD(mriP) {
327331
RB_UNUSED_PARAM;
328332

329333
printP(argc, argv, "inspect", "\n");
330334

335+
shState->checkShutdown();
336+
shState->checkReset();
337+
331338
return Qnil;
332339
}
340+
RB_METHOD_GUARD_END
333341

334342
RB_METHOD(mkxpDelta) {
335343
RB_UNUSED_PARAM;
@@ -757,15 +765,21 @@ static VALUE rgssMainRescue(VALUE arg, VALUE exc) {
757765
return Qnil;
758766
}
759767

760-
static void processReset() {
761-
shState->graphics().reset();
762-
shState->audio().reset();
763-
764-
shState->rtData().rqReset.clear();
765-
shState->graphics().repaintWait(shState->rtData().rqResetFinish, false);
768+
static bool processReset(bool rubyExc) {
769+
const char *str = "Audio.__reset__; Graphics.__reset__;";
770+
771+
if (rubyExc) {
772+
rb_eval_string(str);
773+
} else {
774+
int state;
775+
rb_eval_string_protect(str, &state);
776+
return state;
777+
}
778+
779+
return 0;
766780
}
767781

768-
RB_METHOD(mriRgssMain) {
782+
RB_METHOD_GUARD(mriRgssMain) {
769783
RB_UNUSED_PARAM;
770784

771785
while (true) {
@@ -783,22 +797,24 @@ RB_METHOD(mriRgssMain) {
783797
break;
784798

785799
if (rb_obj_class(exc) == getRbData()->exc[Reset])
786-
processReset();
800+
processReset(true);
787801
else
788802
rb_exc_raise(exc);
789803
}
790804

791805
return Qnil;
792806
}
807+
RB_METHOD_GUARD_END
793808

794-
RB_METHOD(mriRgssStop) {
809+
RB_METHOD_GUARD(mriRgssStop) {
795810
RB_UNUSED_PARAM;
796811

797812
while (true)
798813
shState->graphics().update();
799814

800815
return Qnil;
801816
}
817+
RB_METHOD_GUARD_END
802818

803819
RB_METHOD(_kernelCaller) {
804820
RB_UNUSED_PARAM;
@@ -1038,7 +1054,8 @@ static void runRMXPScripts(BacktraceData &btData) {
10381054
if (rb_obj_class(exc) != getRbData()->exc[Reset])
10391055
break;
10401056

1041-
processReset();
1057+
if (processReset(false))
1058+
break;
10421059
}
10431060
}
10441061

@@ -1247,6 +1264,6 @@ static void mriBindingExecute() {
12471264
shState->rtData().rqTermAck.set();
12481265
}
12491266

1250-
static void mriBindingTerminate() { rb_raise(rb_eSystemExit, " "); }
1267+
static void mriBindingTerminate() { throw Exception(Exception::SystemExit, " "); }
12511268

1252-
static void mriBindingReset() { rb_raise(getRbData()->exc[Reset], " "); }
1269+
static void mriBindingReset() { throw Exception(Exception::Reset, " "); }

binding/binding-util.cpp

+39-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ RbData::~RbData() {}
5858

5959
/* Indexed with Exception::Type */
6060
const RbException excToRbExc[] = {
61-
RGSS, /* RGSSError */
62-
ErrnoENOENT, /* NoFileError */
61+
RGSS, /* RGSSError */
62+
Reset, /* Reset/RGSSReset */
63+
ErrnoENOENT, /* NoFileError */
6364
IOError,
6465

6566
TypeError, ArgumentError, SystemExit, RuntimeError,
@@ -317,3 +318,39 @@ int rb_get_args(int argc, VALUE *argv, const char *format, ...) {
317318

318319
return 0;
319320
}
321+
322+
#if RAPI_MAJOR >= 2
323+
#include <ruby/thread.h>
324+
325+
typedef struct gvl_guard_args {
326+
Exception *exc;
327+
void *(*func)(void *);
328+
void *args;
329+
} gvl_guard_args;
330+
331+
static void *gvl_guard(void *args) {
332+
gvl_guard_args *gvl_args = (gvl_guard_args*)args;
333+
try{
334+
return gvl_args->func(gvl_args->args);
335+
} catch (const Exception &e) {
336+
gvl_args->exc = new Exception(e.type, e.msg);
337+
}
338+
return 0;
339+
}
340+
341+
void *drop_gvl_guard(void *(*func)(void *), void *args,
342+
rb_unblock_function_t *ubf, void *data2) {
343+
gvl_guard_args gvl_args = {0, func, args};
344+
345+
void *ret = rb_thread_call_without_gvl(&gvl_guard, &gvl_args, ubf, data2);
346+
347+
Exception *&exc = gvl_args.exc;
348+
if (exc){
349+
Exception e(exc->type, exc->msg);
350+
delete exc;
351+
throw e;
352+
}
353+
return ret;
354+
}
355+
356+
#endif

binding/binding-util.h

+5-9
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ struct Exception;
7878
VALUE excToRbClass(const Exception &exc);
7979
void raiseRbExc(Exception exc);
8080

81+
#if RAPI_MAJOR >= 2
82+
void *drop_gvl_guard(void *(*func)(void *), void *args,
83+
rb_unblock_function_t *ubf, void *data2);
84+
#endif
85+
8186
#if RAPI_FULL > 187
8287
#define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type
8388

@@ -309,15 +314,6 @@ static inline void _rb_define_module_function(VALUE module, const char *name,
309314
rb_define_module_function(module, name, RUBY_METHOD_FUNC(func), -1);
310315
}
311316

312-
#define GUARD_EXC(exp) \
313-
{ \
314-
try { \
315-
exp \
316-
} catch (const Exception &exc) { \
317-
raiseRbExc(exc); \
318-
} \
319-
}
320-
321317
#define GFX_GUARD_EXC(exp) \
322318
{ \
323319
GFX_LOCK; \

0 commit comments

Comments
 (0)