static void *
sol_worker_thread_do(void *data)
{
    struct sol_worker_thread_posix *thread = data;
    struct sol_worker_thread_config *config = &thread->config;

    SOL_DBG("worker thread %p started", thread);

    if (config->setup) {
        if (!config->setup((void *)config->data))
            goto end;
    }

    while (!sol_worker_thread_impl_cancel_check(thread)) {
        if (!config->iterate((void *)config->data))
            break;
    }

    if (config->cleanup)
        config->cleanup((void *)config->data);

end:
    if (sol_worker_thread_lock(thread)) {
        if (thread->idler)
            sol_idle_del(thread->idler);
        thread->idler = sol_idle_add(sol_worker_thread_finished, thread);
        sol_worker_thread_unlock(thread);
    }

    SOL_DBG("worker thread %p stopped", thread);

    return thread;
}
void
sol_worker_thread_impl_cancel(void *handle)
{
    struct sol_worker_thread_posix *thread = handle;

    SOL_NULL_CHECK(thread);

    if (sol_worker_thread_impl_cancel_check(thread)) {
        SOL_WRN("worker thread %p is not running.", thread);
        return;
    }
    if (thread->thread == pthread_self()) {
        SOL_WRN("trying to cancel from worker thread %p.", thread);
        return;
    }

    cancel_set(thread);

    if (thread->config.cancel)
        thread->config.cancel((void *)thread->config.data);

    pthread_join(thread->thread, NULL);
    thread->thread = 0;

    /* no locks since thread is now dead */
    sol_idle_del(thread->idler);
    sol_worker_thread_finished(thread);
}
static gpointer
sol_worker_thread_do(gpointer data)
{
    struct sol_worker_thread_glib *thread = data;
    struct sol_worker_thread_config *config = &thread->config;

    SOL_DBG("worker thread %p started", thread);

    if (config->setup) {
        if (!config->setup((void *)config->data))
            goto end;
    }

    while (!sol_worker_thread_impl_cancel_check(thread)) {
        if (!config->iterate((void *)config->data))
            break;
    }

    if (config->cleanup)
        config->cleanup((void *)config->data);

end:
    g_mutex_lock(&thread->lock);
    if (thread->idler)
        sol_idle_del(thread->idler);
    thread->idler = sol_idle_add(sol_worker_thread_finished, thread);
    g_mutex_unlock(&thread->lock);

    SOL_DBG("worker thread %p stopped", thread);

    return thread;
}
void
sol_worker_thread_impl_feedback(void *handle)
{
    struct sol_worker_thread_posix *thread = handle;

    SOL_NULL_CHECK(thread);
    SOL_NULL_CHECK(thread->config.feedback);

    if (sol_worker_thread_impl_cancel_check(thread)) {
        SOL_WRN("worker thread %p is not running.", thread);
        return;
    }
    if (thread->thread != pthread_self()) {
        SOL_WRN("trying to feedback from different worker thread %p.", thread);
        return;
    }
    if (sol_worker_thread_lock(thread)) {
        if (!thread->idler)
            thread->idler = sol_idle_add(sol_worker_thread_feedback_dispatch, thread);
        sol_worker_thread_unlock(thread);
    }
}
static bool
sol_worker_thread_finished(void *data)
{
    struct sol_worker_thread_posix *thread = data;

    if (!sol_worker_thread_impl_cancel_check(thread)) {
        /* no need to set cancel, the thread has finished */
        pthread_join(thread->thread, NULL);
        thread->thread = 0;
    }
    pthread_mutex_destroy(&thread->lock);

    /* no locks since thread is now dead */
    thread->idler = NULL;

    SOL_DBG("worker thread %p finished", thread);

    if (thread->config.finished)
        thread->config.finished((void *)thread->config.data);

    free(thread);
    return false;
}
SOL_API bool
sol_worker_thread_cancel_check(const struct sol_worker_thread *thread)
{
    SOL_NULL_CHECK(thread, false);
    return sol_worker_thread_impl_cancel_check(thread);
}