Parallelize

This commit is contained in:
2024-09-17 11:10:09 +02:00
parent 72091042bb
commit cdbe010679
10 changed files with 963 additions and 51 deletions
+353
View File
@@ -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;
}