Compiled code now executes in it's own thread.

This commit is contained in:
Scott Duensing 2023-05-10 18:08:56 -05:00
parent 721b23d584
commit b4d06317ab
2 changed files with 78 additions and 27 deletions

View file

@ -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;

View file

@ -42,6 +42,8 @@ char **___recipeTargets = NULL;
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;
}