--- a/ui/common/threadpool.c Sun Dec 07 20:00:33 2025 +0100 +++ b/ui/common/threadpool.c Sat Dec 13 15:58:58 2025 +0100 @@ -40,24 +40,20 @@ UiThreadpool* threadpool_new(int min, int max) { UiThreadpool *pool = malloc(sizeof(UiThreadpool)); - pool->queue = NULL; - pool->queue_len = 0; + pool->queue = ui_queue_create(); pool->num_idle = 0; pool->min_threads = min; pool->max_threads = max; - pthread_mutex_init(&pool->queue_lock, NULL); - pthread_mutex_init(&pool->avlbl_lock, NULL); - pthread_cond_init(&pool->available, NULL); - return pool; } int threadpool_start(UiThreadpool *pool) { + pool->nthreads = pool->min_threads; + pool->threads = calloc(pool->max_threads, sizeof(pthread_t)); /* create pool threads */ - for(int i=0;i<pool->min_threads;i++) { - pthread_t t; - if (pthread_create(&t, NULL, threadpool_func, pool) != 0) { + 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; } @@ -65,6 +61,16 @@ 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; @@ -82,69 +88,17 @@ } threadpool_job* threadpool_get_job(UiThreadpool *pool) { - pthread_mutex_lock(&pool->queue_lock); - - threadpool_job *job = NULL; - pool->num_idle++; - while(job == NULL) { - if(pool->queue_len == 0) { - pthread_cond_wait(&pool->available, &pool->queue_lock); - continue; - } else { - pool_queue_t *q = pool->queue; - job = q->job; - pool->queue = q->next; - pool->queue_len--; - free(q); - } - } - pool->num_idle--; - - pthread_mutex_unlock(&pool->queue_lock); + threadpool_job *job = ui_queue_get_wait(pool->queue); return job; } -void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) { - // TODO: handle errors - +void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) { threadpool_job *job = malloc(sizeof(threadpool_job)); job->callback = func; job->data = data; - - pthread_mutex_lock(&pool->queue_lock); - threadpool_enqueue_job(pool, job); - - int create_thread = 0; - int destroy_thread = 0; - int diff = pool->queue_len - pool->num_idle; - - //if(pool->queue_len == 1) { - pthread_cond_signal(&pool->available); - //} - - pthread_mutex_unlock(&pool->queue_lock); + ui_queue_put(pool->queue, job); } -void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) { - pool_queue_t *q = malloc(sizeof(pool_queue_t)); - q->job = job; - q->next = NULL; - - if(pool->queue == NULL) { - pool->queue = q; - } else { - pool_queue_t *last_elem = pool->queue; - while(last_elem->next != NULL) { - last_elem = last_elem->next; - } - last_elem->next = q; - } - pool->queue_len++; -} - - - - UiThreadpool* ui_threadpool_create(int nthreads) { @@ -191,6 +145,71 @@ threadpool_run(pool, ui_threadpool_job_func, job); } +/* --------------------------------- Queue --------------------------------- */ + +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) { + // The queue must be empty, we could free UiQueueElm, + // but not the payload data + 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) { + // create queue element + UiQueueElm *elm = malloc(sizeof(UiQueueElm)); + elm->data = data; + elm->next = NULL; + + pthread_mutex_lock(&queue->lock); + + // put queue element at the end of the linked list + if(queue->elements) { + UiQueueElm *end = queue->elements; + while(end->next) { + end = end->next; + } + end->next = elm; + } else { + queue->elements = elm; + } + queue->length++; + + // signal new available data + 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