diff options
Diffstat (limited to 'openmp/offload/src/orsl-lite/lib/orsl-lite.c')
-rw-r--r-- | openmp/offload/src/orsl-lite/lib/orsl-lite.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/openmp/offload/src/orsl-lite/lib/orsl-lite.c b/openmp/offload/src/orsl-lite/lib/orsl-lite.c new file mode 100644 index 00000000000..221cda7130a --- /dev/null +++ b/openmp/offload/src/orsl-lite/lib/orsl-lite.c @@ -0,0 +1,337 @@ +//===----------------------------------------------------------------------===// +// +// 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: */ |