#include <cassert>
#include <err.h>
#include "benchmark_worker.hpp"
#include "os_thread.h"
static void
worker_state_wait_for_transition(struct benchmark_worker *worker,
enum benchmark_worker_state state,
enum benchmark_worker_state new_state)
{
while (worker->state == state)
os_cond_wait(&worker->cond, &worker->lock);
assert(worker->state == new_state);
}
static void
worker_state_transition(struct benchmark_worker *worker,
enum benchmark_worker_state old_state,
enum benchmark_worker_state new_state)
{
assert(worker->state == old_state);
worker->state = new_state;
os_cond_signal(&worker->cond);
}
static void *
thread_func(void *arg)
{
assert(arg != NULL);
struct benchmark_worker *worker = (struct benchmark_worker *)arg;
os_mutex_lock(&worker->lock);
worker_state_wait_for_transition(worker, WORKER_STATE_IDLE,
WORKER_STATE_INIT);
if (worker->init)
worker->ret_init = worker->init(worker->bench, worker->args,
&worker->info);
worker_state_transition(worker, WORKER_STATE_INIT,
WORKER_STATE_INITIALIZED);
worker_state_wait_for_transition(worker, WORKER_STATE_INITIALIZED,
WORKER_STATE_RUN);
worker->ret = worker->func(worker->bench, &worker->info);
worker_state_transition(worker, WORKER_STATE_RUN, WORKER_STATE_END);
worker_state_wait_for_transition(worker, WORKER_STATE_END,
WORKER_STATE_EXIT);
if (worker->exit)
worker->exit(worker->bench, worker->args, &worker->info);
worker_state_transition(worker, WORKER_STATE_EXIT, WORKER_STATE_DONE);
os_mutex_unlock(&worker->lock);
return NULL;
}
struct benchmark_worker *
benchmark_worker_alloc(void)
{
struct benchmark_worker *w =
(struct benchmark_worker *)calloc(1, sizeof(*w));
if (!w)
return NULL;
if (os_mutex_init(&w->lock))
goto err_free_worker;
if (os_cond_init(&w->cond))
goto err_destroy_mutex;
if (os_thread_create(&w->thread, NULL, thread_func, w))
goto err_destroy_cond;
return w;
err_destroy_cond:
os_cond_destroy(&w->cond);
err_destroy_mutex:
os_mutex_destroy(&w->lock);
err_free_worker:
free(w);
return NULL;
}
void
benchmark_worker_free(struct benchmark_worker *w)
{
os_thread_join(&w->thread, NULL);
os_cond_destroy(&w->cond);
os_mutex_destroy(&w->lock);
free(w);
}
int
benchmark_worker_init(struct benchmark_worker *worker)
{
os_mutex_lock(&worker->lock);
worker_state_transition(worker, WORKER_STATE_IDLE, WORKER_STATE_INIT);
worker_state_wait_for_transition(worker, WORKER_STATE_INIT,
WORKER_STATE_INITIALIZED);
int ret = worker->ret_init;
os_mutex_unlock(&worker->lock);
return ret;
}
void
benchmark_worker_exit(struct benchmark_worker *worker)
{
os_mutex_lock(&worker->lock);
worker_state_transition(worker, WORKER_STATE_END, WORKER_STATE_EXIT);
worker_state_wait_for_transition(worker, WORKER_STATE_EXIT,
WORKER_STATE_DONE);
os_mutex_unlock(&worker->lock);
}
int
benchmark_worker_run(struct benchmark_worker *worker)
{
int ret = 0;
os_mutex_lock(&worker->lock);
worker_state_transition(worker, WORKER_STATE_INITIALIZED,
WORKER_STATE_RUN);
os_mutex_unlock(&worker->lock);
return ret;
}
int
benchmark_worker_join(struct benchmark_worker *worker)
{
os_mutex_lock(&worker->lock);
worker_state_wait_for_transition(worker, WORKER_STATE_RUN,
WORKER_STATE_END);
os_mutex_unlock(&worker->lock);
return 0;
}