From b4d06317ab92f1c82d1ca5ce7cecc191885ff1f2 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 10 May 2023 18:08:56 -0500 Subject: [PATCH] Compiled code now executes in it's own thread. --- include/compiler.h | 8 ++++ src/compiler.c | 97 +++++++++++++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/include/compiler.h b/include/compiler.h index be13bb0..715e071 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -47,6 +47,7 @@ enum CompilerErrorsE { COMPILER_ERROR_NO_ENTRYPOINT, COMPILER_ERROR_SIGHANDLER_FAILED, COMPILER_ERROR_SEGFAULT, + COMPILER_ERROR_NO_THREAD, COMPILER_ERROR_COUNT }; @@ -59,10 +60,17 @@ typedef void (*CompilerCallback)(struct CompilerContextS **context); typedef struct CompilerContextS { TCCState *s; + pthread_t thread; + gboolean isRunning; int compilerResult; int programResult; CompilerCallback callback; void *userData; + char *script; + int (*RecipeEntryPoint)(char *, char *); + char *arg1; + char *arg2; + char *oldPath; #if HAVE_SIGSEGV_RECOVERY volatile int runPass; jmp_buf runJump; diff --git a/src/compiler.c b/src/compiler.c index 7bdae7d..48be3c8 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -41,7 +41,9 @@ static CompilerContextT *_currentRunningContext = NULL; // Right now we can onl char **___recipeTargets = NULL; -static void compilerErrorHandler(void *opaque, const char *msg); +static void compilerErrorHandler(void *opaque, const char *msg); +static gboolean compilerRunRecipeFinished(gpointer userData); +static void *compilerRunRecipeThread(void *arg); // Exposed to dynamic code. Not static. void recipeAddTarget(char *target); @@ -98,6 +100,7 @@ CompilerContextT *compilerNewContext(CompilerCallback callback, void *userData) c = NEW(CompilerContextT); + c->isRunning = FALSE; c->compilerResult = COMPILER_ERROR_NONE; c->programResult = 0; c->callback = callback; @@ -130,15 +133,12 @@ CompilerContextT *compilerNewContext(CompilerCallback callback, void *userData) void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, char *outputPath) { - char *oldLocation; - int (*entry)(char *, char *); - void *self; + + int err; + pthread_attr_t attr; // All the paths passed in here are expected to be complete and absolute. - //***TODO*** Oh my god this is so bad. The next line depends on 'userData' being set to 'self' when called from project.c. - self = context->userData; - if (_currentRunningContext != NULL) { context->compilerResult = COMPILER_ERROR_ALREADY_RUNNING; context->callback(&context); @@ -166,19 +166,73 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha return; } - entry = tcc_get_symbol(context->s, "recipe"); - if (!entry) { + context->RecipeEntryPoint = tcc_get_symbol(context->s, "recipe"); + if (!context->RecipeEntryPoint) { // Something bad happened. context->compilerResult = COMPILER_ERROR_NO_ENTRYPOINT; context->callback(&context); return; } + context->script = recipe; + context->arg1 = input; + context->arg2 = outputPath; getcwd(__utilFilenameBuffer, FILENAME_MAX); - oldLocation = strdup(__utilFilenameBuffer); + context->oldPath = strdup(__utilFilenameBuffer); chdir(outputPath); _currentRunningContext = context; + context->isRunning = TRUE; + g_idle_add(compilerRunRecipeFinished, context); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + err = pthread_create(&context->thread, &attr, &compilerRunRecipeThread, context); + pthread_attr_destroy(&attr); + if (err != 0) { + context->compilerResult = COMPILER_ERROR_NO_THREAD; + context->callback(&context); + debug("Can't create thread: %s\n", strerror(err)); + return; + } +} + + +static gboolean compilerRunRecipeFinished(gpointer userData) { + CompilerContextT *ctx = (CompilerContextT *)userData; + void *self; + + //***TODO*** Oh my god this is so bad. The next line depends on 'userData' being set to 'self' when called from project.c. + self = ctx->userData; + + // Has the program finished running? + if (ctx->isRunning) { + // Keep waiting. + return G_SOURCE_CONTINUE; + } + + chdir(ctx->oldPath); + DEL(ctx->oldPath); + + while (arrlen(___recipeTargets) > 0) { + if (projectAddToTree(self, ___recipeTargets[0])) { + utilSetDirty((WindowDataT *)ctx, TRUE); + } + DEL(___recipeTargets[0]); + arrdel(___recipeTargets, 0); + } + ARRFREE(___recipeTargets); + + // Call finish callback. + ctx->callback(&ctx); + + // We're done. + return G_SOURCE_REMOVE; +} + + +static void *compilerRunRecipeThread(void *arg) { + CompilerContextT *context = (CompilerContextT *)arg; #if HAVE_SIGSEGV_RECOVERY sigset_t emptySet; @@ -188,7 +242,7 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha if (sigsegv_install_handler(&sigHandler) < 0) { context->compilerResult = COMPILER_ERROR_SIGHANDLER_FAILED; context->callback(&context); - return; + return NULL; } sigemptyset(&emptySet); @@ -196,38 +250,27 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha switch (setjmp(context->runJump)) { case 0: - context->programResult = entry(input, outputPath); + context->programResult = context->RecipeEntryPoint(context->arg1, context->arg2); case 1: sigprocmask(SIG_SETMASK, &context->runSigSet, NULL); sigsegv_install_handler(NULL); if (context->runPass != 0) { - message(MSG_SEVERE, "%s caused a segmentation fault!", recipe); + message(MSG_SEVERE, "%s caused a segmentation fault!", context->script); context->compilerResult = COMPILER_ERROR_SEGFAULT; } break; } - context->callback(&context); #else - context->programResult = entry(input, outputPath); - context->callback(&context); + context->programResult = context->EntryPoint(context->arg1, context->arg2); #endif + context->isRunning = FALSE; _currentRunningContext = NULL; - chdir(oldLocation); - DEL(oldLocation); - - while (arrlen(___recipeTargets) > 0) { - if (projectAddToTree(self, ___recipeTargets[0])) { - utilSetDirty((WindowDataT *)context, TRUE); - } - DEL(___recipeTargets[0]); - arrdel(___recipeTargets, 0); - } - ARRFREE(___recipeTargets); + return NULL; }