UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2024 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "threadpool.h" 30 #include "context.h" 31 32 #ifndef _WIN32 33 34 #include <pthread.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <errno.h> 38 39 static threadpool_job kill_job; 40 41 UiThreadpool* threadpool_new(int min, int max) { 42 UiThreadpool *pool = malloc(sizeof(UiThreadpool)); 43 pool->queue = NULL; 44 pool->queue_len = 0; 45 pool->num_idle = 0; 46 pool->min_threads = min; 47 pool->max_threads = max; 48 49 pthread_mutex_init(&pool->queue_lock, NULL); 50 pthread_mutex_init(&pool->avlbl_lock, NULL); 51 pthread_cond_init(&pool->available, NULL); 52 53 return pool; 54 } 55 56 int threadpool_start(UiThreadpool *pool) { 57 /* create pool threads */ 58 for(int i=0;i<pool->min_threads;i++) { 59 pthread_t t; 60 if (pthread_create(&t, NULL, threadpool_func, pool) != 0) { 61 fprintf(stderr, "uic: threadpool_start: pthread_create failed: %s", strerror(errno)); 62 return 1; 63 } 64 } 65 return 0; 66 } 67 68 void* threadpool_func(void *data) { 69 UiThreadpool *pool = (UiThreadpool*)data; 70 71 for(;;) { 72 threadpool_job *job = threadpool_get_job(pool); 73 if(job == &kill_job) { 74 break; 75 } 76 77 job->callback(job->data); 78 79 free(job); 80 } 81 return NULL; 82 } 83 84 threadpool_job* threadpool_get_job(UiThreadpool *pool) { 85 pthread_mutex_lock(&pool->queue_lock); 86 87 threadpool_job *job = NULL; 88 pool->num_idle++; 89 while(job == NULL) { 90 if(pool->queue_len == 0) { 91 pthread_cond_wait(&pool->available, &pool->queue_lock); 92 continue; 93 } else { 94 pool_queue_t *q = pool->queue; 95 job = q->job; 96 pool->queue = q->next; 97 pool->queue_len--; 98 free(q); 99 } 100 } 101 pool->num_idle--; 102 103 pthread_mutex_unlock(&pool->queue_lock); 104 return job; 105 } 106 107 void threadpool_run(UiThreadpool *pool, job_callback_f func, void *data) { 108 // TODO: handle errors 109 110 threadpool_job *job = malloc(sizeof(threadpool_job)); 111 job->callback = func; 112 job->data = data; 113 114 pthread_mutex_lock(&pool->queue_lock); 115 threadpool_enqueue_job(pool, job); 116 117 int create_thread = 0; 118 int destroy_thread = 0; 119 int diff = pool->queue_len - pool->num_idle; 120 121 //if(pool->queue_len == 1) { 122 pthread_cond_signal(&pool->available); 123 //} 124 125 pthread_mutex_unlock(&pool->queue_lock); 126 } 127 128 void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) { 129 pool_queue_t *q = malloc(sizeof(pool_queue_t)); 130 q->job = job; 131 q->next = NULL; 132 133 if(pool->queue == NULL) { 134 pool->queue = q; 135 } else { 136 pool_queue_t *last_elem = pool->queue; 137 while(last_elem->next != NULL) { 138 last_elem = last_elem->next; 139 } 140 last_elem->next = q; 141 } 142 pool->queue_len++; 143 } 144 145 146 147 148 149 150 UiThreadpool* ui_threadpool_create(int nthreads) { 151 UiThreadpool *pool = threadpool_new(nthreads, nthreads); 152 threadpool_start(pool); // TODO: check return value 153 return pool; 154 } 155 156 void ui_threadpool_destroy(UiThreadpool* pool) { 157 158 } 159 160 static int ui_threadpool_job_finish(void *data) { 161 UiJob *job = data; 162 UiEvent event; 163 event.obj = job->obj; 164 event.window = job->obj->window; 165 event.document = job->obj->ctx->document; 166 event.intval = 0; 167 event.eventdata = NULL; 168 job->finish_callback(&event, job->finish_data); 169 free(job); 170 return 0; 171 } 172 173 static void* ui_threadpool_job_func(void *data) { 174 UiJob *job = data; 175 if (!job->job_func(job->job_data) && job->finish_callback) { 176 ui_call_mainthread(ui_threadpool_job_finish, job); 177 } else { 178 free(job); 179 } 180 return NULL; 181 } 182 183 void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { 184 UiJob* job = malloc(sizeof(UiJob)); 185 job->obj = obj; 186 job->job_func = tf; 187 job->job_data = td; 188 job->finish_callback = f; 189 job->finish_data = fd; 190 threadpool_run(pool, ui_threadpool_job_func, job); 191 } 192 193 194 #endif 195 196