#ifndef _WIN32
#include "threadpool.h"
#include "context.h"
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
static threadpool_job kill_job;
UiThreadpool* threadpool_new(
int min,
int max) {
UiThreadpool *pool = malloc(
sizeof(UiThreadpool));
pool->queue = ui_queue_create();
pool->num_idle =
0;
pool->min_threads = min;
pool->max_threads = max;
return pool;
}
int threadpool_start(UiThreadpool *pool) {
pool->nthreads = pool->min_threads;
pool->threads = calloc(pool->max_threads,
sizeof(
pthread_t));
for(
int i=
0;i<pool->nthreads;i++) {
if (pthread_create(&pool->threads[i],
NULL, threadpool_func, pool) !=
0) {
fprintf(stderr,
"uic: threadpool_start: pthread_create failed: %s", strerror(errno));
return 1;
}
}
return 0;
}
int threadpool_join(UiThreadpool *pool) {
int err =
0;
for(
int i=
0;i<pool->nthreads;i++) {
if(pthread_join(pool->threads[i],
NULL)) {
err =
1;
}
}
return err;
}
void* threadpool_func(
void *data) {
UiThreadpool *pool = (UiThreadpool*)data;
for(;;) {
threadpool_job *job = threadpool_get_job(pool);
if(job == &kill_job) {
break;
}
job->callback(job->data);
free(job);
}
return NULL;
}
threadpool_job* threadpool_get_job(UiThreadpool *pool) {
threadpool_job *job = ui_queue_get_wait(pool->queue);
return job;
}
void threadpool_run(UiThreadpool *pool, job_callback_f func,
void *data) {
threadpool_job *job = malloc(
sizeof(threadpool_job));
job->callback = func;
job->data = data;
ui_queue_put(pool->queue, job);
}
UiThreadpool* ui_threadpool_create(
int nthreads) {
UiThreadpool *pool = threadpool_new(nthreads, nthreads);
threadpool_start(pool);
return pool;
}
void ui_threadpool_destroy(UiThreadpool* pool) {
}
static int ui_threadpool_job_finish(
void *data) {
UiJob *job = data;
UiEvent event;
event.obj = job->obj;
event.window = job->obj->window;
event.document = job->obj->ctx->document;
event.intval =
0;
event.eventdata =
NULL;
event.eventdatatype =
0;
job->finish_callback(&event, job->finish_data);
free(job);
return 0;
}
static void* ui_threadpool_job_func(
void *data) {
UiJob *job = data;
if (!job->job_func(job->job_data) && job->finish_callback) {
ui_call_mainthread(ui_threadpool_job_finish, job);
}
else {
free(job);
}
return NULL;
}
void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf,
void* td, ui_callback f,
void* fd) {
UiJob* job = malloc(
sizeof(UiJob));
job->obj = obj;
job->job_func = tf;
job->job_data = td;
job->finish_callback = f;
job->finish_data = fd;
threadpool_run(pool, ui_threadpool_job_func, job);
}
UiQueue* ui_queue_create(
void) {
UiQueue *queue = calloc(
1,
sizeof(UiQueue));
pthread_mutex_init(&queue->lock,
NULL);
pthread_mutex_init(&queue->avlbl_lock,
NULL);
pthread_cond_init(&queue->available,
NULL);
return queue;
}
void ui_queue_free(UiQueue *queue) {
pthread_mutex_destroy(&queue->lock);
pthread_mutex_destroy(&queue->avlbl_lock);
pthread_cond_destroy(&queue->available);
free(queue);
}
void ui_queue_put(UiQueue *queue,
void *data) {
UiQueueElm *elm = malloc(
sizeof(UiQueueElm));
elm->data = data;
elm->next =
NULL;
pthread_mutex_lock(&queue->lock);
if(queue->elements) {
UiQueueElm *end = queue->elements;
while(end->next) {
end = end->next;
}
end->next = elm;
}
else {
queue->elements = elm;
}
queue->length++;
pthread_cond_signal(&queue->available);
pthread_mutex_unlock(&queue->lock);
}
void* ui_queue_get_wait(UiQueue *queue) {
pthread_mutex_lock(&queue->lock);
void *data =
NULL;
while(data ==
NULL) {
if(queue->length ==
0) {
pthread_cond_wait(&queue->available, &queue->lock);
continue;
}
else {
UiQueueElm *q = queue->elements;
data = q->data;
queue->elements = q->next;
queue->length--;
free(q);
}
}
pthread_mutex_unlock(&queue->lock);
return data;
}
#endif