Parallelize
This commit is contained in:
+353
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "sync.h"
|
||||
#include "clock.h"
|
||||
|
||||
//#define SYNC_PRINT_ERRORS
|
||||
#ifdef SYNC_PRINT_ERRORS
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
PROFILE_GLOBAL_START;
|
||||
|
||||
void os_mutex_create(os_mutex_t *mutex)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
InitializeCriticalSection(mutex);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_mutex_init(mutex, NULL))
|
||||
abort();
|
||||
#else
|
||||
(void) mutex;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void os_mutex_delete(os_mutex_t *mutex)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
DeleteCriticalSection(mutex);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
abort();
|
||||
#else
|
||||
(void) mutex;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void os_mutex_lock(os_mutex_t *mutex)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
EnterCriticalSection(mutex);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_mutex_lock(mutex))
|
||||
abort();
|
||||
#else
|
||||
(void) mutex;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void os_mutex_unlock(os_mutex_t *mutex)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
LeaveCriticalSection(mutex);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_mutex_unlock(mutex))
|
||||
abort();
|
||||
#else
|
||||
(void) mutex;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void os_condvar_create(os_condvar_t *condvar)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
InitializeConditionVariable(condvar);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_cond_init(condvar, NULL))
|
||||
abort();
|
||||
#else
|
||||
(void) condvar;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void os_condvar_delete(os_condvar_t *condvar)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(__linux__)
|
||||
if (pthread_cond_destroy(condvar))
|
||||
abort();
|
||||
#else
|
||||
(void) condvar;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
bool os_condvar_wait(os_condvar_t *condvar, os_mutex_t *mutex, int timeout_ms)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
DWORD timeout = INFINITE;
|
||||
if (timeout_ms >= 0) timeout = timeout_ms;
|
||||
if (!SleepConditionVariableCS(condvar, mutex, timeout)) {
|
||||
if (GetLastError() == ERROR_TIMEOUT) {
|
||||
PROFILE_END;
|
||||
return false;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
PROFILE_END;
|
||||
return true;
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
int err;
|
||||
if (timeout_ms < 0)
|
||||
err = pthread_cond_wait(condvar, mutex);
|
||||
else {
|
||||
uint64_t wakeup_ms = (uint64_t) timeout_ms + get_absolute_time_us() / 1000;
|
||||
struct timespec abstime = {
|
||||
.tv_sec = wakeup_ms / 1000,
|
||||
.tv_nsec = (wakeup_ms % 1000) * 1000000,
|
||||
};
|
||||
err = pthread_cond_timedwait(condvar, mutex, &abstime);
|
||||
}
|
||||
if (err) {
|
||||
if (err == ETIMEDOUT) {
|
||||
PROFILE_END;
|
||||
return false;
|
||||
}
|
||||
#ifdef SYNC_PRINT_ERRORS
|
||||
fprintf(stderr, "ERROR!! pthread_cond_wait/timedwait: %s\n", strerror(err));
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
PROFILE_END;
|
||||
return true;
|
||||
|
||||
#else
|
||||
PROFILE_END;
|
||||
(void) condvar;
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_condvar_signal(os_condvar_t *condvar)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
#if defined(_WIN32)
|
||||
WakeConditionVariable(condvar);
|
||||
#elif defined(__linux__)
|
||||
if (pthread_cond_signal(condvar))
|
||||
abort();
|
||||
#else
|
||||
(void) condvar;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void semaphore_create(semaphore_t *sem, int count)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
sem->count = count;
|
||||
os_mutex_create(&sem->mutex);
|
||||
os_condvar_create(&sem->cond);
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
void semaphore_delete(semaphore_t *sem)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
os_mutex_delete(&sem->mutex);
|
||||
os_condvar_delete(&sem->cond);
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
bool semaphore_wait(semaphore_t *sem, int count, int timeout_ms)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
assert(count > 0);
|
||||
|
||||
uint64_t start_time_ms = get_relative_time_ns() / 1000000;
|
||||
|
||||
os_mutex_lock(&sem->mutex);
|
||||
while (sem->count < count) {
|
||||
|
||||
uint64_t current_time_ms = get_relative_time_ns() / 1000000;
|
||||
|
||||
int remaining_ms = -1;
|
||||
if (timeout_ms >= 0)
|
||||
remaining_ms = timeout_ms - (int) (current_time_ms - start_time_ms);
|
||||
|
||||
if (!os_condvar_wait(&sem->cond, &sem->mutex, remaining_ms)) {
|
||||
os_mutex_unlock(&sem->mutex);
|
||||
PROFILE_END;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sem->count -= count;
|
||||
os_mutex_unlock(&sem->mutex);
|
||||
|
||||
PROFILE_END;
|
||||
return true;
|
||||
}
|
||||
|
||||
void semaphore_signal(semaphore_t *sem, int count)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
assert(count > 0);
|
||||
|
||||
os_mutex_lock(&sem->mutex);
|
||||
sem->count += count;
|
||||
if (sem->count > 0)
|
||||
os_condvar_signal(&sem->cond);
|
||||
os_mutex_unlock(&sem->mutex);
|
||||
|
||||
PROFILE_END;
|
||||
}
|
||||
|
||||
bool os_semaphore_create(os_semaphore_t *sem, int count, int max)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
int ok;
|
||||
|
||||
#ifdef _WIN32
|
||||
SECURITY_ATTRIBUTES *attr = NULL; // Default
|
||||
const char *name = NULL; // No name
|
||||
void *handle = CreateSemaphoreA(attr, count, max, name);
|
||||
if (handle == NULL) {
|
||||
PROFILE_END;
|
||||
return false;
|
||||
}
|
||||
sem->data = handle;
|
||||
ok = 1;
|
||||
#else
|
||||
(void) max; // POSIX doesn't use this
|
||||
ok = sem_init(&sem->data, 0, count) == 0;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool os_semaphore_delete(os_semaphore_t *sem)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
int ok;
|
||||
|
||||
#ifdef _WIN32
|
||||
CloseHandle(sem->data);
|
||||
ok = 1;
|
||||
#else
|
||||
ok = sem_destroy(&sem->data) == 0;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool os_semaphore_wait(os_semaphore_t *sem)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
int ok;
|
||||
|
||||
#ifdef _WIN32
|
||||
ok = WaitForSingleObject(sem->data, INFINITE) == WAIT_OBJECT_0;
|
||||
#else
|
||||
ok = sem_wait(&sem->data) == 0;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool os_semaphore_signal(os_semaphore_t *sem)
|
||||
{
|
||||
PROFILE_START;
|
||||
|
||||
int ok;
|
||||
|
||||
#ifdef _WIN32
|
||||
ok = ReleaseSemaphore(sem->data, 1, NULL);
|
||||
#else
|
||||
ok = sem_post(&sem->data) == 0;
|
||||
#endif
|
||||
|
||||
PROFILE_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
PROFILE_GLOBAL_END;
|
||||
|
||||
profile_results_t sync_profile_results(void)
|
||||
{
|
||||
return PROFILE_RESULTS;
|
||||
}
|
||||
Reference in New Issue
Block a user