#include <assert.h>
#ifdef MUTEX_win32
#if !(defined(__MINGW32__) && defined(__i386__))
#define HAVE_INTERLOCKED_COMPARE_EXCHANGE …
#endif
#include <windows.h>
#include <process.h>
#include "opj_includes.h"
OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
{
return OPJ_TRUE;
}
int OPJ_CALLCONV opj_get_num_cpus(void)
{
SYSTEM_INFO info;
DWORD dwNum;
GetSystemInfo(&info);
dwNum = info.dwNumberOfProcessors;
if (dwNum < 1) {
return 1;
}
return (int)dwNum;
}
struct opj_mutex_t {
CRITICAL_SECTION cs;
};
opj_mutex_t* opj_mutex_create(void)
{
opj_mutex_t* mutex = (opj_mutex_t*) opj_malloc(sizeof(opj_mutex_t));
if (!mutex) {
return NULL;
}
InitializeCriticalSectionAndSpinCount(&(mutex->cs), 4000);
return mutex;
}
void opj_mutex_lock(opj_mutex_t* mutex)
{
EnterCriticalSection(&(mutex->cs));
}
void opj_mutex_unlock(opj_mutex_t* mutex)
{
LeaveCriticalSection(&(mutex->cs));
}
void opj_mutex_destroy(opj_mutex_t* mutex)
{
if (!mutex) {
return;
}
DeleteCriticalSection(&(mutex->cs));
opj_free(mutex);
}
struct opj_cond_waiter_list_t {
HANDLE hEvent;
struct opj_cond_waiter_list_t* next;
};
typedef struct opj_cond_waiter_list_t opj_cond_waiter_list_t;
struct opj_cond_t {
opj_mutex_t *internal_mutex;
opj_cond_waiter_list_t *waiter_list;
};
static DWORD TLSKey = 0;
static volatile LONG inTLSLockedSection = 0;
static volatile int TLSKeyInit = OPJ_FALSE;
opj_cond_t* opj_cond_create(void)
{
opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
if (!cond) {
return NULL;
}
while (OPJ_TRUE) {
#if HAVE_INTERLOCKED_COMPARE_EXCHANGE
if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
#endif
{
if (!TLSKeyInit) {
TLSKey = TlsAlloc();
TLSKeyInit = OPJ_TRUE;
}
#if HAVE_INTERLOCKED_COMPARE_EXCHANGE
InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
#endif
break;
}
}
if (TLSKey == TLS_OUT_OF_INDEXES) {
opj_free(cond);
return NULL;
}
cond->internal_mutex = opj_mutex_create();
if (cond->internal_mutex == NULL) {
opj_free(cond);
return NULL;
}
cond->waiter_list = NULL;
return cond;
}
void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
{
opj_cond_waiter_list_t* item;
HANDLE hEvent = (HANDLE) TlsGetValue(TLSKey);
if (hEvent == NULL) {
hEvent = CreateEvent(NULL,
0,
0,
NULL );
assert(hEvent);
TlsSetValue(TLSKey, hEvent);
}
opj_mutex_lock(cond->internal_mutex);
item = (opj_cond_waiter_list_t*)opj_malloc(sizeof(opj_cond_waiter_list_t));
assert(item != NULL);
item->hEvent = hEvent;
item->next = cond->waiter_list;
cond->waiter_list = item;
opj_mutex_unlock(cond->internal_mutex);
opj_mutex_unlock(mutex);
WaitForSingleObject(hEvent, INFINITE);
opj_mutex_lock(mutex);
}
void opj_cond_signal(opj_cond_t* cond)
{
opj_cond_waiter_list_t* psIter;
opj_mutex_lock(cond->internal_mutex);
psIter = cond->waiter_list;
if (psIter != NULL) {
SetEvent(psIter->hEvent);
cond->waiter_list = psIter->next;
opj_free(psIter);
}
opj_mutex_unlock(cond->internal_mutex);
}
void opj_cond_destroy(opj_cond_t* cond)
{
if (!cond) {
return;
}
opj_mutex_destroy(cond->internal_mutex);
assert(cond->waiter_list == NULL);
opj_free(cond);
}
struct opj_thread_t {
opj_thread_fn thread_fn;
void* user_data;
HANDLE hThread;
};
static unsigned int __stdcall opj_thread_callback_adapter(void *info)
{
opj_thread_t* thread = (opj_thread_t*) info;
HANDLE hEvent = NULL;
thread->thread_fn(thread->user_data);
while (OPJ_TRUE) {
#if HAVE_INTERLOCKED_COMPARE_EXCHANGE
if (InterlockedCompareExchange(&inTLSLockedSection, 1, 0) == 0)
#endif
{
if (TLSKeyInit) {
hEvent = (HANDLE) TlsGetValue(TLSKey);
}
#if HAVE_INTERLOCKED_COMPARE_EXCHANGE
InterlockedCompareExchange(&inTLSLockedSection, 0, 1);
#endif
break;
}
}
if (hEvent) {
CloseHandle(hEvent);
}
return 0;
}
opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
{
opj_thread_t* thread;
assert(thread_fn);
thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
if (!thread) {
return NULL;
}
thread->thread_fn = thread_fn;
thread->user_data = user_data;
thread->hThread = (HANDLE)_beginthreadex(NULL, 0,
opj_thread_callback_adapter, thread, 0, NULL);
if (thread->hThread == NULL) {
opj_free(thread);
return NULL;
}
return thread;
}
void opj_thread_join(opj_thread_t* thread)
{
WaitForSingleObject(thread->hThread, INFINITE);
CloseHandle(thread->hThread);
opj_free(thread);
}
#elif MUTEX_pthread
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include "opj_includes.h"
OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
{
return OPJ_TRUE;
}
int OPJ_CALLCONV opj_get_num_cpus(void)
{
#ifdef _SC_NPROCESSORS_ONLN
return (int)sysconf(_SC_NPROCESSORS_ONLN);
#else
return 1;
#endif
}
struct opj_mutex_t {
pthread_mutex_t mutex;
};
opj_mutex_t* opj_mutex_create(void)
{
opj_mutex_t* mutex = (opj_mutex_t*) opj_calloc(1U, sizeof(opj_mutex_t));
if (mutex != NULL) {
if (pthread_mutex_init(&mutex->mutex, NULL) != 0) {
opj_free(mutex);
mutex = NULL;
}
}
return mutex;
}
void opj_mutex_lock(opj_mutex_t* mutex)
{
pthread_mutex_lock(&(mutex->mutex));
}
void opj_mutex_unlock(opj_mutex_t* mutex)
{
pthread_mutex_unlock(&(mutex->mutex));
}
void opj_mutex_destroy(opj_mutex_t* mutex)
{
if (!mutex) {
return;
}
pthread_mutex_destroy(&(mutex->mutex));
opj_free(mutex);
}
struct opj_cond_t {
pthread_cond_t cond;
};
opj_cond_t* opj_cond_create(void)
{
opj_cond_t* cond = (opj_cond_t*) opj_malloc(sizeof(opj_cond_t));
if (!cond) {
return NULL;
}
if (pthread_cond_init(&(cond->cond), NULL) != 0) {
opj_free(cond);
return NULL;
}
return cond;
}
void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
{
pthread_cond_wait(&(cond->cond), &(mutex->mutex));
}
void opj_cond_signal(opj_cond_t* cond)
{
int ret = pthread_cond_signal(&(cond->cond));
(void)ret;
assert(ret == 0);
}
void opj_cond_destroy(opj_cond_t* cond)
{
if (!cond) {
return;
}
pthread_cond_destroy(&(cond->cond));
opj_free(cond);
}
struct opj_thread_t {
opj_thread_fn thread_fn;
void* user_data;
pthread_t thread;
};
static void* opj_thread_callback_adapter(void* info)
{
opj_thread_t* thread = (opj_thread_t*) info;
thread->thread_fn(thread->user_data);
return NULL;
}
opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
{
pthread_attr_t attr;
opj_thread_t* thread;
assert(thread_fn);
thread = (opj_thread_t*) opj_malloc(sizeof(opj_thread_t));
if (!thread) {
return NULL;
}
thread->thread_fn = thread_fn;
thread->user_data = user_data;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (pthread_create(&(thread->thread), &attr,
opj_thread_callback_adapter, (void *) thread) != 0) {
opj_free(thread);
return NULL;
}
return thread;
}
void opj_thread_join(opj_thread_t* thread)
{
void* status;
pthread_join(thread->thread, &status);
opj_free(thread);
}
#else
#include "opj_includes.h"
OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void)
{ … }
int OPJ_CALLCONV opj_get_num_cpus(void)
{ … }
opj_mutex_t* opj_mutex_create(void)
{ … }
void opj_mutex_lock(opj_mutex_t* mutex)
{ … }
void opj_mutex_unlock(opj_mutex_t* mutex)
{ … }
void opj_mutex_destroy(opj_mutex_t* mutex)
{ … }
opj_cond_t* opj_cond_create(void)
{ … }
void opj_cond_wait(opj_cond_t* cond, opj_mutex_t* mutex)
{ … }
void opj_cond_signal(opj_cond_t* cond)
{ … }
void opj_cond_destroy(opj_cond_t* cond)
{ … }
opj_thread_t* opj_thread_create(opj_thread_fn thread_fn, void* user_data)
{ … }
void opj_thread_join(opj_thread_t* thread)
{ … }
#endif
opj_tls_key_val_t;
struct opj_tls_t { … };
static opj_tls_t* opj_tls_new(void)
{ … }
static void opj_tls_destroy(opj_tls_t* tls)
{ … }
void* opj_tls_get(opj_tls_t* tls, int key)
{ … }
OPJ_BOOL opj_tls_set(opj_tls_t* tls, int key, void* value,
opj_tls_free_func opj_free_func)
{ … }
opj_worker_thread_job_t;
opj_worker_thread_t;
opj_worker_thread_state;
struct opj_job_list_t { … };
opj_job_list_t;
struct opj_worker_thread_list_t { … };
opj_worker_thread_list_t;
struct opj_thread_pool_t { … };
static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads);
static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
opj_thread_pool_t* tp,
opj_worker_thread_t* worker_thread,
OPJ_BOOL signal_job_finished);
opj_thread_pool_t* opj_thread_pool_create(int num_threads)
{ … }
static void opj_worker_thread_function(void* user_data)
{ … }
static OPJ_BOOL opj_thread_pool_setup(opj_thread_pool_t* tp, int num_threads)
{ … }
static opj_worker_thread_job_t* opj_thread_pool_get_next_job(
opj_thread_pool_t* tp,
opj_worker_thread_t* worker_thread,
OPJ_BOOL signal_job_finished)
{ … }
OPJ_BOOL opj_thread_pool_submit_job(opj_thread_pool_t* tp,
opj_job_fn job_fn,
void* user_data)
{ … }
void opj_thread_pool_wait_completion(opj_thread_pool_t* tp,
int max_remaining_jobs)
{ … }
int opj_thread_pool_get_thread_count(opj_thread_pool_t* tp)
{ … }
void opj_thread_pool_destroy(opj_thread_pool_t* tp)
{ … }