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.
36 /* Some versions of x86_64-w64-mingw32-gc -m32 resolve InterlockedCompareExchange() */
37 /* as __sync_val_compare_and_swap_4 but fails to link it. As this protects against */
38 /* a rather unlikely race, skip it */
39 #if !(defined(__MINGW32__) && defined(__i386__))
40 #define HAVE_INTERLOCKED_COMPARE_EXCHANGE 1
46 #include "opj_includes.h"
48 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
53 int OPJ_CALLCONV opj_get_num_cpus(void)
58 dwNum = info.dwNumberOfProcessors;
69 opj_mutex_t* opj_mutex_create(void)
71 opj_mutex_t* mutex = (opj_mutex_t*) opj_malloc(sizeof(opj_mutex_t));
75 InitializeCriticalSectionAndSpinCount(&(mutex->cs), 4000);
79 void opj_mutex_lock(opj_mutex_t* mutex)
81 EnterCriticalSection(&(mutex->cs));
84 void opj_mutex_unlock(opj_mutex_t* mutex)
86 LeaveCriticalSection(&(mutex->cs));
89 void opj_mutex_destroy(opj_mutex_t* mutex)
94 DeleteCriticalSection(&(mutex->cs));
98 struct opj_cond_waiter_list_t {
100 struct opj_cond_waiter_list_t* next;
102 typedef struct opj_cond_waiter_list_t opj_cond_waiter_list_t;
105 opj_mutex_t *internal_mutex;
106 opj_cond_waiter_list_t *waiter_list;
109 static DWORD TLSKey = 0;
110 static volatile LONG inTLSLockedSection = 0;
111 static volatile int TLSKeyInit = OPJ_FALSE;
113 opj_cond_t* opj_cond_create(void)
115 opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
120 /* Make sure that the TLS key is allocated in a thread-safe way */
121 /* We cannot use a global mutex/critical section since its creation itself would not be */
122 /* thread-safe, so use InterlockedCompareExchange trick */
125 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
126 if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
131 TLSKeyInit = OPJ_TRUE;
133 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
134 InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
140 if (TLSKey == TLS_OUT_OF_INDEXES) {
144 cond->internal_mutex = opj_mutex_create();
145 if (cond->internal_mutex == NULL) {
149 cond->waiter_list = NULL;
153 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
155 opj_cond_waiter_list_t* item;
156 HANDLE hEvent = (HANDLE) TlsGetValue(TLSKey);
157 if (hEvent == NULL) {
158 hEvent = CreateEvent(NULL, /* security attributes */
159 0, /* manual reset = no */
160 0, /* initial state = unsignaled */
164 TlsSetValue(TLSKey, hEvent);
167 /* Insert the waiter into the waiter list of the condition */
168 opj_mutex_lock(cond->internal_mutex);
170 item = (opj_cond_waiter_list_t*)opj_malloc(sizeof(opj_cond_waiter_list_t));
171 assert(item != NULL);
173 item->hEvent = hEvent;
174 item->next = cond->waiter_list;
176 cond->waiter_list = item;
178 opj_mutex_unlock(cond->internal_mutex);
180 /* Release the client mutex before waiting for the event being signaled */
181 opj_mutex_unlock(mutex);
183 /* Ideally we would check that we do not get WAIT_FAILED but it is hard */
184 /* to report a failure. */
185 WaitForSingleObject(hEvent, INFINITE);
187 /* Reacquire the client mutex */
188 opj_mutex_lock(mutex);
191 void opj_cond_signal(opj_cond_t* cond)
193 opj_cond_waiter_list_t* psIter;
195 /* Signal the first registered event, and remove it from the list */
196 opj_mutex_lock(cond->internal_mutex);
198 psIter = cond->waiter_list;
199 if (psIter != NULL) {
200 SetEvent(psIter->hEvent);
201 cond->waiter_list = psIter->next;
205 opj_mutex_unlock(cond->internal_mutex);
208 void opj_cond_destroy(opj_cond_t* cond)
213 opj_mutex_destroy(cond->internal_mutex);
214 assert(cond->waiter_list == NULL);
218 struct opj_thread_t {
219 opj_thread_fn thread_fn;
224 unsigned int __stdcall opj_thread_callback_adapter(void *info)
226 opj_thread_t* thread = (opj_thread_t*) info;
227 HANDLE hEvent = NULL;
229 thread->thread_fn(thread->user_data);
231 /* Free the handle possible allocated by a cond */
233 /* Make sure TLSKey is not being created just at that moment... */
234 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
235 if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
239 hEvent = (HANDLE) TlsGetValue(TLSKey);
241 #if HAVE_INTERLOCKED_COMPARE_EXCHANGE
242 InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
254 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
256 opj_thread_t* thread;
260 thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
264 thread->thread_fn = thread_fn;
265 thread->user_data = user_data;
267 thread->hThread = (HANDLE)_beginthreadex(NULL, 0,
268 opj_thread_callback_adapter, thread, 0, NULL);
270 if (thread->hThread == NULL) {
277 void opj_thread_join(opj_thread_t* thread)
279 WaitForSingleObject(thread->hThread, INFINITE);
280 CloseHandle(thread->hThread);
291 /* Moved after all system includes, and in particular pthread.h, so as to */
292 /* avoid poisoning issuing with malloc() use in pthread.h with ulibc (#1013) */
293 #include "opj_includes.h"
295 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
300 int OPJ_CALLCONV opj_get_num_cpus(void)
302 #ifdef _SC_NPROCESSORS_ONLN
303 return (int)sysconf(_SC_NPROCESSORS_ONLN);
310 pthread_mutex_t mutex;
313 opj_mutex_t* opj_mutex_create(void)
315 opj_mutex_t* mutex = (opj_mutex_t*) opj_calloc(1U, sizeof(opj_mutex_t));
317 if (pthread_mutex_init(&mutex->mutex, NULL) != 0) {
325 void opj_mutex_lock(opj_mutex_t* mutex)
327 pthread_mutex_lock(&(mutex->mutex));
330 void opj_mutex_unlock(opj_mutex_t* mutex)
332 pthread_mutex_unlock(&(mutex->mutex));
335 void opj_mutex_destroy(opj_mutex_t* mutex)
340 pthread_mutex_destroy(&(mutex->mutex));
348 opj_cond_t* opj_cond_create(void)
350 opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
354 if (pthread_cond_init(&(cond->cond), NULL) != 0) {
361 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
363 pthread_cond_wait(&(cond->cond), &(mutex->mutex));
366 void opj_cond_signal(opj_cond_t* cond)
368 int ret = pthread_cond_signal(&(cond->cond));
373 void opj_cond_destroy(opj_cond_t* cond)
378 pthread_cond_destroy(&(cond->cond));
383 struct opj_thread_t {
384 opj_thread_fn thread_fn;
389 static void* opj_thread_callback_adapter(void* info)
391 opj_thread_t* thread = (opj_thread_t*) info;
392 thread->thread_fn(thread->user_data);
396 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
399 opj_thread_t* thread;
403 thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
407 thread->thread_fn = thread_fn;
408 thread->user_data = user_data;
410 pthread_attr_init(&attr);
411 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
412 if (pthread_create(&(thread->thread), &attr,
413 opj_thread_callback_adapter, (void *) thread) != 0) {
420 void opj_thread_join(opj_thread_t* thread)
423 pthread_join(thread->thread, &status);
429 /* Stub implementation */
431 #include "opj_includes.h"
433 OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
438 int OPJ_CALLCONV opj_get_num_cpus(void)
443 opj_mutex_t* opj_mutex_create(void)
448 void opj_mutex_lock(opj_mutex_t* mutex)
453 void opj_mutex_unlock(opj_mutex_t* mutex)
458 void opj_mutex_destroy(opj_mutex_t* mutex)
463 opj_cond_t* opj_cond_create(void)
468 void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
474 void opj_cond_signal(opj_cond_t* cond)
479 void opj_cond_destroy(opj_cond_t* cond)
484 opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
491 void opj_thread_join(opj_thread_t* thread)
501 opj_tls_free_func opj_free_func;
505 opj_tls_key_val_t* key_val;
509 static opj_tls_t* opj_tls_new(void)
511 return (opj_tls_t*) opj_calloc(1, sizeof(opj_tls_t));
514 static void opj_tls_destroy(opj_tls_t* tls)
520 for (i = 0; i < tls->key_val_count; i++) {
521 if (tls->key_val[i].opj_free_func) {
522 tls->key_val[i].opj_free_func(tls->key_val[i].value);
525 opj_free(tls->key_val);
529 void* opj_tls_get(opj_tls_t* tls, int key)
532 for (i = 0; i < tls->key_val_count; i++) {
533 if (tls->key_val[i].key == key) {
534 return tls->key_val[i].value;
540 OPJ_BOOL opj_tls_set(opj_tls_t* tls, int key, void* value,
541 opj_tls_free_func opj_free_func)
543 opj_tls_key_val_t* new_key_val;
546 if (tls->key_val_count == INT_MAX) {
549 for (i = 0; i < tls->key_val_count; i++) {
550 if (tls->key_val[i].key == key) {
551 if (tls->key_val[i].opj_free_func) {
552 tls->key_val[i].opj_free_func(tls->key_val[i].value);
554 tls->key_val[i].value = value;
555 tls->key_val[i].opj_free_func = opj_free_func;
559 new_key_val = (opj_tls_key_val_t*) opj_realloc(tls->key_val,
560 ((size_t)tls->key_val_count + 1U) * sizeof(opj_tls_key_val_t));
564 tls->key_val = new_key_val;
565 new_key_val[tls->key_val_count].key = key;
566 new_key_val[tls->key_val_count].value = value;
567 new_key_val[tls->key_val_count].opj_free_func = opj_free_func;
568 tls->key_val_count ++;
576 } opj_worker_thread_job_t;
579 opj_thread_pool_t *tp;
580 opj_thread_t *thread;
581 int marked_as_waiting;
585 } opj_worker_thread_t;
591 } opj_worker_thread_state;
593 struct opj_job_list_t {
594 opj_worker_thread_job_t* job;
595 struct opj_job_list_t* next;
597 typedef struct opj_job_list_t opj_job_list_t;
599 struct opj_worker_thread_list_t {
600 opj_worker_thread_t* worker_thread;
601 struct opj_worker_thread_list_t* next;
603 typedef struct opj_worker_thread_list_t opj_worker_thread_list_t;
605 struct opj_thread_pool_t {
606 opj_worker_thread_t* worker_threads;
607 int worker_threads_count;
610 volatile opj_worker_thread_state state;
611 opj_job_list_t* job_queue;
612 volatile int pending_jobs_count;
613 opj_worker_thread_list_t* waiting_worker_thread_list;
614 int waiting_worker_thread_count;
616 int signaling_threshold;
619 static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads);
620 static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
621 opj_thread_pool_t* tp,
622 opj_worker_thread_t* worker_thread,
623 OPJ_BOOL signal_job_finished);
625 opj_thread_pool_t* opj_thread_pool_create(int num_threads)
627 opj_thread_pool_t* tp;
629 tp = (opj_thread_pool_t*) opj_calloc(1, sizeof(opj_thread_pool_t));
633 tp->state = OPJWTS_OK;
635 if (num_threads <= 0) {
636 tp->tls = opj_tls_new();
644 tp->mutex = opj_mutex_create();
649 if (!opj_thread_pool_setup(tp, num_threads)) {
650 opj_thread_pool_destroy(tp);
656 static void opj_worker_thread_function(void* user_data)
658 opj_worker_thread_t* worker_thread;
659 opj_thread_pool_t* tp;
661 OPJ_BOOL job_finished = OPJ_FALSE;
663 worker_thread = (opj_worker_thread_t*) user_data;
664 tp = worker_thread->tp;
668 opj_worker_thread_job_t* job = opj_thread_pool_get_next_job(tp, worker_thread,
675 job->job_fn(job->user_data, tls);
678 job_finished = OPJ_TRUE;
681 opj_tls_destroy(tls);
684 static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads)
687 OPJ_BOOL bRet = OPJ_TRUE;
689 assert(num_threads > 0);
691 tp->cond = opj_cond_create();
692 if (tp->cond == NULL) {
696 tp->worker_threads = (opj_worker_thread_t*) opj_calloc((size_t)num_threads,
697 sizeof(opj_worker_thread_t));
698 if (tp->worker_threads == NULL) {
701 tp->worker_threads_count = num_threads;
703 for (i = 0; i < num_threads; i++) {
704 tp->worker_threads[i].tp = tp;
706 tp->worker_threads[i].mutex = opj_mutex_create();
707 if (tp->worker_threads[i].mutex == NULL) {
708 tp->worker_threads_count = i;
713 tp->worker_threads[i].cond = opj_cond_create();
714 if (tp->worker_threads[i].cond == NULL) {
715 opj_mutex_destroy(tp->worker_threads[i].mutex);
716 tp->worker_threads_count = i;
721 tp->worker_threads[i].marked_as_waiting = OPJ_FALSE;
723 tp->worker_threads[i].thread = opj_thread_create(opj_worker_thread_function,
724 &(tp->worker_threads[i]));
725 if (tp->worker_threads[i].thread == NULL) {
726 opj_mutex_destroy(tp->worker_threads[i].mutex);
727 opj_cond_destroy(tp->worker_threads[i].cond);
728 tp->worker_threads_count = i;
734 /* Wait all threads to be started */
735 /* printf("waiting for all threads to be started\n"); */
736 opj_mutex_lock(tp->mutex);
737 while (tp->waiting_worker_thread_count < tp->worker_threads_count) {
738 opj_cond_wait(tp->cond, tp->mutex);
740 opj_mutex_unlock(tp->mutex);
741 /* printf("all threads started\n"); */
743 if (tp->state == OPJWTS_ERROR) {
753 printf("waiting!\n");
757 static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
758 opj_thread_pool_t* tp,
759 opj_worker_thread_t* worker_thread,
760 OPJ_BOOL signal_job_finished)
763 opj_job_list_t* top_job_iter;
765 opj_mutex_lock(tp->mutex);
767 if (signal_job_finished) {
768 signal_job_finished = OPJ_FALSE;
769 tp->pending_jobs_count --;
770 /*printf("tp=%p, remaining jobs: %d\n", tp, tp->pending_jobs_count);*/
771 if (tp->pending_jobs_count <= tp->signaling_threshold) {
772 opj_cond_signal(tp->cond);
776 if (tp->state == OPJWTS_STOP) {
777 opj_mutex_unlock(tp->mutex);
780 top_job_iter = tp->job_queue;
782 opj_worker_thread_job_t* job;
783 tp->job_queue = top_job_iter->next;
785 job = top_job_iter->job;
786 opj_mutex_unlock(tp->mutex);
787 opj_free(top_job_iter);
792 if (!worker_thread->marked_as_waiting) {
793 opj_worker_thread_list_t* item;
795 worker_thread->marked_as_waiting = OPJ_TRUE;
796 tp->waiting_worker_thread_count ++;
797 assert(tp->waiting_worker_thread_count <= tp->worker_threads_count);
799 item = (opj_worker_thread_list_t*) opj_malloc(sizeof(opj_worker_thread_list_t));
801 tp->state = OPJWTS_ERROR;
802 opj_cond_signal(tp->cond);
804 opj_mutex_unlock(tp->mutex);
808 item->worker_thread = worker_thread;
809 item->next = tp->waiting_worker_thread_list;
810 tp->waiting_worker_thread_list = item;
813 /* printf("signaling that worker thread is ready\n"); */
814 opj_cond_signal(tp->cond);
816 opj_mutex_lock(worker_thread->mutex);
817 opj_mutex_unlock(tp->mutex);
819 /* printf("waiting for job\n"); */
820 opj_cond_wait(worker_thread->cond, worker_thread->mutex);
822 opj_mutex_unlock(worker_thread->mutex);
823 /* printf("got job\n"); */
827 OPJ_BOOL opj_thread_pool_submit_job(opj_thread_pool_t* tp,
831 opj_worker_thread_job_t* job;
832 opj_job_list_t* item;
834 if (tp->mutex == NULL) {
835 job_fn(user_data, tp->tls);
839 job = (opj_worker_thread_job_t*)opj_malloc(sizeof(opj_worker_thread_job_t));
843 job->job_fn = job_fn;
844 job->user_data = user_data;
846 item = (opj_job_list_t*) opj_malloc(sizeof(opj_job_list_t));
853 opj_mutex_lock(tp->mutex);
855 tp->signaling_threshold = 100 * tp->worker_threads_count;
856 while (tp->pending_jobs_count > tp->signaling_threshold) {
857 /* printf("%d jobs enqueued. Waiting\n", tp->pending_jobs_count); */
858 opj_cond_wait(tp->cond, tp->mutex);
859 /* printf("...%d jobs enqueued.\n", tp->pending_jobs_count); */
862 item->next = tp->job_queue;
863 tp->job_queue = item;
864 tp->pending_jobs_count ++;
866 if (tp->waiting_worker_thread_list) {
867 opj_worker_thread_t* worker_thread;
868 opj_worker_thread_list_t* next;
869 opj_worker_thread_list_t* to_opj_free;
871 worker_thread = tp->waiting_worker_thread_list->worker_thread;
873 assert(worker_thread->marked_as_waiting);
874 worker_thread->marked_as_waiting = OPJ_FALSE;
876 next = tp->waiting_worker_thread_list->next;
877 to_opj_free = tp->waiting_worker_thread_list;
878 tp->waiting_worker_thread_list = next;
879 tp->waiting_worker_thread_count --;
881 opj_mutex_lock(worker_thread->mutex);
882 opj_mutex_unlock(tp->mutex);
883 opj_cond_signal(worker_thread->cond);
884 opj_mutex_unlock(worker_thread->mutex);
886 opj_free(to_opj_free);
888 opj_mutex_unlock(tp->mutex);
894 void opj_thread_pool_wait_completion(opj_thread_pool_t* tp,
895 int max_remaining_jobs)
897 if (tp->mutex == NULL) {
901 if (max_remaining_jobs < 0) {
902 max_remaining_jobs = 0;
904 opj_mutex_lock(tp->mutex);
905 tp->signaling_threshold = max_remaining_jobs;
906 while (tp->pending_jobs_count > max_remaining_jobs) {
907 /*printf("tp=%p, jobs before wait = %d, max_remaining_jobs = %d\n", tp, tp->pending_jobs_count, max_remaining_jobs);*/
908 opj_cond_wait(tp->cond, tp->mutex);
909 /*printf("tp=%p, jobs after wait = %d\n", tp, tp->pending_jobs_count);*/
911 opj_mutex_unlock(tp->mutex);
914 int opj_thread_pool_get_thread_count(opj_thread_pool_t* tp)
916 return tp->worker_threads_count;
919 void opj_thread_pool_destroy(opj_thread_pool_t* tp)
926 opj_thread_pool_wait_completion(tp, 0);
928 opj_mutex_lock(tp->mutex);
929 tp->state = OPJWTS_STOP;
930 opj_mutex_unlock(tp->mutex);
932 for (i = 0; i < tp->worker_threads_count; i++) {
933 opj_mutex_lock(tp->worker_threads[i].mutex);
934 opj_cond_signal(tp->worker_threads[i].cond);
935 opj_mutex_unlock(tp->worker_threads[i].mutex);
936 opj_thread_join(tp->worker_threads[i].thread);
937 opj_cond_destroy(tp->worker_threads[i].cond);
938 opj_mutex_destroy(tp->worker_threads[i].mutex);
941 opj_free(tp->worker_threads);
943 while (tp->waiting_worker_thread_list != NULL) {
944 opj_worker_thread_list_t* next = tp->waiting_worker_thread_list->next;
945 opj_free(tp->waiting_worker_thread_list);
946 tp->waiting_worker_thread_list = next;
949 opj_cond_destroy(tp->cond);
951 opj_mutex_destroy(tp->mutex);
952 opj_tls_destroy(tp->tls);