2 * The copyright in this software is being made available under the 2-clauses
3 * BSD License, included below. This software may be subject to other third
4 * party and contributor rights, including patent rights, and no such rights
5 * are granted under this license.
7 * Copyright (c) 2016, Even Rouault
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include "opj_includes.h"
39 /* Some versions of x86_64-w64-mingw32-gc -m32 resolve InterlockedCompareExchange() */
40 /* as __sync_val_compare_and_swap_4 but fails to link it. As this protects against */
41 /* a rather unlikely race, skip it */
42 #if !(defined(__MINGW32__) && defined(__i386__))
43 #define HAVE_INTERLOCKED_COMPARE_EXCHANGE 1
49 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
54 int OPJ_CALLCONV opj_get_num_cpus(void)
59 dwNum = info.dwNumberOfProcessors;
70 opj_mutex_t* opj_mutex_create(void)
72 opj_mutex_t* mutex = (opj_mutex_t*) opj_malloc(sizeof(opj_mutex_t));
76 InitializeCriticalSectionAndSpinCount(&(mutex->cs), 4000);
80 void opj_mutex_lock(opj_mutex_t* mutex)
82 EnterCriticalSection(&(mutex->cs));
85 void opj_mutex_unlock(opj_mutex_t* mutex)
87 LeaveCriticalSection(&(mutex->cs));
90 void opj_mutex_destroy(opj_mutex_t* mutex)
95 DeleteCriticalSection(&(mutex->cs));
99 struct opj_cond_waiter_list_t {
101 struct opj_cond_waiter_list_t* next;
103 typedef struct opj_cond_waiter_list_t opj_cond_waiter_list_t;
106 opj_mutex_t *internal_mutex;
107 opj_cond_waiter_list_t *waiter_list;
110 static DWORD TLSKey = 0;
111 static volatile LONG inTLSLockedSection = 0;
112 static volatile int TLSKeyInit = OPJ_FALSE;
114 opj_cond_t* opj_cond_create(void)
116 opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
121 /* Make sure that the TLS key is allocated in a thread-safe way */
122 /* We cannot use a global mutex/critical section since its creation itself would not be */
123 /* thread-safe, so use InterlockedCompareExchange trick */
126 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
127 if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
132 TLSKeyInit = OPJ_TRUE;
134 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
135 InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
141 if (TLSKey == TLS_OUT_OF_INDEXES) {
145 cond->internal_mutex = opj_mutex_create();
146 if (cond->internal_mutex == NULL) {
150 cond->waiter_list = NULL;
154 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
156 opj_cond_waiter_list_t* item;
157 HANDLE hEvent = (HANDLE) TlsGetValue(TLSKey);
158 if (hEvent == NULL) {
159 hEvent = CreateEvent(NULL, /* security attributes */
160 0, /* manual reset = no */
161 0, /* initial state = unsignaled */
165 TlsSetValue(TLSKey, hEvent);
168 /* Insert the waiter into the waiter list of the condition */
169 opj_mutex_lock(cond->internal_mutex);
171 item = (opj_cond_waiter_list_t*)opj_malloc(sizeof(opj_cond_waiter_list_t));
172 assert(item != NULL);
174 item->hEvent = hEvent;
175 item->next = cond->waiter_list;
177 cond->waiter_list = item;
179 opj_mutex_unlock(cond->internal_mutex);
181 /* Release the client mutex before waiting for the event being signaled */
182 opj_mutex_unlock(mutex);
184 /* Ideally we would check that we do not get WAIT_FAILED but it is hard */
185 /* to report a failure. */
186 WaitForSingleObject(hEvent, INFINITE);
188 /* Reacquire the client mutex */
189 opj_mutex_lock(mutex);
192 void opj_cond_signal(opj_cond_t* cond)
194 opj_cond_waiter_list_t* psIter;
196 /* Signal the first registered event, and remove it from the list */
197 opj_mutex_lock(cond->internal_mutex);
199 psIter = cond->waiter_list;
200 if (psIter != NULL) {
201 SetEvent(psIter->hEvent);
202 cond->waiter_list = psIter->next;
206 opj_mutex_unlock(cond->internal_mutex);
209 void opj_cond_destroy(opj_cond_t* cond)
214 opj_mutex_destroy(cond->internal_mutex);
215 assert(cond->waiter_list == NULL);
219 struct opj_thread_t {
220 opj_thread_fn thread_fn;
225 unsigned int __stdcall opj_thread_callback_adapter(void *info)
227 opj_thread_t* thread = (opj_thread_t*) info;
228 HANDLE hEvent = NULL;
230 thread->thread_fn(thread->user_data);
232 /* Free the handle possible allocated by a cond */
234 /* Make sure TLSKey is not being created just at that moment... */
235 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
236 if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
240 hEvent = (HANDLE) TlsGetValue(TLSKey);
242 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
243 InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
255 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
257 opj_thread_t* thread;
261 thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
265 thread->thread_fn = thread_fn;
266 thread->user_data = user_data;
268 thread->hThread = (HANDLE)_beginthreadex(NULL, 0,
269 opj_thread_callback_adapter, thread, 0, NULL);
271 if (thread->hThread == NULL) {
278 void opj_thread_join(opj_thread_t* thread)
280 WaitForSingleObject(thread->hThread, INFINITE);
281 CloseHandle(thread->hThread);
292 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
297 int OPJ_CALLCONV opj_get_num_cpus(void)
299 #ifdef _SC_NPROCESSORS_ONLN
300 return (int)sysconf(_SC_NPROCESSORS_ONLN);
307 pthread_mutex_t mutex;
310 opj_mutex_t* opj_mutex_create(void)
312 opj_mutex_t* mutex = (opj_mutex_t*) opj_calloc(1U, sizeof(opj_mutex_t));
314 if (pthread_mutex_init(&mutex->mutex, NULL) != 0) {
322 void opj_mutex_lock(opj_mutex_t* mutex)
324 pthread_mutex_lock(&(mutex->mutex));
327 void opj_mutex_unlock(opj_mutex_t* mutex)
329 pthread_mutex_unlock(&(mutex->mutex));
332 void opj_mutex_destroy(opj_mutex_t* mutex)
337 pthread_mutex_destroy(&(mutex->mutex));
345 opj_cond_t* opj_cond_create(void)
347 opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
351 if (pthread_cond_init(&(cond->cond), NULL) != 0) {
358 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
360 pthread_cond_wait(&(cond->cond), &(mutex->mutex));
363 void opj_cond_signal(opj_cond_t* cond)
365 int ret = pthread_cond_signal(&(cond->cond));
370 void opj_cond_destroy(opj_cond_t* cond)
375 pthread_cond_destroy(&(cond->cond));
380 struct opj_thread_t {
381 opj_thread_fn thread_fn;
386 static void* opj_thread_callback_adapter(void* info)
388 opj_thread_t* thread = (opj_thread_t*) info;
389 thread->thread_fn(thread->user_data);
393 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
396 opj_thread_t* thread;
400 thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
404 thread->thread_fn = thread_fn;
405 thread->user_data = user_data;
407 pthread_attr_init(&attr);
408 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
409 if (pthread_create(&(thread->thread), &attr,
410 opj_thread_callback_adapter, (void *) thread) != 0) {
417 void opj_thread_join(opj_thread_t* thread)
420 pthread_join(thread->thread, &status);
426 /* Stub implementation */
428 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
433 int OPJ_CALLCONV opj_get_num_cpus(void)
438 opj_mutex_t* opj_mutex_create(void)
443 void opj_mutex_lock(opj_mutex_t* mutex)
448 void opj_mutex_unlock(opj_mutex_t* mutex)
453 void opj_mutex_destroy(opj_mutex_t* mutex)
458 opj_cond_t* opj_cond_create(void)
463 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
469 void opj_cond_signal(opj_cond_t* cond)
474 void opj_cond_destroy(opj_cond_t* cond)
479 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
486 void opj_thread_join(opj_thread_t* thread)
496 opj_tls_free_func opj_free_func;
500 opj_tls_key_val_t* key_val;
504 static opj_tls_t* opj_tls_new(void)
506 return (opj_tls_t*) opj_calloc(1, sizeof(opj_tls_t));
509 static void opj_tls_destroy(opj_tls_t* tls)
515 for (i = 0; i < tls->key_val_count; i++) {
516 if (tls->key_val[i].opj_free_func) {
517 tls->key_val[i].opj_free_func(tls->key_val[i].value);
520 opj_free(tls->key_val);
524 void* opj_tls_get(opj_tls_t* tls, int key)
527 for (i = 0; i < tls->key_val_count; i++) {
528 if (tls->key_val[i].key == key) {
529 return tls->key_val[i].value;
535 OPJ_BOOL opj_tls_set(opj_tls_t* tls, int key, void* value,
536 opj_tls_free_func opj_free_func)
538 opj_tls_key_val_t* new_key_val;
541 if (tls->key_val_count == INT_MAX) {
544 for (i = 0; i < tls->key_val_count; i++) {
545 if (tls->key_val[i].key == key) {
546 if (tls->key_val[i].opj_free_func) {
547 tls->key_val[i].opj_free_func(tls->key_val[i].value);
549 tls->key_val[i].value = value;
550 tls->key_val[i].opj_free_func = opj_free_func;
554 new_key_val = (opj_tls_key_val_t*) opj_realloc(tls->key_val,
555 ((size_t)tls->key_val_count + 1U) * sizeof(opj_tls_key_val_t));
559 tls->key_val = new_key_val;
560 new_key_val[tls->key_val_count].key = key;
561 new_key_val[tls->key_val_count].value = value;
562 new_key_val[tls->key_val_count].opj_free_func = opj_free_func;
563 tls->key_val_count ++;
571 } opj_worker_thread_job_t;
574 opj_thread_pool_t *tp;
575 opj_thread_t *thread;
576 int marked_as_waiting;
580 } opj_worker_thread_t;
586 } opj_worker_thread_state;
588 struct opj_job_list_t {
589 opj_worker_thread_job_t* job;
590 struct opj_job_list_t* next;
592 typedef struct opj_job_list_t opj_job_list_t;
594 struct opj_worker_thread_list_t {
595 opj_worker_thread_t* worker_thread;
596 struct opj_worker_thread_list_t* next;
598 typedef struct opj_worker_thread_list_t opj_worker_thread_list_t;
600 struct opj_thread_pool_t {
601 opj_worker_thread_t* worker_threads;
602 int worker_threads_count;
605 volatile opj_worker_thread_state state;
606 opj_job_list_t* job_queue;
607 volatile int pending_jobs_count;
608 opj_worker_thread_list_t* waiting_worker_thread_list;
609 int waiting_worker_thread_count;
611 int signaling_threshold;
614 static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads);
615 static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
616 opj_thread_pool_t* tp,
617 opj_worker_thread_t* worker_thread,
618 OPJ_BOOL signal_job_finished);
620 opj_thread_pool_t* opj_thread_pool_create(int num_threads)
622 opj_thread_pool_t* tp;
624 tp = (opj_thread_pool_t*) opj_calloc(1, sizeof(opj_thread_pool_t));
628 tp->state = OPJWTS_OK;
630 if (num_threads <= 0) {
631 tp->tls = opj_tls_new();
639 tp->mutex = opj_mutex_create();
644 if (!opj_thread_pool_setup(tp, num_threads)) {
645 opj_thread_pool_destroy(tp);
651 static void opj_worker_thread_function(void* user_data)
653 opj_worker_thread_t* worker_thread;
654 opj_thread_pool_t* tp;
656 OPJ_BOOL job_finished = OPJ_FALSE;
658 worker_thread = (opj_worker_thread_t*) user_data;
659 tp = worker_thread->tp;
663 opj_worker_thread_job_t* job = opj_thread_pool_get_next_job(tp, worker_thread,
670 job->job_fn(job->user_data, tls);
673 job_finished = OPJ_TRUE;
676 opj_tls_destroy(tls);
679 static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads)
682 OPJ_BOOL bRet = OPJ_TRUE;
684 assert(num_threads > 0);
686 tp->cond = opj_cond_create();
687 if (tp->cond == NULL) {
691 tp->worker_threads = (opj_worker_thread_t*) opj_calloc((size_t)num_threads,
692 sizeof(opj_worker_thread_t));
693 if (tp->worker_threads == NULL) {
696 tp->worker_threads_count = num_threads;
698 for (i = 0; i < num_threads; i++) {
699 tp->worker_threads[i].tp = tp;
701 tp->worker_threads[i].mutex = opj_mutex_create();
702 if (tp->worker_threads[i].mutex == NULL) {
703 tp->worker_threads_count = i;
708 tp->worker_threads[i].cond = opj_cond_create();
709 if (tp->worker_threads[i].cond == NULL) {
710 opj_mutex_destroy(tp->worker_threads[i].mutex);
711 tp->worker_threads_count = i;
716 tp->worker_threads[i].marked_as_waiting = OPJ_FALSE;
718 tp->worker_threads[i].thread = opj_thread_create(opj_worker_thread_function,
719 &(tp->worker_threads[i]));
720 if (tp->worker_threads[i].thread == NULL) {
721 tp->worker_threads_count = i;
727 /* Wait all threads to be started */
728 /* printf("waiting for all threads to be started\n"); */
729 opj_mutex_lock(tp->mutex);
730 while (tp->waiting_worker_thread_count < num_threads) {
731 opj_cond_wait(tp->cond, tp->mutex);
733 opj_mutex_unlock(tp->mutex);
734 /* printf("all threads started\n"); */
736 if (tp->state == OPJWTS_ERROR) {
746 printf("waiting!\n");
750 static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
751 opj_thread_pool_t* tp,
752 opj_worker_thread_t* worker_thread,
753 OPJ_BOOL signal_job_finished)
756 opj_job_list_t* top_job_iter;
758 opj_mutex_lock(tp->mutex);
760 if (signal_job_finished) {
761 signal_job_finished = OPJ_FALSE;
762 tp->pending_jobs_count --;
763 /*printf("tp=%p, remaining jobs: %d\n", tp, tp->pending_jobs_count);*/
764 if (tp->pending_jobs_count <= tp->signaling_threshold) {
765 opj_cond_signal(tp->cond);
769 if (tp->state == OPJWTS_STOP) {
770 opj_mutex_unlock(tp->mutex);
773 top_job_iter = tp->job_queue;
775 opj_worker_thread_job_t* job;
776 tp->job_queue = top_job_iter->next;
778 job = top_job_iter->job;
779 opj_mutex_unlock(tp->mutex);
780 opj_free(top_job_iter);
785 if (!worker_thread->marked_as_waiting) {
786 opj_worker_thread_list_t* item;
788 worker_thread->marked_as_waiting = OPJ_TRUE;
789 tp->waiting_worker_thread_count ++;
790 assert(tp->waiting_worker_thread_count <= tp->worker_threads_count);
792 item = (opj_worker_thread_list_t*) opj_malloc(sizeof(opj_worker_thread_list_t));
794 tp->state = OPJWTS_ERROR;
795 opj_cond_signal(tp->cond);
797 opj_mutex_unlock(tp->mutex);
801 item->worker_thread = worker_thread;
802 item->next = tp->waiting_worker_thread_list;
803 tp->waiting_worker_thread_list = item;
806 /* printf("signaling that worker thread is ready\n"); */
807 opj_cond_signal(tp->cond);
809 opj_mutex_lock(worker_thread->mutex);
810 opj_mutex_unlock(tp->mutex);
812 /* printf("waiting for job\n"); */
813 opj_cond_wait(worker_thread->cond, worker_thread->mutex);
815 opj_mutex_unlock(worker_thread->mutex);
816 /* printf("got job\n"); */
820 OPJ_BOOL opj_thread_pool_submit_job(opj_thread_pool_t* tp,
824 opj_worker_thread_job_t* job;
825 opj_job_list_t* item;
827 if (tp->mutex == NULL) {
828 job_fn(user_data, tp->tls);
832 job = (opj_worker_thread_job_t*)opj_malloc(sizeof(opj_worker_thread_job_t));
836 job->job_fn = job_fn;
837 job->user_data = user_data;
839 item = (opj_job_list_t*) opj_malloc(sizeof(opj_job_list_t));
846 opj_mutex_lock(tp->mutex);
848 tp->signaling_threshold = 100 * tp->worker_threads_count;
849 while (tp->pending_jobs_count > tp->signaling_threshold) {
850 /* printf("%d jobs enqueued. Waiting\n", tp->pending_jobs_count); */
851 opj_cond_wait(tp->cond, tp->mutex);
852 /* printf("...%d jobs enqueued.\n", tp->pending_jobs_count); */
855 item->next = tp->job_queue;
856 tp->job_queue = item;
857 tp->pending_jobs_count ++;
859 if (tp->waiting_worker_thread_list) {
860 opj_worker_thread_t* worker_thread;
861 opj_worker_thread_list_t* next;
862 opj_worker_thread_list_t* to_opj_free;
864 worker_thread = tp->waiting_worker_thread_list->worker_thread;
866 assert(worker_thread->marked_as_waiting);
867 worker_thread->marked_as_waiting = OPJ_FALSE;
869 next = tp->waiting_worker_thread_list->next;
870 to_opj_free = tp->waiting_worker_thread_list;
871 tp->waiting_worker_thread_list = next;
872 tp->waiting_worker_thread_count --;
874 opj_mutex_lock(worker_thread->mutex);
875 opj_mutex_unlock(tp->mutex);
876 opj_cond_signal(worker_thread->cond);
877 opj_mutex_unlock(worker_thread->mutex);
879 opj_free(to_opj_free);
881 opj_mutex_unlock(tp->mutex);
887 void opj_thread_pool_wait_completion(opj_thread_pool_t* tp,
888 int max_remaining_jobs)
890 if (tp->mutex == NULL) {
894 if (max_remaining_jobs < 0) {
895 max_remaining_jobs = 0;
897 opj_mutex_lock(tp->mutex);
898 tp->signaling_threshold = max_remaining_jobs;
899 while (tp->pending_jobs_count > max_remaining_jobs) {
900 /*printf("tp=%p, jobs before wait = %d, max_remaining_jobs = %d\n", tp, tp->pending_jobs_count, max_remaining_jobs);*/
901 opj_cond_wait(tp->cond, tp->mutex);
902 /*printf("tp=%p, jobs after wait = %d\n", tp, tp->pending_jobs_count);*/
904 opj_mutex_unlock(tp->mutex);
907 int opj_thread_pool_get_thread_count(opj_thread_pool_t* tp)
909 return tp->worker_threads_count;
912 void opj_thread_pool_destroy(opj_thread_pool_t* tp)
919 opj_thread_pool_wait_completion(tp, 0);
921 opj_mutex_lock(tp->mutex);
922 tp->state = OPJWTS_STOP;
923 opj_mutex_unlock(tp->mutex);
925 for (i = 0; i < tp->worker_threads_count; i++) {
926 opj_mutex_lock(tp->worker_threads[i].mutex);
927 opj_cond_signal(tp->worker_threads[i].cond);
928 opj_mutex_unlock(tp->worker_threads[i].mutex);
929 opj_thread_join(tp->worker_threads[i].thread);
930 opj_cond_destroy(tp->worker_threads[i].cond);
931 opj_mutex_destroy(tp->worker_threads[i].mutex);
934 opj_free(tp->worker_threads);
936 while (tp->waiting_worker_thread_list != NULL) {
937 opj_worker_thread_list_t* next = tp->waiting_worker_thread_list->next;
938 opj_free(tp->waiting_worker_thread_list);
939 tp->waiting_worker_thread_list = next;
942 opj_cond_destroy(tp->cond);
944 opj_mutex_destroy(tp->mutex);
945 opj_tls_destroy(tp->tls);