Compiled code now executes in it's own thread.
This commit is contained in:
parent
721b23d584
commit
b4d06317ab
2 changed files with 78 additions and 27 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue