summaryrefslogtreecommitdiffstats
path: root/openmp/offload/src/orsl-lite/lib/orsl-lite.c
diff options
context:
space:
mode:
Diffstat (limited to 'openmp/offload/src/orsl-lite/lib/orsl-lite.c')
-rw-r--r--openmp/offload/src/orsl-lite/lib/orsl-lite.c337
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: */
OpenPOWER on IntegriCloud