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_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;
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue