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