[async] shenanigans to run the backend in another thread

This commit is contained in:
Milo Turner 2020-02-19 20:55:14 -05:00
parent bb8eda00e4
commit fbe01e351b
5 changed files with 124 additions and 28 deletions

View File

@ -10,6 +10,7 @@ struct ax_backend;
struct ax_theme;
extern const char* ax__backend_impl_name;
extern size_t ax__backend_desired_region_size;
int ax__backend_new(
struct rgn* init_rgn,

View File

@ -12,6 +12,7 @@
* -------------------------------------------------------------------------- */
const char* ax__backend_impl_name = "SDL";
size_t ax__backend_desired_region_size = SMALL;
struct ax_backend {
struct msgq* mq;
@ -48,6 +49,7 @@ int ax__backend_new(
if (out_bac != NULL) {
*out_bac = bac;
}
printf("hello from SDL\n");
return 0;
fail:
@ -61,6 +63,7 @@ static void backend_cleanup(struct ax_backend* bac)
{
TTF_Quit();
SDL_Quit();
printf("bye from SDL\n");
}
struct msgq* ax__backend_msgq(struct ax_backend* bac)

View File

@ -1,8 +1,9 @@
#pragma once
#include "util/region.h"
#include <stdbool.h>
#include <stdio.h>
#include "util/region.h"
#include <pthread.h>
struct ax_theme;
struct ax_theme_builder;
@ -20,6 +21,7 @@ struct ax_ctxt {
const char* err;
// backend
pthread_t bac_thid;
struct ax_backend* bac;
// theme

View File

@ -1,5 +1,7 @@
#include "../ax.h"
#include "../backend.h"
#include "../concurrent/msg.h"
#include "../concurrent/msgq.h"
#include "../ctxt.h"
#include "../util.h"
#include "theme.h"
@ -37,8 +39,15 @@ const char* ax_get_error(struct ax_ctxt* ax)
* Internal 'ax_ctxt' operations
* -------------------------------------------------------------------------- */
static void spawn_backend(
struct rgn* init_rgn,
pthread_t* out_thid,
struct ax_backend** out_backend);
void ax__ctxt_init(struct ax_ctxt* ax, struct rgn* init_rgn)
{
/* init simple stuff */
ax->init_rgn = init_rgn;
ax->log_out = NULL;
@ -51,16 +60,20 @@ void ax__ctxt_init(struct ax_ctxt* ax, struct rgn* init_rgn)
ax->thmb = NULL;
ax->sel_theme = NULL;
const char* err;
if (ax__backend_new(init_rgn, &ax->bac, &err) != 0) {
ASSERT(0, "initializing %s backend failed: %s",
ax__backend_impl_name,
err);
}
ax->bac = NULL;
spawn_backend(init_rgn, &ax->bac_thid, &ax->bac);
ASSERT(ax->bac != NULL, "backend wasn't initialized");
}
void ax__ctxt_cleanup(struct ax_ctxt* ax)
{
struct msgq* bac_mq = ax__backend_msgq(ax->bac);
msgq_begin_send_typed(bac_mq, ax_msg_shutdown);
msgq_end_send(bac_mq);
ax_log(ax, "waiting for backend shutdown.");
pthread_join(ax->bac_thid, NULL);
ax_log(ax, "backend shutdown");
rgn_cleanup(&ax->thmb_rgn);
rgn_cleanup(&ax->err_rgn);
}
@ -153,3 +166,86 @@ int ax_select_theme(struct ax_ctxt* ax, struct ax_theme* thm)
ax_log(ax, "theme selected");
return 0;
}
/* -----------------------------------------------------------------------------
* Backend worker thread
* -------------------------------------------------------------------------- */
struct backend_init_ctxt {
// "input"
struct rgn* rgn;
pthread_mutex_t mx;
pthread_cond_t cv;
// "output"
struct ax_backend* backend;
const char* err;
};
static void* backend_worker(void* arg);
static void spawn_backend(
struct rgn* init_rgn,
pthread_t* out_thid,
struct ax_backend** out_backend)
{
pthread_t thid;
struct backend_init_ctxt init = {
.rgn = init_rgn,
.err = NULL,
};
pthread_mutex_init(&init.mx, NULL);
pthread_cond_init(&init.cv, NULL);
pthread_mutex_lock(&init.mx);
pthread_create(&thid, NULL, backend_worker, &init);
pthread_cond_wait(&init.cv, &init.mx);
pthread_mutex_unlock(&init.mx);
pthread_cond_destroy(&init.cv);
pthread_mutex_destroy(&init.mx);
if (init.err != NULL) {
ASSERT(0, "failed to initialize `%s' backend: %s",
ax__backend_impl_name, init.err);
}
if (out_thid != NULL) {
*out_thid = thid;
}
if (out_backend != NULL) {
*out_backend = init.backend;
}
}
static void* backend_worker(void* arg)
{
struct backend_init_ctxt* init = arg;
struct rgn* bac_rgn = ralloc_typed(init->rgn, struct rgn, 1);
rgn_init(bac_rgn, ax__backend_desired_region_size);
struct ax_backend* bac;
const char* err = NULL;
int rv = ax__backend_new(bac_rgn, &bac, &err);
pthread_mutex_lock(&init->mx);
init->backend = bac;
if (rv != 0) {
init->err = rstrdup(init->rgn, err);
}
pthread_cond_signal(&init->cv);
pthread_mutex_unlock(&init->mx);
if (rv != 0) {
goto cleanup;
}
// `bac` is succesfully initialized here!
while (!ax__backend_is_shutdown(bac)) {
ax__backend_wait_for_event(bac);
ax__backend_step(bac);
}
cleanup:
rgn_cleanup(bac_rgn);
return NULL;
}

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include "../src/ax.h"
#include "../src/ctxt.h"
#include "../src/backend.h"
@ -20,6 +21,17 @@ static void sigint_handler(int signum)
exit(0);
}
static struct ax_theme* make_example_theme()
{
ax_begin_theme(ax);
ax_set_theme_color(ax, "primary", 0x00ff00);
ax_set_theme_font(ax, "default", "/usr/share/fonts/TTF/DejaVuSans.ttf", 0);
ax_set_theme_font(ax, "h1", NULL, 95);
struct ax_theme* thm;
ax_end_theme(ax, &thm);
return thm;
}
int main(void)
{
signal(SIGINT, sigint_handler);
@ -27,28 +39,10 @@ int main(void)
ax = ax_new();
ax_set_logger(ax, 0, false);
int rv = 0;
#define GUARD(f, ...) if ((rv = f(__VA_ARGS__)) != 0) goto cleanup
(void) make_example_theme();
ax_begin_theme(ax);
ax_set_theme_color(ax, "primary", 0x00ff00);
ax_set_theme_font(ax, "default", "/usr/share/fonts/TTF/DejaVuSans.ttf", 0);
ax_set_theme_font(ax, "h1", NULL, 95);
usleep(5 * 1000 * 1000);
struct ax_theme* thm;
ax_end_theme(ax, &thm);
ax_log(ax, "Got here\n");
while (!ax__backend_is_shutdown(ax->bac)) {
ax__backend_wait_for_event(ax->bac);
ax__backend_step(ax->bac);
}
//cleanup:
if (rv != 0) {
printf("error: %s\n", ax_get_error(ax));
}
cleanup();
return rv;
return 0;
}