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_NO_ENTRYPOINT,
COMPILER_ERROR_SIGHANDLER_FAILED, COMPILER_ERROR_SIGHANDLER_FAILED,
COMPILER_ERROR_SEGFAULT, COMPILER_ERROR_SEGFAULT,
COMPILER_ERROR_NO_THREAD,
COMPILER_ERROR_COUNT COMPILER_ERROR_COUNT
}; };
@ -59,10 +60,17 @@ typedef void (*CompilerCallback)(struct CompilerContextS **context);
typedef struct CompilerContextS { typedef struct CompilerContextS {
TCCState *s; TCCState *s;
pthread_t thread;
gboolean isRunning;
int compilerResult; int compilerResult;
int programResult; int programResult;
CompilerCallback callback; CompilerCallback callback;
void *userData; void *userData;
char *script;
int (*RecipeEntryPoint)(char *, char *);
char *arg1;
char *arg2;
char *oldPath;
#if HAVE_SIGSEGV_RECOVERY #if HAVE_SIGSEGV_RECOVERY
volatile int runPass; volatile int runPass;
jmp_buf runJump; jmp_buf runJump;

View file

@ -41,7 +41,9 @@ static CompilerContextT *_currentRunningContext = NULL; // Right now we can onl
char **___recipeTargets = NULL; 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. // Exposed to dynamic code. Not static.
void recipeAddTarget(char *target); void recipeAddTarget(char *target);
@ -98,6 +100,7 @@ CompilerContextT *compilerNewContext(CompilerCallback callback, void *userData)
c = NEW(CompilerContextT); c = NEW(CompilerContextT);
c->isRunning = FALSE;
c->compilerResult = COMPILER_ERROR_NONE; c->compilerResult = COMPILER_ERROR_NONE;
c->programResult = 0; c->programResult = 0;
c->callback = callback; c->callback = callback;
@ -130,15 +133,12 @@ CompilerContextT *compilerNewContext(CompilerCallback callback, void *userData)
void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, char *outputPath) { void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, char *outputPath) {
char *oldLocation;
int (*entry)(char *, char *); int err;
void *self; pthread_attr_t attr;
// All the paths passed in here are expected to be complete and absolute. // 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) { if (_currentRunningContext != NULL) {
context->compilerResult = COMPILER_ERROR_ALREADY_RUNNING; context->compilerResult = COMPILER_ERROR_ALREADY_RUNNING;
context->callback(&context); context->callback(&context);
@ -166,19 +166,73 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha
return; return;
} }
entry = tcc_get_symbol(context->s, "recipe"); context->RecipeEntryPoint = tcc_get_symbol(context->s, "recipe");
if (!entry) { if (!context->RecipeEntryPoint) {
// Something bad happened. // Something bad happened.
context->compilerResult = COMPILER_ERROR_NO_ENTRYPOINT; context->compilerResult = COMPILER_ERROR_NO_ENTRYPOINT;
context->callback(&context); context->callback(&context);
return; return;
} }
context->script = recipe;
context->arg1 = input;
context->arg2 = outputPath;
getcwd(__utilFilenameBuffer, FILENAME_MAX); getcwd(__utilFilenameBuffer, FILENAME_MAX);
oldLocation = strdup(__utilFilenameBuffer); context->oldPath = strdup(__utilFilenameBuffer);
chdir(outputPath); chdir(outputPath);
_currentRunningContext = context; _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 #if HAVE_SIGSEGV_RECOVERY
sigset_t emptySet; sigset_t emptySet;
@ -188,7 +242,7 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha
if (sigsegv_install_handler(&sigHandler) < 0) { if (sigsegv_install_handler(&sigHandler) < 0) {
context->compilerResult = COMPILER_ERROR_SIGHANDLER_FAILED; context->compilerResult = COMPILER_ERROR_SIGHANDLER_FAILED;
context->callback(&context); context->callback(&context);
return; return NULL;
} }
sigemptyset(&emptySet); sigemptyset(&emptySet);
@ -196,38 +250,27 @@ void compilerRunRecipe(CompilerContextT *context, char *recipe, char *input, cha
switch (setjmp(context->runJump)) { switch (setjmp(context->runJump)) {
case 0: case 0:
context->programResult = entry(input, outputPath); context->programResult = context->RecipeEntryPoint(context->arg1, context->arg2);
case 1: case 1:
sigprocmask(SIG_SETMASK, &context->runSigSet, NULL); sigprocmask(SIG_SETMASK, &context->runSigSet, NULL);
sigsegv_install_handler(NULL); sigsegv_install_handler(NULL);
if (context->runPass != 0) { 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; context->compilerResult = COMPILER_ERROR_SEGFAULT;
} }
break; break;
} }
context->callback(&context);
#else #else
context->programResult = entry(input, outputPath); context->programResult = context->EntryPoint(context->arg1, context->arg2);
context->callback(&context);
#endif #endif
context->isRunning = FALSE;
_currentRunningContext = NULL; _currentRunningContext = NULL;
chdir(oldLocation); return NULL;
DEL(oldLocation);
while (arrlen(___recipeTargets) > 0) {
if (projectAddToTree(self, ___recipeTargets[0])) {
utilSetDirty((WindowDataT *)context, TRUE);
}
DEL(___recipeTargets[0]);
arrdel(___recipeTargets, 0);
}
ARRFREE(___recipeTargets);
} }