blob: 221cda7130ada082f9fc041c9c64e19bba7ba4e4 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "orsl-lite/include/orsl-lite.h"
#define DISABLE_SYMBOL_VERSIONING
#if defined(__linux__) && !defined(DISABLE_SYMBOL_VERSIONING)
#define symver(src, tgt, verstr) __asm__(".symver " #src "," #tgt verstr)
symver(ORSLReserve0, ORSLReserve, "@@ORSL_0.0");
symver(ORSLTryReserve0, ORSLTryReserve, "@@ORSL_0.0");
symver(ORSLReservePartial0, ORSLReservePartial, "@@ORSL_0.0");
symver(ORSLRelease0, ORSLRelease, "@@ORSL_0.0");
#else
#define ORSLReserve0 ORSLReserve
#define ORSLTryReserve0 ORSLTryReserve
#define ORSLReservePartial0 ORSLReservePartial
#define ORSLRelease0 ORSLRelease
#endif
#ifdef __linux__
#include <pthread.h>
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t release_cond = PTHREAD_COND_INITIALIZER;
#endif
#ifdef _WIN32
#include <windows.h>
#pragma intrinsic(_ReadWriteBarrier)
static SRWLOCK global_mutex = SRWLOCK_INIT;
static volatile int release_cond_initialized = 0;
static CONDITION_VARIABLE release_cond;
static void state_lazy_init_sync()
{
if (!release_cond_initialized) {
AcquireSRWLockExclusive(&global_mutex);
_ReadWriteBarrier();
if (!release_cond_initialized) {
InitializeConditionVariable(&release_cond);
release_cond_initialized = 1;
}
ReleaseSRWLockExclusive(&global_mutex);
}
}
#endif
static int state_lock()
{
#ifdef __linux__
return pthread_mutex_lock(&global_mutex);
#endif
#ifdef _WIN32
AcquireSRWLockExclusive(&global_mutex);
return 0;
#endif
}
static int state_unlock()
{
#ifdef __linux__
return pthread_mutex_unlock(&global_mutex);
#endif
#ifdef _WIN32
ReleaseSRWLockExclusive(&global_mutex);
return 0;
#endif
}
static int state_wait_for_release()
{
#ifdef __linux__
return pthread_cond_wait(&release_cond, &global_mutex);
#endif
#ifdef _WIN32
return SleepConditionVariableSRW(&release_cond,
&global_mutex, INFINITE, 0) == 0 ? 1 : 0;
#endif
}
static int state_signal_release()
{
#ifdef __linux__
return pthread_cond_signal(&release_cond);
#endif
#ifdef _WIN32
WakeConditionVariable(&release_cond);
return 0;
#endif
}
static struct {
char owner[ORSL_MAX_TAG_LEN + 1];
unsigned long rsrv_cnt;
} rsrv_data[ORSL_MAX_CARDS];
static int check_args(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i;
int card_specified[ORSL_MAX_CARDS];
if (tag == NULL) return -1;
if (strlen((char *)tag) > ORSL_MAX_TAG_LEN) return -1;
if (n < 0 || n >= ORSL_MAX_CARDS) return -1;
if (n != 0 && (inds == NULL || bsets == NULL)) return -1;
for (i = 0; i < ORSL_MAX_CARDS; i++)
card_specified[i] = 0;
for (i = 0; i < n; i++) {
int ind = inds[i];
if (ind < 0 || ind >= ORSL_MAX_CARDS) return -1;
if (card_specified[ind]) return -1;
card_specified[ind] = 1;
}
return 0;
}
static int check_bsets(const int n, const ORSLBusySet *bsets)
{
int i;
for (i = 0; i < n; i++)
if (bsets[i].type == BUSY_SET_PARTIAL) return -1;
return 0;
}
static int can_reserve_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
return (bset->type == BUSY_SET_EMPTY ||
((rsrv_data[card].rsrv_cnt == 0 ||
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0) &&
rsrv_data[card].rsrv_cnt < ULONG_MAX)) ? 0 : - 1;
}
static void reserve_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
if (bset->type == BUSY_SET_EMPTY)
return;
assert(rsrv_data[card].rsrv_cnt == 0 ||
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
assert(rsrv_data[card].rsrv_cnt < ULONG_MAX);
if (rsrv_data[card].rsrv_cnt == 0)
strncpy(rsrv_data[card].owner, (char *)tag, ORSL_MAX_TAG_LEN);
rsrv_data[card].owner[ORSL_MAX_TAG_LEN] = '\0';
rsrv_data[card].rsrv_cnt++;
}
static int can_release_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
return (bset->type == BUSY_SET_EMPTY || (rsrv_data[card].rsrv_cnt > 0 &&
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0)) ? 0 : 1;
}
static void release_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
if (bset->type == BUSY_SET_EMPTY)
return;
assert(strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
assert(rsrv_data[card].rsrv_cnt > 0);
rsrv_data[card].rsrv_cnt--;
}
int ORSLReserve0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, ok;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Loop until we find that all the resources we want are available */
do {
ok = 1;
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
ok = 0;
/* Wait for someone to release some resources */
state_wait_for_release();
break;
}
} while (!ok);
/* At this point we are good to reserve_card the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
state_unlock();
return 0;
}
int ORSLTryReserve0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, rc = EBUSY;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check resource availability once */
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0)
goto bail_out;
/* At this point we are good to reserve the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
rc = 0;
bail_out:
state_unlock();
return rc;
}
int ORSLReservePartial0(const ORSLPartialGranularity gran, const int n,
const int *__restrict inds, ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int rc = EBUSY;
int i, num_avail = n;
if (n == 0) return 0;
if (gran != GRAN_CARD && gran != GRAN_THREAD) return EINVAL;
if (gran != GRAN_CARD) return EINVAL;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check resource availability once; remove unavailable resources from the
* user-provided list */
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
num_avail--;
bsets[i].type = BUSY_SET_EMPTY;
}
if (num_avail == 0)
goto bail_out;
/* At this point we are good to reserve the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
rc = 0;
bail_out:
state_unlock();
return rc;
}
int ORSLRelease0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, rc = EPERM;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check that we can release all the resources */
for (i = 0; i < n; i++)
if (can_release_card(inds[i], &bsets[i], tag) != 0)
goto bail_out;
/* At this point we are good to release the resources we want */
for (i = 0; i < n; i++)
release_card(inds[i], &bsets[i], tag);
state_signal_release();
rc = 0;
bail_out:
state_unlock();
return rc;
}
/* vim:set et: */