00001 00002 #include <microfeed/microfeedthread.h> 00003 #include <microfeed/microfeedmisc.h> 00004 #include <microfeed/microfeedstore.h> 00005 00006 #include <pthread.h> 00007 #include <signal.h> 00008 00009 struct _MicrofeedThread { 00010 MicrofeedThread* next; 00011 MicrofeedThread* previous; 00012 00013 unsigned int reference_count; 00014 MicrofeedMutex* mutex; 00015 00016 MicrofeedThreadPool* thread_pool; 00017 void* thread_implementation; 00018 MicrofeedThreadFunction function; 00019 void* in_data; 00020 void* out_data; 00021 MicrofeedThreadExitCallback exit_callback; 00022 void* user_data; 00023 }; 00024 00025 struct _MicrofeedThreadPool { 00026 unsigned int started_threads; 00027 unsigned int max_threads; 00028 MicrofeedThreadExitCallback exit_callback; 00029 void* user_data; 00030 MicrofeedMutex* mutex; 00031 MicrofeedStore* waiting_threads; 00032 }; 00033 00034 struct _MicrofeedMutex { 00035 void* mutex_implementation; 00036 }; 00037 00038 static void* default_thread_new(MicrofeedThreadFunction function, void* data); 00039 static void default_thread_free(void* thread_implementation); 00040 static void* default_thread_get_current(void); 00041 static void default_thread_send_signal(void* thread_implementation, int signal_number); 00042 static void default_thread_join(void* thread_implementation); 00043 static void* default_mutex_new(void); 00044 static void default_mutex_free(void* mutex_implementation); 00045 static void default_mutex_lock(void* mutex_implementation); 00046 static void default_mutex_unlock(void* mutex_implementation); 00047 static void* thread_function(void* data); 00048 00049 MicrofeedThreadFunctions functions = { 00050 default_thread_new, 00051 default_thread_free, 00052 default_thread_get_current, 00053 default_thread_send_signal, 00054 default_thread_join, 00055 default_mutex_new, 00056 default_mutex_free, 00057 default_mutex_lock, 00058 default_mutex_unlock 00059 }; 00060 00061 static MicrofeedThread* threads = NULL; 00062 static MicrofeedMutex* threads_mutex = NULL; 00063 00069 void microfeed_thread_set_functions(MicrofeedThreadFunctions* thread_functions) { 00070 functions = *thread_functions; 00071 } 00072 00073 void microfeed_thread_init(void) { 00074 if (!threads_mutex) { 00075 threads_mutex = microfeed_mutex_new(); 00076 } 00077 if (!threads) { 00078 threads = microfeed_thread_get_current(); 00079 } 00080 } 00081 00082 void microfeed_thread_cleanup(void) { 00083 void* current_thread_implementation; 00084 MicrofeedThread* thread; 00085 00086 microfeed_mutex_lock(threads_mutex); 00087 00088 current_thread_implementation = functions.thread_get_current(); 00089 00090 do { 00091 for (thread = threads; thread; thread = thread->next) { 00092 if (thread->thread_implementation && thread->thread_implementation != current_thread_implementation) { 00093 break; 00094 } 00095 } 00096 if (thread) { 00097 microfeed_mutex_unlock(threads_mutex); 00098 00099 microfeed_thread_join(thread); 00100 00101 microfeed_mutex_lock(threads_mutex); 00102 } 00103 } while (thread); 00104 00105 microfeed_mutex_unlock(threads_mutex); 00106 } 00107 00108 MicrofeedThread* microfeed_thread_new(MicrofeedThreadFunction function, void* data) { 00109 00110 return microfeed_thread_new_with_exit_callback(function, data, NULL, NULL); 00111 } 00112 00113 MicrofeedThread* microfeed_thread_new_with_exit_callback(MicrofeedThreadFunction function, void* data, MicrofeedThreadExitCallback exit_callback, void* user_data) { 00114 MicrofeedThread* thread; 00115 00116 thread = microfeed_memory_allocate(MicrofeedThread); 00117 thread->reference_count = 2; 00118 thread->mutex = microfeed_mutex_new(); 00119 thread->function = function; 00120 thread->in_data = data; 00121 thread->out_data= NULL; 00122 thread->exit_callback = exit_callback; 00123 thread->user_data = user_data; 00124 00125 microfeed_mutex_lock(threads_mutex); 00126 00127 thread->next = threads; 00128 if (thread->next) { 00129 thread->next->previous = thread; 00130 } 00131 threads = thread; 00132 00133 microfeed_mutex_lock(thread->mutex); 00134 00135 thread->thread_implementation = functions.thread_new(thread_function, thread); 00136 00137 microfeed_mutex_unlock(thread->mutex); 00138 00139 microfeed_mutex_unlock(threads_mutex); 00140 00141 return thread; 00142 } 00143 00144 void microfeed_thread_free(MicrofeedThread* thread) { 00145 functions.thread_free(thread->thread_implementation); 00146 00147 microfeed_mutex_lock(threads_mutex); 00148 00149 if (thread->previous) { 00150 thread->previous->next = thread->next; 00151 } else if (threads) { 00152 threads = thread->next; 00153 } 00154 if (thread->next) { 00155 thread->next->previous = thread->previous; 00156 } 00157 00158 microfeed_mutex_unlock(threads_mutex); 00159 00160 microfeed_memory_free(thread); 00161 } 00162 00163 MicrofeedThread* microfeed_thread_ref(MicrofeedThread* thread) { 00164 microfeed_mutex_lock(thread->mutex); 00165 00166 thread->reference_count++; 00167 00168 microfeed_mutex_unlock(thread->mutex); 00169 00170 return thread; 00171 } 00172 00173 void microfeed_thread_unref(MicrofeedThread* thread) { 00174 microfeed_mutex_lock(thread->mutex); 00175 00176 thread->reference_count--; 00177 if (thread->reference_count == 0) { 00178 microfeed_thread_free(thread); 00179 } else { 00180 00181 microfeed_mutex_unlock(thread->mutex); 00182 } 00183 } 00184 00185 MicrofeedThread* microfeed_thread_get_current(void) { 00186 MicrofeedThread* thread = NULL; 00187 void* thread_implementation; 00188 00189 microfeed_mutex_lock(threads_mutex); 00190 00191 if ((thread_implementation = functions.thread_get_current())) { 00192 for (thread = threads; thread; thread = thread->next) { 00193 if (thread->thread_implementation == thread_implementation) { 00194 break; 00195 } 00196 } 00197 } 00198 if (!thread) { 00199 thread = microfeed_memory_allocate(MicrofeedThread); 00200 thread->reference_count = 1; 00201 thread->mutex = microfeed_mutex_new(); 00202 thread->function = NULL; 00203 thread->in_data = NULL; 00204 thread->out_data= NULL; 00205 00206 thread->next = threads; 00207 if (thread->next) { 00208 thread->next->previous = thread; 00209 } 00210 threads = thread; 00211 thread->thread_implementation = thread_implementation; 00212 } 00213 00214 microfeed_mutex_unlock(threads_mutex); 00215 00216 return thread; 00217 } 00218 00219 void microfeed_thread_send_signal(MicrofeedThread* thread, int signal_number) { 00220 functions.thread_send_signal(thread->thread_implementation, signal_number); 00221 } 00222 00223 void microfeed_thread_join(MicrofeedThread* thread) { 00224 functions.thread_join(thread->thread_implementation); 00225 } 00226 00227 MicrofeedThreadPool* microfeed_thread_pool_new(unsigned int maximum_thread_count) { 00228 00229 return microfeed_thread_pool_new_with_exit_callback(maximum_thread_count, NULL, NULL); 00230 } 00231 00237 MicrofeedThreadPool* microfeed_thread_pool_new_with_exit_callback(unsigned int maximum_thread_count, MicrofeedThreadExitCallback exit_callback, void* user_data) { 00238 MicrofeedThreadPool* thread_pool; 00239 00240 thread_pool = microfeed_memory_allocate(MicrofeedThreadPool); 00241 thread_pool->max_threads = maximum_thread_count; 00242 thread_pool->exit_callback = exit_callback; 00243 thread_pool->user_data = user_data; 00244 thread_pool->mutex = microfeed_mutex_new(); 00245 thread_pool->waiting_threads = microfeed_store_new_unsorted(microfeed_store_compare_keys_direct, microfeed_store_get_key_direct); 00246 00247 return thread_pool; 00248 00249 } 00250 00251 MicrofeedThread* microfeed_thread_pool_queue_thread(MicrofeedThreadPool* thread_pool, MicrofeedThreadFunction function, void* data) { 00252 00253 return microfeed_thread_pool_queue_thread_with_exit_callback(thread_pool, function, data, NULL, NULL); 00254 } 00255 00256 MicrofeedThread* microfeed_thread_pool_queue_thread_with_exit_callback(MicrofeedThreadPool* thread_pool, MicrofeedThreadFunction function, void* data, MicrofeedThreadExitCallback exit_callback, void* user_data) { 00257 MicrofeedThread* thread; 00258 00259 thread = microfeed_memory_allocate(MicrofeedThread); 00260 thread->reference_count = 2; 00261 thread->mutex = microfeed_mutex_new(); 00262 thread->thread_pool = thread_pool; 00263 thread->function = function; 00264 thread->in_data = data; 00265 thread->out_data= NULL; 00266 thread->exit_callback = exit_callback; 00267 thread->user_data = user_data; 00268 00269 microfeed_mutex_lock(thread_pool->mutex); 00270 00271 if (thread_pool->started_threads < thread_pool->max_threads) { 00272 thread_pool->started_threads++; 00273 00274 microfeed_mutex_lock(threads_mutex); 00275 00276 thread->next = threads; 00277 if (thread->next) { 00278 thread->next->previous = thread; 00279 } 00280 threads = thread; 00281 00282 microfeed_mutex_lock(thread->mutex); 00283 00284 thread->thread_implementation = functions.thread_new(thread_function, thread); 00285 00286 microfeed_mutex_unlock(thread->mutex); 00287 00288 microfeed_mutex_unlock(threads_mutex); 00289 } else { 00290 microfeed_store_insert(thread_pool->waiting_threads, thread); 00291 } 00292 00293 microfeed_mutex_unlock(thread_pool->mutex); 00294 00295 return thread; 00296 } 00297 00298 unsigned int microfeed_thread_pool_get_started_thread_count(MicrofeedThreadPool* thread_pool) { 00299 00300 return thread_pool->started_threads; 00301 } 00302 00303 unsigned int microfeed_thread_pool_get_waiting_thread_count(MicrofeedThreadPool* thread_pool) { 00304 00305 return microfeed_store_get_size(thread_pool->waiting_threads); 00306 } 00307 00308 void microfeed_thread_pool_set_maximum_thread_count(MicrofeedThreadPool* thread_pool, unsigned int maximum_thread_count) { 00309 00310 thread_pool->max_threads = maximum_thread_count; 00311 } 00312 00313 MicrofeedMutex* microfeed_mutex_new(void) { 00314 MicrofeedMutex* mutex; 00315 00316 mutex = microfeed_memory_allocate(MicrofeedMutex); 00317 mutex->mutex_implementation = functions.mutex_new(); 00318 00319 return mutex; 00320 } 00321 00322 void microfeed_mutex_free(MicrofeedMutex* mutex) { 00323 functions.mutex_free(mutex->mutex_implementation); 00324 microfeed_memory_free(mutex); 00325 } 00326 00327 void microfeed_mutex_lock(MicrofeedMutex* mutex) { 00328 functions.mutex_lock(mutex->mutex_implementation); 00329 } 00330 00331 void microfeed_mutex_unlock(MicrofeedMutex* mutex) { 00332 functions.mutex_unlock(mutex->mutex_implementation); 00333 } 00334 00335 static void* default_thread_new(MicrofeedThreadFunction function, void* data) { 00336 pthread_t* thread_implementation; 00337 00338 thread_implementation = microfeed_memory_allocate(pthread_t); 00339 pthread_create(thread_implementation, NULL, (void* (*)(void*))function, data); 00340 00341 return (void*)thread_implementation; 00342 } 00343 00344 static void default_thread_free(void* thread_implementation) { 00345 microfeed_memory_free(thread_implementation); 00346 } 00347 00348 static void* default_thread_get_current(void) { 00349 pthread_t self; 00350 MicrofeedThread* thread; 00351 pthread_t* thread_implementation; 00352 00353 self = pthread_self(); 00354 for (thread = threads; thread; thread = thread->next) { 00355 if (*((pthread_t*)thread->thread_implementation) == self) { 00356 break; 00357 } 00358 } 00359 if (thread) { 00360 thread_implementation = thread->thread_implementation; 00361 } else { 00362 thread_implementation = microfeed_memory_allocate(pthread_t); 00363 *thread_implementation = self; 00364 } 00365 00366 return (void*)thread_implementation; 00367 } 00368 00369 static void default_thread_send_signal(void* thread_implementation, int signal_number) { 00370 pthread_kill(*(pthread_t*)thread_implementation, signal_number); 00371 } 00372 00373 static void default_thread_join(void* thread_implementation) { 00374 pthread_join(*(pthread_t*)thread_implementation, NULL); 00375 } 00376 00377 static void* default_mutex_new(void) { 00378 pthread_mutex_t* mutex_implementation; 00379 00380 mutex_implementation = microfeed_memory_allocate(pthread_mutex_t); 00381 pthread_mutex_init(mutex_implementation, NULL); 00382 00383 return (void*)mutex_implementation; 00384 } 00385 00386 static void default_mutex_free(void* mutex_implementation) { 00387 pthread_mutex_destroy((pthread_mutex_t*)mutex_implementation); 00388 microfeed_memory_free(mutex_implementation); 00389 } 00390 00391 static void default_mutex_lock(void* mutex_implementation) { 00392 pthread_mutex_lock((pthread_mutex_t*)mutex_implementation); 00393 } 00394 00395 static void default_mutex_unlock(void* mutex_implementation) { 00396 pthread_mutex_unlock((pthread_mutex_t*)mutex_implementation); 00397 } 00398 00399 static void* thread_function(void* data) { 00400 MicrofeedThread* thread; 00401 MicrofeedThreadPool* thread_pool; 00402 00403 thread = (MicrofeedThread*)data; 00404 thread_pool = thread->thread_pool; 00405 00406 do { 00407 thread->out_data = thread->function(thread->in_data); 00408 00409 if (thread->exit_callback) { 00410 thread->exit_callback(thread, thread->user_data); 00411 } 00412 00413 microfeed_mutex_lock(thread->mutex); 00414 00415 thread->reference_count--; 00416 if (thread->reference_count == 0) { 00417 microfeed_thread_free(thread); 00418 } else { 00419 thread->thread_implementation = NULL; 00420 00421 microfeed_mutex_unlock(thread->mutex); 00422 } 00423 thread = NULL; 00424 00425 if (thread_pool) { 00426 microfeed_mutex_lock(thread_pool->mutex); 00427 00428 if (thread_pool->started_threads <= thread_pool->max_threads && microfeed_store_get_size(thread_pool->waiting_threads) > 0) { 00429 thread = microfeed_store_remove_index(thread_pool->waiting_threads, 0, MicrofeedThread); 00430 } else { 00431 thread_pool->started_threads--; 00432 if (thread_pool->exit_callback) { 00433 thread_pool->exit_callback(thread, thread_pool->user_data); 00434 } 00435 } 00436 00437 microfeed_mutex_unlock(thread_pool->mutex); 00438 } 00439 } while (thread); 00440 00441 return NULL; 00442 }