chromium/third_party/pdfium/third_party/libopenjpeg/thread.c

/*
 * The copyright in this software is being made available under the 2-clauses
 * BSD License, included below. This software may be subject to other third
 * party and contributor rights, including patent rights, and no such rights
 * are granted under this license.
 *
 * Copyright (c) 2016, Even Rouault
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <assert.h>

#ifdef MUTEX_win32

/* Some versions of x86_64-w64-mingw32-gc -m32 resolve InterlockedCompareExchange() */
/* as __sync_val_compare_and_swap_4 but fails to link it. As this protects against */
/* a rather unlikely race, skip it */
#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;
    }

    /* Make sure that the TLS key is allocated in a thread-safe way */
    /* We cannot use a global mutex/critical section since its creation itself would not be */
    /* thread-safe, so use InterlockedCompareExchange trick */
    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, /* security attributes */
                             0,    /* manual reset = no */
                             0,    /* initial state = unsignaled */
                             NULL  /* no name */);
        assert(hEvent);

        TlsSetValue(TLSKey, hEvent);
    }

    /* Insert the waiter into the waiter list of the condition */
    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);

    /* Release the client mutex before waiting for the event being signaled */
    opj_mutex_unlock(mutex);

    /* Ideally we would check that we do not get WAIT_FAILED but it is hard */
    /* to report a failure. */
    WaitForSingleObject(hEvent, INFINITE);

    /* Reacquire the client mutex */
    opj_mutex_lock(mutex);
}

void opj_cond_signal(opj_cond_t* cond)
{
    opj_cond_waiter_list_t* psIter;

    /* Signal the first registered event, and remove it from the list */
    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);

    /* Free the handle possible allocated by a cond */
    while (OPJ_TRUE) {
        /* Make sure TLSKey is not being created just at that moment... */
#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>

/* Moved after all system includes, and in particular pthread.h, so as to */
/* avoid poisoning issuing with malloc() use in pthread.h with ulibc (#1013) */
#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
/* Stub implementation */

#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)
{}

/*
void opj_waiting()
{
    printf("waiting!\n");
}
*/

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)
{}