From c17f5a5377f959a7e67526e0ae89b329bf99a101 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Wed, 16 Jan 2019 07:15:26 -0500 Subject: solve in background thread --- src/sdl/solve.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 src/sdl/solve.c (limited to 'src/sdl/solve.c') diff --git a/src/sdl/solve.c b/src/sdl/solve.c new file mode 100644 index 0000000..0fee274 --- /dev/null +++ b/src/sdl/solve.c @@ -0,0 +1,218 @@ +#include // bool +#include // errno +#include // strerror() +#include +#include "util.h" +#include "solve.h" + +struct solve_t_ { + SDL_mutex *mutex; + + // thread-private copy of context + sok_ctx_t ctx; + + Uint32 solve_event_type; + + // number of moves at call to solve() + size_t old_num_moves; + + // number of times the on_step cb has been invoked + size_t num_steps; + + // result of solve + bool result; + + // cancel solve + bool cancel; +}; + +static void +push_event( + solve_t * const data, + const solve_event_type_t type, + void *user_data +) { + // alloc/clear event + SDL_Event ev; + memset(&ev, 0, sizeof(SDL_Event)); + + // init event + ev.type = data->solve_event_type; + ev.user.code = (Sint32) type; + ev.user.data1 = data; + ev.user.data2 = user_data; + + // push event + if (!SDL_PushEvent(&ev)) { + die("SDL_PushEvent(): %s", SDL_GetError()); + } +} + +static bool +solve_on_step( + const sok_ctx_t * const ctx, + void *user_data +) { + solve_t *data = user_data; + UNUSED(ctx); + + // lock mutex + if (SDL_LockMutex(data->mutex)) { + die("SDL_LockMutex(): %s", SDL_GetError()); + } + + // increment number of steps + data->num_steps++; + + // cache number of steps and cancel state + const size_t num_steps = data->num_steps; + const bool cancel = data->cancel; + + // unlock mutex + if (SDL_UnlockMutex(data->mutex)) { + die("SDL_UnlockMutex(): %s", SDL_GetError()); + } + + if ((num_steps % 100) == 0) { + // push event + push_event(data, SOLVE_EVENT_STEP, NULL); + } + + // return false if cancelled + return !cancel; +} + +static void +solve_on_error( + const char * const err, + void *user_data +) { + solve_t *data = user_data; + UNUSED(user_data); + // die("Error solving level: %s", err); + push_event(data, SOLVE_EVENT_FAIL, (void*) err); +} + +static const sok_solve_cbs_t +SOLVE_CBS = { + .on_step = solve_on_step, + .on_error = solve_on_error, +}; + +static int +solve_thread( + void * const thread_data +) { + solve_t *data = thread_data; + warn("solve started"); + + // solve board + data->result = sok_solve(&(data->ctx), &SOLVE_CBS, data); + if (data->result) { + // push success + push_event(data, SOLVE_EVENT_DONE, NULL); + } + warn("solve done"); + + return 0; +} + +solve_t * +solve( + const sok_ctx_t * const ctx, + const Uint32 solve_event_type +) { + // create thread mutex + SDL_mutex *mutex = SDL_CreateMutex(); + if (!mutex) { + die("SDL_CreateMutex(): %s", SDL_GetError()); + } + + // alloc solve thread data + solve_t *data = malloc(sizeof(solve_t)); + if (!data) { + die("malloc(): %s", strerror(errno)); + } + + // init solve data + data->mutex = mutex; + data->ctx = *ctx; + data->solve_event_type = solve_event_type; + data->old_num_moves = ctx->num_moves; + data->num_steps = 0; + data->result = false; + data->cancel = false; + + // create solve thread + SDL_Thread *thread = SDL_CreateThread(solve_thread, "solve", data); + if (!thread) { + die("SDL_CreateThread(): %s", SDL_GetError()); + } + + // detach thread + SDL_DetachThread(thread); + + SDL_Log("Solving (thread ID = %lu, address = %p)", SDL_GetThreadID(thread), thread); + + // return thread data + return data; +} + +void +solve_fini( + solve_t * const data, + void (*on_done)(const bool, const sok_ctx_t *, const size_t, void *), + void *user_data +) { + if (on_done) { + // call handler + on_done(data->result, &(data->ctx), data->num_steps, user_data); + } + + // free mutex + SDL_DestroyMutex(data->mutex); + data->mutex = NULL; + + // free thread data + free(data); +} + +void +solve_cancel(solve_t * const data) { + // lock mutex + if (SDL_LockMutex(data->mutex)) { + die("SDL_LockMutex(): %s", SDL_GetError()); + } + + // set cancel + data->cancel = true; + + // lock mutex + if (SDL_UnlockMutex(data->mutex)) { + die("SDL_UnlockMutex(): %s", SDL_GetError()); + } +} + +size_t +solve_get_num_steps(solve_t * const data) { + // lock mutex + if (SDL_LockMutex(data->mutex)) { + die("SDL_LockMutex(): %s", SDL_GetError()); + } + + // get num steps + const size_t num_steps = data->num_steps; + + // lock mutex + if (SDL_UnlockMutex(data->mutex)) { + die("SDL_UnlockMutex(): %s", SDL_GetError()); + } + + // return num_steps + return num_steps; +} + +bool +solve_get_result(solve_t * const data) { + return data->result; +} -- cgit v1.2.3