Small ChangeLog tweak.
[official-gcc.git] / liboffloadmic / runtime / orsl-lite / lib / orsl-lite.c
blob669c40a13584dcbf4cb662a5ffcf09dc3d04317c
1 /*
2 Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved.
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of Intel Corporation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <errno.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <assert.h>
36 #include "orsl-lite/include/orsl-lite.h"
38 #define DISABLE_SYMBOL_VERSIONING
40 #if defined(__linux__) && !defined(DISABLE_SYMBOL_VERSIONING)
41 #define symver(src, tgt, verstr) __asm__(".symver " #src "," #tgt verstr)
42 symver(ORSLReserve0, ORSLReserve, "@@ORSL_0.0");
43 symver(ORSLTryReserve0, ORSLTryReserve, "@@ORSL_0.0");
44 symver(ORSLReservePartial0, ORSLReservePartial, "@@ORSL_0.0");
45 symver(ORSLRelease0, ORSLRelease, "@@ORSL_0.0");
46 #else
47 #define ORSLReserve0 ORSLReserve
48 #define ORSLTryReserve0 ORSLTryReserve
49 #define ORSLReservePartial0 ORSLReservePartial
50 #define ORSLRelease0 ORSLRelease
51 #endif
53 #ifdef __linux__
54 #include <pthread.h>
55 static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
56 static pthread_cond_t release_cond = PTHREAD_COND_INITIALIZER;
57 #endif
59 #ifdef _WIN32
60 #include <windows.h>
61 #pragma intrinsic(_ReadWriteBarrier)
62 static SRWLOCK global_mutex = SRWLOCK_INIT;
63 static volatile int release_cond_initialized = 0;
64 static CONDITION_VARIABLE release_cond;
66 static void state_lazy_init_sync()
68 if (!release_cond_initialized) {
69 AcquireSRWLockExclusive(&global_mutex);
70 _ReadWriteBarrier();
71 if (!release_cond_initialized) {
72 InitializeConditionVariable(&release_cond);
73 release_cond_initialized = 1;
75 ReleaseSRWLockExclusive(&global_mutex);
78 #endif
80 static int state_lock()
82 #ifdef __linux__
83 return pthread_mutex_lock(&global_mutex);
84 #endif
86 #ifdef _WIN32
87 AcquireSRWLockExclusive(&global_mutex);
88 return 0;
89 #endif
92 static int state_unlock()
94 #ifdef __linux__
95 return pthread_mutex_unlock(&global_mutex);
96 #endif
98 #ifdef _WIN32
99 ReleaseSRWLockExclusive(&global_mutex);
100 return 0;
101 #endif
104 static int state_wait_for_release()
106 #ifdef __linux__
107 return pthread_cond_wait(&release_cond, &global_mutex);
108 #endif
110 #ifdef _WIN32
111 return SleepConditionVariableSRW(&release_cond,
112 &global_mutex, INFINITE, 0) == 0 ? 1 : 0;
113 #endif
116 static int state_signal_release()
118 #ifdef __linux__
119 return pthread_cond_signal(&release_cond);
120 #endif
122 #ifdef _WIN32
123 WakeConditionVariable(&release_cond);
124 return 0;
125 #endif
128 static struct {
129 char owner[ORSL_MAX_TAG_LEN + 1];
130 unsigned long rsrv_cnt;
131 } rsrv_data[ORSL_MAX_CARDS];
133 static int check_args(const int n, const int *__restrict inds,
134 const ORSLBusySet *__restrict bsets,
135 const ORSLTag __restrict tag)
137 int i;
138 int card_specified[ORSL_MAX_CARDS];
139 if (tag == NULL) return -1;
140 if (strlen((char *)tag) > ORSL_MAX_TAG_LEN) return -1;
141 if (n < 0 || n >= ORSL_MAX_CARDS) return -1;
142 if (n != 0 && (inds == NULL || bsets == NULL)) return -1;
143 for (i = 0; i < ORSL_MAX_CARDS; i++)
144 card_specified[i] = 0;
145 for (i = 0; i < n; i++) {
146 int ind = inds[i];
147 if (ind < 0 || ind >= ORSL_MAX_CARDS) return -1;
148 if (card_specified[ind]) return -1;
149 card_specified[ind] = 1;
151 return 0;
154 static int check_bsets(const int n, const ORSLBusySet *bsets)
156 int i;
157 for (i = 0; i < n; i++)
158 if (bsets[i].type == BUSY_SET_PARTIAL) return -1;
159 return 0;
162 static int can_reserve_card(int card, const ORSLBusySet *__restrict bset,
163 const ORSLTag __restrict tag)
165 assert(tag != NULL);
166 assert(bset != NULL);
167 assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
168 assert(bset->type != BUSY_SET_PARTIAL);
170 return (bset->type == BUSY_SET_EMPTY ||
171 ((rsrv_data[card].rsrv_cnt == 0 ||
172 strncmp((char *)tag,
173 rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0) &&
174 rsrv_data[card].rsrv_cnt < ULONG_MAX)) ? 0 : - 1;
177 static void reserve_card(int card, const ORSLBusySet *__restrict bset,
178 const ORSLTag __restrict tag)
180 assert(tag != NULL);
181 assert(bset != NULL);
182 assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
183 assert(bset->type != BUSY_SET_PARTIAL);
185 if (bset->type == BUSY_SET_EMPTY)
186 return;
188 assert(rsrv_data[card].rsrv_cnt == 0 ||
189 strncmp((char *)tag,
190 rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
191 assert(rsrv_data[card].rsrv_cnt < ULONG_MAX);
193 if (rsrv_data[card].rsrv_cnt == 0)
194 strncpy(rsrv_data[card].owner, (char *)tag, ORSL_MAX_TAG_LEN);
195 rsrv_data[card].owner[ORSL_MAX_TAG_LEN] = '\0';
196 rsrv_data[card].rsrv_cnt++;
199 static int can_release_card(int card, const ORSLBusySet *__restrict bset,
200 const ORSLTag __restrict tag)
202 assert(tag != NULL);
203 assert(bset != NULL);
204 assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
205 assert(bset->type != BUSY_SET_PARTIAL);
207 return (bset->type == BUSY_SET_EMPTY || (rsrv_data[card].rsrv_cnt > 0 &&
208 strncmp((char *)tag,
209 rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0)) ? 0 : 1;
212 static void release_card(int card, const ORSLBusySet *__restrict bset,
213 const ORSLTag __restrict tag)
215 assert(tag != NULL);
216 assert(bset != NULL);
217 assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
218 assert(bset->type != BUSY_SET_PARTIAL);
220 if (bset->type == BUSY_SET_EMPTY)
221 return;
223 assert(strncmp((char *)tag,
224 rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
225 assert(rsrv_data[card].rsrv_cnt > 0);
227 rsrv_data[card].rsrv_cnt--;
230 int ORSLReserve0(const int n, const int *__restrict inds,
231 const ORSLBusySet *__restrict bsets,
232 const ORSLTag __restrict tag)
234 int i, ok;
236 if (n == 0) return 0;
237 if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
238 if (check_bsets(n, bsets) != 0) return ENOSYS;
240 state_lock();
242 /* Loop until we find that all the resources we want are available */
243 do {
244 ok = 1;
245 for (i = 0; i < n; i++)
246 if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
247 ok = 0;
248 /* Wait for someone to release some resources */
249 state_wait_for_release();
250 break;
252 } while (!ok);
254 /* At this point we are good to reserve_card the resources we want */
255 for (i = 0; i < n; i++)
256 reserve_card(inds[i], &bsets[i], tag);
258 state_unlock();
259 return 0;
262 int ORSLTryReserve0(const int n, const int *__restrict inds,
263 const ORSLBusySet *__restrict bsets,
264 const ORSLTag __restrict tag)
266 int i, rc = EBUSY;
268 if (n == 0) return 0;
269 if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
270 if (check_bsets(n, bsets) != 0) return ENOSYS;
272 state_lock();
274 /* Check resource availability once */
275 for (i = 0; i < n; i++)
276 if (can_reserve_card(inds[i], &bsets[i], tag) != 0)
277 goto bail_out;
279 /* At this point we are good to reserve the resources we want */
280 for (i = 0; i < n; i++)
281 reserve_card(inds[i], &bsets[i], tag);
283 rc = 0;
285 bail_out:
286 state_unlock();
287 return rc;
290 int ORSLReservePartial0(const ORSLPartialGranularity gran, const int n,
291 const int *__restrict inds, ORSLBusySet *__restrict bsets,
292 const ORSLTag __restrict tag)
294 int rc = EBUSY;
295 int i, num_avail = n;
297 if (n == 0) return 0;
298 if (gran != GRAN_CARD && gran != GRAN_THREAD) return EINVAL;
299 if (gran != GRAN_CARD) return EINVAL;
300 if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
301 if (check_bsets(n, bsets) != 0) return ENOSYS;
303 state_lock();
305 /* Check resource availability once; remove unavailable resources from the
306 * user-provided list */
307 for (i = 0; i < n; i++)
308 if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
309 num_avail--;
310 bsets[i].type = BUSY_SET_EMPTY;
313 if (num_avail == 0)
314 goto bail_out;
316 /* At this point we are good to reserve the resources we want */
317 for (i = 0; i < n; i++)
318 reserve_card(inds[i], &bsets[i], tag);
320 rc = 0;
322 bail_out:
323 state_unlock();
324 return rc;
327 int ORSLRelease0(const int n, const int *__restrict inds,
328 const ORSLBusySet *__restrict bsets,
329 const ORSLTag __restrict tag)
331 int i, rc = EPERM;
333 if (n == 0) return 0;
334 if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
335 if (check_bsets(n, bsets) != 0) return ENOSYS;
337 state_lock();
339 /* Check that we can release all the resources */
340 for (i = 0; i < n; i++)
341 if (can_release_card(inds[i], &bsets[i], tag) != 0)
342 goto bail_out;
344 /* At this point we are good to release the resources we want */
345 for (i = 0; i < n; i++)
346 release_card(inds[i], &bsets[i], tag);
348 state_signal_release();
350 rc = 0;
352 bail_out:
353 state_unlock();
354 return rc;
357 /* vim:set et: */