]> git.ipfire.org Git - thirdparty/gcc.git/blame - liboffloadmic/runtime/emulator/coi_host.cpp
libgcc: Special-case BFD ld unwind table encodings in find_fde_tail
[thirdparty/gcc.git] / liboffloadmic / runtime / emulator / coi_host.cpp
CommitLineData
5f520819 1/*
df26a50d 2 Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved.
5f520819
KY
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7
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.
16
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.
28*/
29
44799f87
IV
30#include <set>
31#include <map>
32#include <queue>
33
5f520819
KY
34#include "coi_host.h"
35
36#include "coi_version_asm.h"
37
38#define CYCLE_FREQUENCY 1000000000
39
44799f87 40enum buffer_t
5f520819
KY
41{
42 BUFFER_NORMAL,
43 BUFFER_MEMORY
44799f87 44};
5f520819 45
44799f87 46struct Engine
5f520819
KY
47{
48 COI_ISA_TYPE type;
49 uint32_t index;
50 char *dir;
44799f87 51};
5f520819 52
44799f87 53struct Function
5f520819 54{
5f520819 55 void *ptr;
44799f87
IV
56 uint32_t num_buffers;
57 uint64_t *bufs_size;
58 void * *bufs_data_target;
59 uint16_t misc_data_len;
60 void *misc_data;
61 uint16_t return_value_len;
62 void *return_value;
63 COIEVENT completion_event;
64};
65
66struct Callback
5f520819 67{
44799f87
IV
68 COI_EVENT_CALLBACK ptr;
69 const void *data;
70};
5f520819 71
44799f87 72struct Process
5f520819
KY
73{
74 pid_t pid;
44799f87
IV
75 int pipe_host2tgt;
76 int pipe_tgt2host;
5f520819 77 Engine *engine;
44799f87
IV
78 void **functions;
79};
5f520819 80
44799f87
IV
81struct Pipeline
82{
83 pthread_t thread;
84 bool destroy;
85 bool is_destroyed;
86 char *pipe_host2tgt_path;
87 char *pipe_tgt2host_path;
88 int pipe_host2tgt;
89 int pipe_tgt2host;
90 std::queue<Function> queue;
91 Process *process;
92};
93
94struct Buffer
5f520819
KY
95{
96 buffer_t type;
97 char *name;
98 int fd;
99 int fd_target;
100 uint64_t size;
101 void *data;
102 void *data_target;
103 Process *process;
44799f87
IV
104};
105
106
107/* Environment variables. */
108extern char **environ;
109
110/* List of directories for removing on exit. */
111static char **tmp_dirs;
112static unsigned tmp_dirs_num;
113
114/* Number of emulated MIC engines. */
115static long num_engines;
116
117/* Number of the last COI pipeline. */
118static uint32_t max_pipeline_num;
119
120/* Set of undestroyed pipelines. */
121static std::set<Pipeline *> pipelines;
122
123/* Number of the last COI event, the event #0 is always signalled. */
124static uint64_t max_event_num = 1;
125
126/* Set of created COI events, which are not signalled. */
127static std::set<uint64_t> non_signalled_events;
128
129/* Set of COI events, which encountered errors. */
130static std::map<uint64_t, COIRESULT> errored_events;
131
132/* Set of registered callbacks, indexed by event number. */
133static std::map<uint64_t, Callback> callbacks;
134
135/* Mutex to sync parallel execution. */
136static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
5f520819
KY
137
138
139static COIRESULT
140read_long_env (const char *env_name, long *var, long var_default)
141{
142 char *str = getenv (env_name);
143 char *s;
144
145 if (!str || *str == '\0')
146 *var = var_default;
147 else
148 {
149 errno = 0;
150 *var = strtol (str, &s, 0);
151 if (errno != 0 || s == str || *s != '\0')
152 COIERROR ("Variable %s has invalid value.", env_name);
153 }
154
155 return COI_SUCCESS;
156}
157
158__attribute__((constructor))
159static void
160init ()
161{
2eab9666 162 if (read_long_env (OFFLOAD_EMUL_NUM_ENV, &num_engines, 1) == COI_ERROR)
5f520819
KY
163 exit (0);
164}
165
166
167/* Helper function for directory removing. */
168static COIRESULT remove_directory (char *path)
169{
170 char *file;
171 struct dirent *entry;
172 struct stat statfile;
173 DIR *dir = opendir (path);
174 if (dir == NULL)
175 COIERROR ("Cannot open directory %s.", dir);
176
177 while (entry = readdir (dir))
178 {
179 if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
180 continue;
181
182 MALLOC (char *, file, strlen (path) + strlen (entry->d_name) + 2);
183 sprintf (file, "%s/%s", path, entry->d_name);
184
185 if (stat (file, &statfile) < 0)
186 COIERROR ("Cannot retrieve information about file %s.", file);
187
188 if (S_ISDIR (statfile.st_mode))
189 {
190 if (remove_directory (file) == COI_ERROR)
191 return COI_ERROR;
192 }
193 else
194 {
195 if (unlink (file) < 0)
196 COIERROR ("Cannot unlink file %s.", file);
197 }
198
199 free (file);
200 }
201
202 if (closedir (dir) < 0)
203 COIERROR ("Cannot close directory %s.", path);
204 if (rmdir (path) < 0)
205 COIERROR ("Cannot remove directory %s.", path);
206
207 return COI_SUCCESS;
208}
209
210__attribute__((destructor))
211static void
212cleanup ()
213{
44799f87 214 for (unsigned i = 0; i < tmp_dirs_num; i++)
5f520819
KY
215 {
216 remove_directory (tmp_dirs[i]);
217 free (tmp_dirs[i]);
218 }
44799f87
IV
219 free (tmp_dirs);
220}
221
222static COIRESULT
223start_critical_section ()
224{
225 if (pthread_mutex_lock (&mutex) != 0)
226 COIERROR ("Cannot lock mutex.");
227 return COI_SUCCESS;
228}
229
230static COIRESULT
231finish_critical_section ()
232{
233 if (pthread_mutex_unlock (&mutex) != 0)
234 COIERROR ("Cannot unlock mutex.");
235 return COI_SUCCESS;
236}
237
238static bool
239pipeline_is_destroyed (const Pipeline *pipeline)
240{
241 start_critical_section ();
242 bool res = pipeline->is_destroyed;
243 finish_critical_section ();
244 return res;
245}
246
247static void
248maybe_invoke_callback (const COIEVENT event, const COIRESULT result)
249{
250 std::map<uint64_t, Callback>::iterator cb = callbacks.find (event.opaque[0]);
251
252 if (cb != callbacks.end ())
253 {
254 Callback callback = cb->second;
255 callback.ptr (event, result, callback.data);
256 callbacks.erase (cb);
257 }
258}
259
260static void
261signal_event (const COIEVENT event, const COIRESULT result)
262{
263 if (result != COI_SUCCESS)
264 errored_events.insert (std::pair <uint64_t, COIRESULT> (event.opaque[0],
265 result));
266 non_signalled_events.erase (event.opaque[0]);
267
268 maybe_invoke_callback (event, result);
269}
270
271static COIRESULT
272get_event_result (const COIEVENT event)
273{
274 COIRESULT res = COI_SUCCESS;
275
276 std::map<uint64_t, COIRESULT>::iterator ee
277 = errored_events.find (event.opaque[0]);
278
279 if (ee != errored_events.end ())
280 res = ee->second;
281
282 return res;
5f520819
KY
283}
284
285
286extern "C"
287{
288
289COIRESULT
44799f87
IV
290SYMBOL_VERSION (COIBufferCopy, 1) (COIBUFFER in_DestBuffer,
291 COIBUFFER in_SourceBuffer,
292 uint64_t in_DestOffset,
293 uint64_t in_SourceOffset,
294 uint64_t in_Length,
295 COI_COPY_TYPE in_Type,
296 uint32_t in_NumDependencies,
297 const COIEVENT *in_pDependencies, // Ignored
298 COIEVENT *out_pCompletion)
5f520819
KY
299{
300 COITRACE ("COIBufferCopy");
301
44799f87
IV
302 /* Features of liboffloadmic. */
303 assert (in_DestBuffer != NULL);
304 assert (in_SourceBuffer != NULL);
305 assert (in_Type == COI_COPY_UNSPECIFIED);
306 assert (in_NumDependencies == 0);
307
5f520819 308 /* Convert input arguments. */
44799f87
IV
309 Buffer *dest = (Buffer *) in_DestBuffer;
310 Buffer *source = (Buffer *) in_SourceBuffer;
5f520819 311
44799f87 312 start_critical_section ();
5f520819
KY
313
314 /* Map buffers if needed. */
315 if (dest->data == 0 && dest->type == BUFFER_NORMAL)
44799f87 316 if (COIBufferMap (in_DestBuffer, 0, dest->size, (COI_MAP_TYPE) 0,
5f520819
KY
317 0, 0, 0, 0, 0) == COI_ERROR)
318 return COI_ERROR;
319 if (source->data == 0 && source->type == BUFFER_NORMAL)
44799f87 320 if (COIBufferMap (in_SourceBuffer, 0, source->size, (COI_MAP_TYPE) 0,
5f520819
KY
321 0, 0, 0, 0, 0) == COI_ERROR)
322 return COI_ERROR;
323
324 /* Copy data. */
325 if (source->data != 0 && dest->data != 0)
44799f87
IV
326 memcpy ((void *) ((uintptr_t) dest->data + in_DestOffset),
327 (void *) ((uintptr_t) source->data + in_SourceOffset), in_Length);
5f520819
KY
328 else
329 {
330 assert (dest->process == source->process);
331
332 Buffer *buffer;
333 cmd_t cmd = CMD_BUFFER_COPY;
5f520819
KY
334
335 /* Create intermediary buffer. */
44799f87 336 if (COIBufferCreate (in_Length, COI_BUFFER_NORMAL, 0, 0, 1,
5f520819
KY
337 (COIPROCESS*) &dest->process,
338 (COIBUFFER *) &buffer) == COI_ERROR)
339 return COI_ERROR;
340
44799f87
IV
341 int pipe_host2tgt = dest->process->pipe_host2tgt;
342 int pipe_tgt2host = dest->process->pipe_tgt2host;
343
5f520819
KY
344 /* Copy from source to intermediary buffer. */
345 if (source->data == 0)
346 {
347 assert (source->data_target != 0);
348
349 /* Send data to target. */
44799f87
IV
350 WRITE (pipe_host2tgt, &cmd, sizeof (cmd_t));
351 WRITE (pipe_host2tgt, &buffer->data_target, sizeof (void *));
352 WRITE (pipe_host2tgt, &source->data_target, sizeof (void *));
353 WRITE (pipe_host2tgt, &buffer->size, sizeof (uint64_t));
5f520819 354
44799f87
IV
355 /* Receive data from target. */
356 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
5f520819
KY
357 }
358 else
359 {
44799f87
IV
360 if (COIBufferCopy ((COIBUFFER) buffer, in_SourceBuffer, 0,
361 in_SourceOffset, in_Length, in_Type, 0, 0, 0)
362 == COI_ERROR)
5f520819
KY
363 return COI_ERROR;
364 }
365
366 /* Copy from intermediary buffer to dest. */
367 if (dest->data == 0)
368 {
369 assert (dest->data_target != 0);
370
371 /* Send data to target. */
44799f87
IV
372 WRITE (pipe_host2tgt, &cmd, sizeof (cmd_t));
373 WRITE (pipe_host2tgt, &dest->data_target, sizeof (void *));
374 WRITE (pipe_host2tgt, &buffer->data_target, sizeof (void *));
375 WRITE (pipe_host2tgt, &buffer->size, sizeof (uint64_t));
5f520819 376
44799f87
IV
377 /* Receive data from target. */
378 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
5f520819
KY
379 }
380 else
381 {
44799f87
IV
382 if (COIBufferCopy (in_DestBuffer, (COIBUFFER) buffer, in_DestOffset,
383 0, in_Length, in_Type, 0, 0, 0) == COI_ERROR)
5f520819
KY
384 return COI_ERROR;
385 }
386
387 /* Unmap on target and destroy intermediary buffer. */
388 if (COIBufferDestroy ((COIBUFFER) buffer) == COI_ERROR)
389 return COI_ERROR;
390 }
391
392 /* Unmap buffers if needed. */
393 if (dest->type == BUFFER_NORMAL)
394 if (COIBufferUnmap ((COIMAPINSTANCE) dest, 0, 0, 0) == COI_ERROR)
395 return COI_ERROR;
396 if (source->type == BUFFER_NORMAL)
397 if (COIBufferUnmap ((COIMAPINSTANCE) source, 0, 0, 0) == COI_ERROR)
398 return COI_ERROR;
399
44799f87
IV
400 finish_critical_section ();
401
402 if (out_pCompletion)
403 out_pCompletion->opaque[0] = 0;
5f520819
KY
404
405 return COI_SUCCESS;
406}
407
408
409COIRESULT
44799f87
IV
410SYMBOL_VERSION (COIBufferCreate, 1) (uint64_t in_Size,
411 COI_BUFFER_TYPE in_Type,
412 uint32_t in_Flags,
413 const void *in_pInitData,
414 uint32_t in_NumProcesses,
415 const COIPROCESS *in_pProcesses,
416 COIBUFFER *out_pBuffer)
5f520819
KY
417{
418 COITRACE ("COIBufferCreate");
419
420 char *shm_name;
5f520819
KY
421 int shm_fd;
422 const int ullong_max_len = 20;
5f520819 423
44799f87 424 /* Features of liboffloadmic. */
df26a50d 425 assert (in_Type == COI_BUFFER_NORMAL || in_Type == COI_BUFFER_OPENCL);
44799f87
IV
426 assert ((in_Flags & COI_SINK_MEMORY) == 0);
427 assert ((in_Flags & COI_SAME_ADDRESS_SINKS) == 0);
428 assert ((in_Flags & COI_SAME_ADDRESS_SINKS_AND_SOURCE) == 0);
429 assert (in_pInitData == NULL);
430 assert (in_NumProcesses == 1);
431 assert (in_pProcesses != NULL);
432 assert (out_pBuffer != NULL);
5f520819
KY
433
434 /* Create shared memory with an unique name. */
435 MALLOC (char *, shm_name, strlen (SHM_NAME) + ullong_max_len + 1);
44799f87 436 for (unsigned long long i = 0; i >= 0; i++)
5f520819 437 {
44799f87 438 sprintf (shm_name, SHM_NAME "%lu", i);
5f520819
KY
439 shm_fd = shm_open (shm_name, O_CLOEXEC | O_CREAT | O_EXCL | O_RDWR,
440 S_IRUSR | S_IWUSR);
441 if (shm_fd > 0)
442 break;
443 }
44799f87 444 if (ftruncate (shm_fd, in_Size) < 0)
5f520819
KY
445 COIERROR ("Cannot truncate shared memory file.");
446
447 /* Create buffer. */
44799f87 448 Buffer *buf = new Buffer;
5f520819
KY
449 buf->data = 0;
450 buf->fd = shm_fd;
44799f87
IV
451 buf->process = (Process *) in_pProcesses[0];
452 buf->size = in_Size;
5f520819
KY
453 buf->type = BUFFER_NORMAL;
454 STRDUP (buf->name, shm_name);
455
456 /* Map buffer on target. */
44799f87 457 size_t len = strlen (buf->name) + 1;
5f520819 458
44799f87 459 start_critical_section ();
5f520819
KY
460
461 /* Send data to target. */
44799f87
IV
462 const cmd_t cmd = CMD_BUFFER_MAP;
463 int pipe_host2tgt = buf->process->pipe_host2tgt;
464 WRITE (pipe_host2tgt, &cmd, sizeof (cmd_t));
465 WRITE (pipe_host2tgt, &len, sizeof (size_t));
466 WRITE (pipe_host2tgt, buf->name, len);
467 WRITE (pipe_host2tgt, &buf->size, sizeof (uint64_t));
5f520819 468
44799f87
IV
469 /* Receive data from target. */
470 int pipe_tgt2host = buf->process->pipe_tgt2host;
471 READ (pipe_tgt2host, &buf->fd_target, sizeof (int));
472 READ (pipe_tgt2host, &buf->data_target, sizeof (void *));
5f520819 473
44799f87 474 finish_critical_section ();
5f520819
KY
475
476 /* Prepare output arguments. */
44799f87 477 *out_pBuffer = (COIBUFFER) buf;
5f520819
KY
478
479 /* Clean up. */
480 free (shm_name);
481
482 return COI_SUCCESS;
483}
484
485
486COIRESULT
44799f87
IV
487SYMBOL_VERSION (COIBufferCreateFromMemory, 1) (uint64_t in_Size,
488 COI_BUFFER_TYPE in_Type,
489 uint32_t in_Flags,
490 void *in_Memory,
491 uint32_t in_NumProcesses,
492 const COIPROCESS *in_pProcesses,
493 COIBUFFER *out_pBuffer)
5f520819
KY
494{
495 COITRACE ("COIBufferCreateFromMemory");
496
44799f87
IV
497 /* Features of liboffloadmic. */
498 assert (in_Type == COI_BUFFER_NORMAL);
499 assert ((in_Flags & COI_SAME_ADDRESS_SINKS) == 0);
500 assert ((in_Flags & COI_SAME_ADDRESS_SINKS_AND_SOURCE) == 0);
501 assert (in_NumProcesses == 1);
502 assert (in_pProcesses != NULL);
503 assert (out_pBuffer != NULL);
5f520819
KY
504
505 /* Create buffer. */
44799f87
IV
506 Buffer *buf = new Buffer;
507 buf->data = (in_Flags & COI_SINK_MEMORY) == 0 ? in_Memory : 0;
508 buf->data_target = (in_Flags & COI_SINK_MEMORY) != 0 ? in_Memory : 0;
509 buf->process = (Process *) in_pProcesses[0];
510 buf->size = in_Size;
5f520819
KY
511 buf->type = BUFFER_MEMORY;
512
513 /* Prepare output argument. */
44799f87 514 *out_pBuffer = (COIBUFFER) buf;
5f520819
KY
515
516 return COI_SUCCESS;
517}
518
519
520COIRESULT
44799f87 521SYMBOL_VERSION (COIBufferDestroy, 1) (COIBUFFER in_Buffer)
5f520819
KY
522{
523 COITRACE ("COIBufferDestroy");
524
525 cmd_t cmd = CMD_BUFFER_UNMAP;
526
44799f87
IV
527 assert (in_Buffer != NULL);
528
5f520819 529 /* Convert input arguments. */
44799f87 530 Buffer *buf = (Buffer *) in_Buffer;
5f520819
KY
531
532 /* Unmap buffer on host. */
533 if (buf->data != 0 && buf->type == BUFFER_NORMAL)
44799f87 534 if (COIBufferUnmap ((COIMAPINSTANCE) in_Buffer, 0, 0, 0) == COI_ERROR)
5f520819
KY
535 return COI_ERROR;
536
537 /* Unmap buffer on target. */
538 if (buf->data_target != 0)
539 {
44799f87 540 start_critical_section ();
5f520819
KY
541
542 /* Send data to target. */
44799f87
IV
543 int pipe_host2tgt = buf->process->pipe_host2tgt;
544 WRITE (pipe_host2tgt, &cmd, sizeof (cmd_t));
545 WRITE (pipe_host2tgt, &buf->fd_target, sizeof (int));
546 WRITE (pipe_host2tgt, &buf->data_target, sizeof (void *));
547 WRITE (pipe_host2tgt, &buf->size, sizeof (uint64_t));
5f520819 548
44799f87
IV
549 /* Receive data from target. */
550 READ (buf->process->pipe_tgt2host, &cmd, sizeof (cmd_t));
5f520819 551
44799f87 552 finish_critical_section ();
5f520819
KY
553 }
554
555 /* Unlink shared memory. */
556 if (buf->type == BUFFER_NORMAL)
557 {
558 if (close (buf->fd) < 0)
559 COIERROR ("Cannot close shared memory file.");
560 if (shm_unlink (buf->name) < 0)
561 COIERROR ("Cannot unlink shared memory.");
562 free (buf->name);
563 }
564
565 /* Clean up. */
44799f87 566 delete buf;
5f520819
KY
567
568 return COI_SUCCESS;
569}
570
571
572COIRESULT
44799f87
IV
573SYMBOL_VERSION (COIBufferGetSinkAddress, 1) (COIBUFFER in_Buffer,
574 uint64_t *out_pAddress)
5f520819
KY
575{
576 COITRACE ("COIBufferGetSinkAddress");
577
44799f87
IV
578 assert (in_Buffer != NULL);
579 assert (out_pAddress != NULL);
580
5f520819 581 /* Convert input arguments. */
44799f87 582 Buffer *buf = (Buffer *) in_Buffer;
5f520819
KY
583
584 /* Here should come BUFFER_NORMAL buffer. */
585 assert (buf->type == BUFFER_NORMAL);
586
587 /* Prepare output argument. */
44799f87 588 *out_pAddress = (uint64_t) buf->data_target;
5f520819
KY
589
590 return COI_SUCCESS;
591}
592
593
594COIRESULT
44799f87
IV
595SYMBOL_VERSION (COIBufferMap, 1) (COIBUFFER in_Buffer,
596 uint64_t in_Offset,
597 uint64_t in_Length, // Ignored
598 COI_MAP_TYPE in_Type, // Ignored
599 uint32_t in_NumDependencies,
600 const COIEVENT *in_pDependencies, // Ignored
601 COIEVENT *out_pCompletion,
602 COIMAPINSTANCE *out_pMapInstance,
603 void **out_ppData)
5f520819
KY
604{
605 COITRACE ("COIBufferMap");
606
44799f87
IV
607 /* Features of liboffloadmic. */
608 assert (in_Offset == 0);
609 assert (in_NumDependencies == 0);
5f520819
KY
610
611 /* Convert input arguments. */
44799f87 612 Buffer *buf = (Buffer *) in_Buffer;
5f520819
KY
613
614 /* Only BUFFER_NORMAL buffers should come here. */
615 assert (buf->type == BUFFER_NORMAL);
616
617 /* Map shared memory. */
618 buf->data = mmap (NULL, buf->size, PROT_READ | PROT_WRITE,
619 MAP_SHARED, buf->fd, 0);
620 if (buf->data == NULL)
621 COIERROR ("Cannot map shared memory.");
622
623 /* Prepare output arguments. */
44799f87
IV
624 if (out_pMapInstance != 0)
625 *out_pMapInstance = (COIMAPINSTANCE) buf;
626 if (out_ppData != 0)
627 *out_ppData = buf->data;
628
629 if (out_pCompletion)
630 out_pCompletion->opaque[0] = 0;
5f520819
KY
631
632 return COI_SUCCESS;
633}
634
635
636COIRESULT
44799f87
IV
637SYMBOL_VERSION (COIBufferRead, 1) (COIBUFFER in_SourceBuffer,
638 uint64_t in_Offset,
639 void *in_pDestData,
640 uint64_t in_Length,
641 COI_COPY_TYPE in_Type,
642 uint32_t in_NumDependencies,
643 const COIEVENT *in_pDependencies, // Ignored
644 COIEVENT *out_pCompletion)
5f520819
KY
645{
646 COITRACE ("COIBufferRead");
647
44799f87
IV
648 /* Features of liboffloadmic. */
649 assert (in_pDestData != NULL);
650 assert (in_Type == COI_COPY_UNSPECIFIED);
651 assert (in_NumDependencies == 0);
5f520819 652
44799f87
IV
653 /* Convert input arguments. */
654 Buffer *buf = (Buffer *) in_SourceBuffer;
5f520819 655
44799f87 656 start_critical_section ();
5f520819
KY
657
658 /* Map buffers if needed. */
659 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
44799f87
IV
660 if (COIBufferMap (in_SourceBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0,
661 0, 0) == COI_ERROR)
5f520819
KY
662 return COI_ERROR;
663
664 /* Copy data. */
44799f87
IV
665 memcpy (in_pDestData, (void *) ((uintptr_t) buf->data + in_Offset),
666 in_Length);
5f520819
KY
667
668 /* Unmap buffers if needed. */
669 if (buf->type == BUFFER_NORMAL)
670 if (COIBufferUnmap ((COIMAPINSTANCE) buf, 0, 0, 0) == COI_ERROR)
671 return COI_ERROR;
672
44799f87
IV
673 finish_critical_section ();
674
675 if (out_pCompletion)
676 out_pCompletion->opaque[0] = 0;
5f520819
KY
677
678 return COI_SUCCESS;
679}
680
681
682COIRESULT
44799f87
IV
683SYMBOL_VERSION (COIBufferSetState, 1) (COIBUFFER in_Buffer, // Ignored
684 COIPROCESS in_Process, // Ignored
685 COI_BUFFER_STATE in_State, // Ignored
686 COI_BUFFER_MOVE_FLAG in_DataMove,
687 uint32_t in_NumDependencies,
688 const COIEVENT *in_pDependencies, // Ignored
689 COIEVENT *out_pCompletion)
5f520819
KY
690{
691 COITRACE ("COIBufferSetState");
692
44799f87
IV
693 /* Features of liboffloadmic. */
694 assert (in_DataMove == COI_BUFFER_NO_MOVE);
695 assert (in_NumDependencies == 0);
5f520819
KY
696
697 /* Looks like we have nothing to do here. */
698
44799f87
IV
699 if (out_pCompletion)
700 out_pCompletion->opaque[0] = 0;
701
5f520819
KY
702 return COI_SUCCESS;
703}
704
705
706COIRESULT
44799f87
IV
707SYMBOL_VERSION (COIBufferUnmap, 1) (COIMAPINSTANCE in_MapInstance,
708 uint32_t in_NumDependencies,
709 const COIEVENT *in_pDependencies, // Ignored
710 COIEVENT *out_pCompletion)
5f520819
KY
711{
712 COITRACE ("COIBufferUnmap");
713
44799f87
IV
714 /* Features of liboffloadmic. */
715 assert (in_MapInstance != NULL);
716 assert (in_NumDependencies == 0);
717
5f520819 718 /* Convert input arguments. */
44799f87 719 Buffer *buffer = (Buffer *) in_MapInstance;
5f520819
KY
720
721 /* Only BUFFER_NORMAL buffers should come here. */
722 assert (buffer->type == BUFFER_NORMAL);
723
724 /* Unmap shared memory. */
725 if (munmap (buffer->data, buffer->size) < 0)
726 COIERROR ("Cannot unmap shared memory.");
727
728 buffer->data = 0;
729
44799f87
IV
730 if (out_pCompletion)
731 out_pCompletion->opaque[0] = 0;
732
5f520819
KY
733 return COI_SUCCESS;
734}
735
736
737COIRESULT
44799f87
IV
738SYMBOL_VERSION (COIBufferWrite, 1) (COIBUFFER in_DestBuffer,
739 uint64_t in_Offset,
740 const void *in_pSourceData,
741 uint64_t in_Length,
742 COI_COPY_TYPE in_Type,
743 uint32_t in_NumDependencies,
744 const COIEVENT *in_pDependencies, // Ignored
745 COIEVENT *out_pCompletion)
5f520819
KY
746{
747 COITRACE ("COIBufferWrite");
748
44799f87
IV
749 /* Features of liboffloadmic. */
750 assert (in_DestBuffer != NULL);
751 assert (in_pSourceData != NULL);
752 assert (in_Type == COI_COPY_UNSPECIFIED);
753 assert (in_NumDependencies == 0);
754
5f520819 755 /* Convert input arguments. */
44799f87 756 Buffer *buf = (Buffer *) in_DestBuffer;
5f520819 757
44799f87 758 start_critical_section ();
5f520819
KY
759
760 /* Map buffers if needed. */
761 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
44799f87
IV
762 if (COIBufferMap (in_DestBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0, 0,
763 0) == COI_ERROR)
5f520819
KY
764 return COI_ERROR;
765
766 /* Copy data. */
44799f87
IV
767 memcpy ((void *) ((uintptr_t) buf->data + in_Offset), in_pSourceData,
768 in_Length);
5f520819
KY
769
770 /* Unmap buffers if needed. */
771 if (buf->type == BUFFER_NORMAL)
772 if (COIBufferUnmap ((COIMAPINSTANCE) buf, 0, 0, 0) == COI_ERROR)
773 return COI_ERROR;
774
44799f87
IV
775 finish_critical_section ();
776
777 if (out_pCompletion)
778 out_pCompletion->opaque[0] = 0;
5f520819
KY
779
780 return COI_SUCCESS;
781}
782
783
784COIRESULT
785SYMBOL_VERSION (COIEngineGetCount, 1) (COI_ISA_TYPE isa,
786 uint32_t *count)
787{
788 COITRACE ("COIEngineGetCount");
789
44799f87 790 /* Features of liboffloadmic. */
2eab9666 791 assert (isa == COI_ISA_MIC);
44799f87 792 assert (count != NULL);
5f520819
KY
793
794 /* Prepare output arguments. */
2eab9666 795 *count = num_engines;
5f520819
KY
796
797 return COI_SUCCESS;
798}
799
800
801COIRESULT
44799f87
IV
802SYMBOL_VERSION (COIEngineGetHandle, 1) (COI_ISA_TYPE in_ISA,
803 uint32_t in_EngineIndex,
804 COIENGINE *out_pEngineHandle)
5f520819
KY
805{
806 COITRACE ("COIEngineGetHandle");
807
44799f87
IV
808 /* Features of liboffloadmic. */
809 assert (in_ISA == COI_ISA_MIC);
810 assert (out_pEngineHandle != NULL);
5f520819
KY
811
812 /* Check engine index. */
44799f87 813 if (in_EngineIndex >= num_engines)
5f520819
KY
814 COIERROR ("Wrong engine index.");
815
816 /* Create engine handle. */
44799f87 817 Engine *engine = new Engine;
5f520819 818 engine->dir = NULL;
44799f87
IV
819 engine->index = in_EngineIndex;
820 engine->type = in_ISA;
5f520819
KY
821
822 /* Prepare output argument. */
44799f87 823 *out_pEngineHandle = (COIENGINE) engine;
5f520819
KY
824
825 return COI_SUCCESS;
826}
827
828
829COIRESULT
44799f87
IV
830SYMBOL_VERSION (COIEventWait, 1) (uint16_t in_NumEvents,
831 const COIEVENT *in_pEvents,
832 int32_t in_TimeoutMilliseconds,
833 uint8_t in_WaitForAll,
834 uint32_t *out_pNumSignaled,
835 uint32_t *out_pSignaledIndices)
5f520819
KY
836{
837 COITRACE ("COIEventWait");
838
44799f87
IV
839 /* Features of liboffloadmic. */
840 assert (in_pEvents != NULL);
841 assert (in_TimeoutMilliseconds == 0 || in_TimeoutMilliseconds == -1);
842 assert (in_WaitForAll == 1);
843 assert (out_pNumSignaled == NULL);
844 assert (out_pSignaledIndices == NULL);
5f520819 845
44799f87
IV
846 if (in_TimeoutMilliseconds == 0)
847 {
848 /* If some event is not signalled, return timeout error. */
849 for (uint16_t i = 0; i < in_NumEvents; i++)
850 if (non_signalled_events.count (in_pEvents[i].opaque[0]) > 0)
851 return COI_TIME_OUT_REACHED;
852 else
853 {
854 /* If the event signalled with an error, return that error. */
855 start_critical_section ();
856 COIRESULT res = get_event_result (in_pEvents[i]);
857 finish_critical_section ();
858 if (res != COI_SUCCESS)
859 return res;
860 }
861 }
862 else
863 {
864 /* Wait indefinitely for all events. */
865 for (uint16_t i = 0; i < in_NumEvents; i++)
866 {
867 while (non_signalled_events.count (in_pEvents[i].opaque[0]) > 0)
868 usleep (1000);
869
870 /* If the event signalled with an error, return that error. */
871 start_critical_section ();
872 COIRESULT res = get_event_result (in_pEvents[i]);
873 finish_critical_section ();
874 if (res != COI_SUCCESS)
875 return res;
876 }
877 }
5f520819
KY
878
879 return COI_SUCCESS;
880}
881
882
883COIRESULT
44799f87
IV
884SYMBOL_VERSION (COIEventRegisterCallback, 1) (const COIEVENT in_Event,
885 COI_EVENT_CALLBACK in_Callback,
886 const void *in_UserData,
887 const uint64_t in_Flags)
5f520819 888{
44799f87 889 COITRACE ("COIEventRegisterCallback");
5f520819 890
44799f87
IV
891 /* Features of liboffloadmic. */
892 assert (in_Callback != NULL);
893 assert (in_UserData != NULL);
894 assert (in_Flags == 0);
5f520819 895
44799f87
IV
896 start_critical_section ();
897 if (non_signalled_events.count (in_Event.opaque[0]) == 0)
898 {
899 /* If the event is already signalled, invoke the callback immediately. */
900 COIRESULT res = get_event_result (in_Event);
901 in_Callback (in_Event, res, in_UserData);
902 }
903 else
904 {
905 Callback callback;
906 callback.ptr = in_Callback;
907 callback.data = in_UserData;
908 callbacks.insert (std::pair <uint64_t, Callback> (in_Event.opaque[0],
909 callback));
910 }
911 finish_critical_section ();
5f520819
KY
912
913 return COI_SUCCESS;
914}
915
916
44799f87
IV
917/* The start routine for the COI pipeline thread. */
918
919static void *
920pipeline_thread_routine (void *in_Pipeline)
921{
922 /* Convert input arguments. */
923 Pipeline *pipeline = (Pipeline *) in_Pipeline;
924
925 /* Open pipes. */
926 pipeline->pipe_host2tgt
927 = open (pipeline->pipe_host2tgt_path, O_CLOEXEC | O_WRONLY);
928 if (pipeline->pipe_host2tgt < 0)
929 COIERRORN ("Cannot open host-to-target pipe.");
930 pipeline->pipe_tgt2host
931 = open (pipeline->pipe_tgt2host_path, O_CLOEXEC | O_RDONLY);
932 if (pipeline->pipe_tgt2host < 0)
933 COIERRORN ("Cannot open target-to-host pipe.");
934
935 free (pipeline->pipe_host2tgt_path);
936 free (pipeline->pipe_tgt2host_path);
937 pipeline->pipe_host2tgt_path = NULL;
938 pipeline->pipe_tgt2host_path = NULL;
939
940 while (!pipeline->destroy)
941 if (pipeline->queue.empty ())
942 usleep (1000);
943 else
944 {
945 Function func = pipeline->queue.front ();
946 start_critical_section ();
947 pipeline->queue.pop ();
948 finish_critical_section ();
949
950 /* Send data to target. */
951 cmd_t cmd = CMD_PIPELINE_RUN_FUNCTION;
952 WRITEN (pipeline->pipe_host2tgt, &cmd, sizeof (cmd_t));
953 WRITEN (pipeline->pipe_host2tgt, &func.ptr, sizeof (void *));
954 WRITEN (pipeline->pipe_host2tgt, &func.num_buffers, sizeof (uint32_t));
955 for (uint32_t i = 0; i < func.num_buffers; i++)
956 {
957 WRITEN (pipeline->pipe_host2tgt, &func.bufs_size[i],
958 sizeof (uint64_t));
959 WRITEN (pipeline->pipe_host2tgt, &func.bufs_data_target[i],
960 sizeof (void *));
961 }
962 WRITEN (pipeline->pipe_host2tgt, &func.misc_data_len,
963 sizeof (uint16_t));
964 if (func.misc_data_len > 0)
965 WRITEN (pipeline->pipe_host2tgt, func.misc_data, func.misc_data_len);
966 WRITEN (pipeline->pipe_host2tgt, &func.return_value_len,
967 sizeof (uint16_t));
968
969 delete [] func.bufs_size;
970 delete [] func.bufs_data_target;
971
972 /* Receive data from target. Wait for target function to complete,
973 whether it has any data to return or not. */
974 bool has_return_value = func.return_value_len > 0;
975 int ret_len
976 = read (pipeline->pipe_tgt2host,
977 has_return_value ? func.return_value : &cmd,
978 has_return_value ? func.return_value_len : sizeof (cmd_t));
979 if (ret_len == 0)
980 {
981 start_critical_section ();
982 signal_event (func.completion_event, COI_PROCESS_DIED);
983 pipeline->is_destroyed = true;
984 finish_critical_section ();
985 return NULL;
986 }
987 else if (ret_len != (has_return_value ? func.return_value_len
988 : sizeof (cmd_t)))
989 COIERRORN ("Cannot read from pipe.");
990
991 start_critical_section ();
992 signal_event (func.completion_event, COI_SUCCESS);
993 finish_critical_section ();
994 }
995
996 /* Send data to target. */
997 const cmd_t cmd = CMD_PIPELINE_DESTROY;
998 WRITEN (pipeline->pipe_host2tgt, &cmd, sizeof (cmd_t));
999
1000 /* Close pipes. */
1001 if (close (pipeline->pipe_host2tgt) < 0)
1002 COIERRORN ("Cannot close host-to-target pipe.");
1003 if (close (pipeline->pipe_tgt2host) < 0)
1004 COIERRORN ("Cannot close target-to-host pipe.");
1005
1006 start_critical_section ();
1007 pipeline->is_destroyed = true;
1008 finish_critical_section ();
1009 return NULL;
1010}
1011
1012
5f520819 1013COIRESULT
44799f87
IV
1014SYMBOL_VERSION (COIPipelineCreate, 1) (COIPROCESS in_Process,
1015 COI_CPU_MASK in_Mask,
1016 uint32_t in_StackSize, // Ignored
1017 COIPIPELINE *out_pPipeline)
5f520819 1018{
44799f87
IV
1019 COITRACE ("COIPipelineCreate");
1020
1021 /* Features of liboffloadmic. */
1022 assert (in_Process != NULL);
1023 assert (in_Mask == 0);
1024 assert (out_pPipeline != NULL);
1025
1026 /* Convert input arguments. */
1027 Process *proc = (Process *) in_Process;
1028
1029 start_critical_section ();
1030
1031 /* Create pipeline handle. */
1032 Pipeline *pipeline = new Pipeline;
1033 pipeline->destroy = false;
1034 pipeline->is_destroyed = false;
1035 pipeline->process = proc;
1036 pipelines.insert (pipeline);
1037
1038 /* Create pipes. */
1039 uint32_t pipeline_num = max_pipeline_num++;
1040 char *eng_dir = pipeline->process->engine->dir;
1041 MALLOC (char *, pipeline->pipe_host2tgt_path,
1042 strlen (eng_dir) + sizeof (PIPE_HOST2TGT_NAME "0000000000"));
1043 MALLOC (char *, pipeline->pipe_tgt2host_path,
1044 strlen (eng_dir) + sizeof (PIPE_TGT2HOST_NAME "0000000000"));
1045 sprintf (pipeline->pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "%010d",
1046 eng_dir, pipeline_num);
1047 sprintf (pipeline->pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "%010d",
1048 eng_dir, pipeline_num);
1049 if (mkfifo (pipeline->pipe_host2tgt_path, S_IRUSR | S_IWUSR) < 0)
1050 COIERROR ("Cannot create pipe %s.", pipeline->pipe_host2tgt_path);
1051 if (mkfifo (pipeline->pipe_tgt2host_path, S_IRUSR | S_IWUSR) < 0)
1052 COIERROR ("Cannot create pipe %s.", pipeline->pipe_tgt2host_path);
5f520819 1053
44799f87
IV
1054 /* Send data to target. */
1055 const cmd_t cmd = CMD_PIPELINE_CREATE;
1056 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1057 WRITE (proc->pipe_host2tgt, &pipeline_num, sizeof (pipeline_num));
1058
1059 /* Create a new thread for the pipeline. */
1060 if (pthread_create (&pipeline->thread, NULL, pipeline_thread_routine,
1061 pipeline))
1062 COIERROR ("Cannot create new thread.");
1063
1064 finish_critical_section ();
1065
1066 /* Prepare output arguments. */
1067 *out_pPipeline = (COIPIPELINE) pipeline;
5f520819
KY
1068
1069 return COI_SUCCESS;
1070}
1071
1072
1073COIRESULT
44799f87 1074SYMBOL_VERSION (COIPipelineDestroy, 1) (COIPIPELINE in_Pipeline)
5f520819 1075{
44799f87 1076 COITRACE ("COIPipelineDestroy");
5f520819 1077
44799f87 1078 assert (in_Pipeline != NULL);
5f520819
KY
1079
1080 /* Convert input arguments. */
44799f87 1081 Pipeline *pipeline = (Pipeline *) in_Pipeline;
5f520819 1082
44799f87
IV
1083 start_critical_section ();
1084 /* Remove pipeline from the set of undestroyed pipelines. */
1085 pipelines.erase (pipeline);
5f520819 1086
44799f87
IV
1087 /* Exit pipeline thread. */
1088 pipeline->destroy = true;
1089 finish_critical_section ();
1090
1091 while (!pipeline_is_destroyed (pipeline))
1092 usleep (1000);
1093
1094 /* Join with a destroyed thread. */
1095 if (pthread_join (pipeline->thread, NULL))
1096 COIERROR ("Cannot join with a thread.");
1097
1098 delete pipeline;
1099
1100 return COI_SUCCESS;
1101}
1102
1103
1104COIRESULT
1105SYMBOL_VERSION (COIPipelineRunFunction, 1) (COIPIPELINE in_Pipeline,
1106 COIFUNCTION in_Function,
1107 uint32_t in_NumBuffers,
1108 const COIBUFFER *in_Buffers,
1109 const COI_ACCESS_FLAGS *in_pBufferAccessFlags, // Ignored
1110 uint32_t in_NumDependencies,
1111 const COIEVENT *in_pDependencies, // Ignored
1112 const void *in_pMiscData,
1113 uint16_t in_MiscDataLen,
1114 void *out_pAsyncReturnValue,
1115 uint16_t in_AsyncReturnValueLen,
1116 COIEVENT *out_pCompletion)
1117{
1118 COITRACE ("COIPipelineRunFunction");
1119
1120 /* Features of liboffloadmic. */
1121 assert (in_Pipeline != NULL);
1122 assert (in_Function != NULL);
1123 assert (in_NumDependencies == 0);
1124
1125 Function func;
1126 func.ptr = (void *) in_Function;
1127 func.num_buffers = in_NumBuffers;
1128 func.bufs_size = new uint64_t [in_NumBuffers];
1129 func.bufs_data_target = new void * [in_NumBuffers];
1130 for (uint32_t i = 0; i < in_NumBuffers; i++)
5f520819 1131 {
44799f87
IV
1132 Buffer **bufs = (Buffer **) in_Buffers;
1133 func.bufs_size[i] = bufs[i]->size;
1134 func.bufs_data_target[i] = bufs[i]->data_target;
5f520819 1135 }
44799f87
IV
1136 func.misc_data = (void *) in_pMiscData;
1137 func.misc_data_len = in_MiscDataLen;
1138 func.return_value = out_pAsyncReturnValue;
1139 func.return_value_len = in_AsyncReturnValueLen;
1140
1141 start_critical_section ();
1142 func.completion_event.opaque[0] = max_event_num++;
1143 non_signalled_events.insert (func.completion_event.opaque[0]);
1144 ((Pipeline *) in_Pipeline)->queue.push (func);
1145 finish_critical_section ();
1146
1147 /* In case of synchronous execution we have to wait for target. */
1148 if (out_pCompletion == NULL)
1149 COIEventWait (1, &func.completion_event, -1, 1, NULL, NULL);
1150 else
1151 *out_pCompletion = func.completion_event;
5f520819
KY
1152
1153 return COI_SUCCESS;
1154}
1155
1156
1157COIRESULT
44799f87
IV
1158SYMBOL_VERSION (COIProcessCreateFromMemory, 1) (COIENGINE in_Engine,
1159 const char *in_pBinaryName,
1160 const void *in_pBinaryBuffer,
1161 uint64_t in_BinaryBufferLength,
1162 int in_Argc,
1163 const char **in_ppArgv,
1164 uint8_t in_DupEnv,
1165 const char **in_ppAdditionalEnv,
1166 uint8_t in_ProxyActive, // Ignored
1167 const char *in_Reserved, // Ignored
1168 uint64_t in_InitialBufferSpace, // Ignored
1169 const char *in_LibrarySearchPath,
1170 const char *in_FileOfOrigin, // Ignored
1171 uint64_t in_FileOfOriginOffset, // Ignored
1172 COIPROCESS *out_pProcess)
5f520819
KY
1173{
1174 COITRACE ("COIProcessCreateFromMemory");
1175
1176 const int run_max_args_num = 128;
5f520819
KY
1177 char *run_argv[run_max_args_num];
1178 char *emul_run = getenv (OFFLOAD_EMUL_RUN_ENV);
5f520819 1179 const int uint_max_len = 11;
5f520819 1180
44799f87
IV
1181 /* Features of liboffloadmic. */
1182 assert (in_Engine != NULL);
1183 assert (in_pBinaryName != NULL);
1184 assert (in_pBinaryBuffer != NULL);
1185 assert (in_Argc == 0);
1186 assert (in_ppArgv == NULL);
1187 assert (in_ppAdditionalEnv == NULL);
1188 assert (in_LibrarySearchPath != NULL);
1189 assert (out_pProcess != NULL);
5f520819
KY
1190
1191 /* Convert input arguments. */
44799f87 1192 Engine *eng = (Engine *) in_Engine;
5f520819
KY
1193
1194 /* Create temporary directory for engine files. */
1195 assert (eng->dir == NULL);
1196 STRDUP (eng->dir, ENGINE_PATH);
1197 if (mkdtemp (eng->dir) == NULL)
1198 COIERROR ("Cannot create temporary directory %s.", eng->dir);
1199
1200 /* Save path to engine directory for clean up on exit. */
1201 tmp_dirs_num++;
1202 tmp_dirs = (char **) realloc (tmp_dirs, tmp_dirs_num * sizeof (char *));
1203 if (!tmp_dirs)
1204 COIERROR ("Cannot allocate memory.");
1205 STRDUP (tmp_dirs[tmp_dirs_num - 1], eng->dir);
1206
1207 /* Create target executable file. */
44799f87
IV
1208 char *target_exe;
1209 MALLOC (char *, target_exe, strlen (eng->dir) + strlen (in_pBinaryName) + 2);
1210 sprintf (target_exe, "%s/%s", eng->dir, in_pBinaryName);
1211 int fd = open (target_exe, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
5f520819
KY
1212 if (fd < 0)
1213 COIERROR ("Cannot create file %s.", target_exe);
44799f87 1214 FILE *file = fdopen (fd, "wb");
5f520819
KY
1215 if (file == NULL)
1216 COIERROR ("Cannot associate stream with file descriptor.");
44799f87
IV
1217 if (fwrite (in_pBinaryBuffer, 1, in_BinaryBufferLength, file)
1218 != in_BinaryBufferLength)
5f520819
KY
1219 COIERROR ("Cannot write in file %s.", target_exe);
1220 if (fclose (file) != 0)
1221 COIERROR ("Cannot close file %s.", target_exe);
1222
1223 /* Fix file permissions. */
1224 if (chmod (target_exe, S_IRWXU) < 0)
1225 COIERROR ("Cannot change permissions for file %s.", target_exe);
1226
1227 /* Create directory for pipes to prevent names collision. */
44799f87
IV
1228 char *pipes_path;
1229 MALLOC (char *, pipes_path, strlen (eng->dir) + sizeof (PIPES_PATH));
2eab9666 1230 sprintf (pipes_path, "%s" PIPES_PATH, eng->dir);
5f520819
KY
1231 if (mkdir (pipes_path, S_IRWXU) < 0)
1232 COIERROR ("Cannot create folder %s.", pipes_path);
1233
44799f87
IV
1234 /* Create 2 main pipes for inter-process communication. */
1235 char *pipe_host2tgt_path, *pipe_tgt2host_path;
1236 MALLOC (char *, pipe_host2tgt_path,
1237 strlen (eng->dir) + sizeof (PIPE_HOST2TGT_NAME "mainpipe"));
1238 MALLOC (char *, pipe_tgt2host_path,
1239 strlen (eng->dir) + sizeof (PIPE_TGT2HOST_NAME "mainpipe"));
1240 sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "mainpipe", eng->dir);
1241 sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "mainpipe", eng->dir);
1242 if (mkfifo (pipe_host2tgt_path, S_IRUSR | S_IWUSR) < 0)
1243 COIERROR ("Cannot create main pipe %s.", pipe_host2tgt_path);
1244 if (mkfifo (pipe_tgt2host_path, S_IRUSR | S_IWUSR) < 0)
1245 COIERROR ("Cannot create main pipe %s.", pipe_tgt2host_path);
5f520819
KY
1246
1247 /* Prepare argv. */
1248 if (emul_run == NULL || strcmp (emul_run, "") == 0)
1249 {
1250 STRDUP (run_argv[0], target_exe);
1251 run_argv[1] = (char *) NULL;
1252 }
1253 else
1254 {
1255 char *ptr, *tmp;
44799f87 1256 int i = 0;
5f520819 1257 STRDUP (tmp, emul_run);
44799f87 1258 char *tok = strtok_r (tmp, " ", &ptr);
5f520819
KY
1259 while (tok != NULL)
1260 {
1261 if (i >= run_max_args_num)
1262 COIERROR ("Run command has too many arguments.");
1263 STRDUP (run_argv[i++], tok);
1264 tok = strtok_r (NULL, " ", &ptr);
1265 }
1266 STRDUP (run_argv[i], target_exe);
44799f87 1267 run_argv[i + 1] = (char *) NULL;
5f520819
KY
1268 free (tmp);
1269 }
1270
1271 /* Prepare envp. */
44799f87
IV
1272 int env_num = 0;
1273 if (in_DupEnv == true)
5f520819
KY
1274 while (environ[env_num++]);
1275 env_num += 4; // LD_LIBRARY_PATH, MIC_DIR, MIC_INDEX, NULL
1276
44799f87 1277 char **envp;
5f520819
KY
1278 MALLOC (char **, envp, env_num * sizeof (char *));
1279
44799f87
IV
1280 int env_i = 0;
1281 if (in_DupEnv == true)
1282 for (unsigned i = 0; environ[i] != NULL; i++)
5f520819 1283 {
44799f87
IV
1284 unsigned j;
1285 char *env_name;
5f520819
KY
1286 STRDUP (env_name, environ[i]);
1287 for (j = 0; env_name[j] != '=' && env_name[j] != '\0'; j++);
1288 env_name[j] = '\0';
1289 if (strcmp (env_name, "LD_LIBRARY_PATH") != 0
1290 && strcmp (env_name, MIC_DIR_ENV) != 0
1291 && strcmp (env_name, MIC_INDEX_ENV) != 0)
1292 STRDUP (envp[env_i++], environ[i]);
1293 free (env_name);
1294 }
1295
1296 MALLOC (char *, envp[env_i], strlen (MIC_DIR_ENV) + strlen (eng->dir) + 2);
1297 sprintf (envp[env_i], "%s=%s", MIC_DIR_ENV, eng->dir);
1298
44799f87
IV
1299 MALLOC (char *, envp[env_i + 1], strlen (MIC_INDEX_ENV) + uint_max_len + 1);
1300 sprintf (envp[env_i + 1], "%s=%u", MIC_INDEX_ENV, eng->index);
5f520819 1301
44799f87
IV
1302 MALLOC (char *, envp[env_i + 2],
1303 strlen ("LD_LIBRARY_PATH=") + strlen (in_LibrarySearchPath) + 1);
1304 sprintf (envp[env_i + 2], "LD_LIBRARY_PATH=%s", in_LibrarySearchPath);
5f520819 1305
44799f87 1306 envp[env_i + 3] = (char *) NULL;
5f520819
KY
1307
1308 /* Create target process. */
44799f87 1309 pid_t pid = vfork ();
5f520819
KY
1310 if (pid < 0)
1311 COIERROR ("Cannot create child process.");
1312
1313 if (pid == 0)
1314 {
1315 /* Run target executable. */
1316 if (execvpe (run_argv[0], run_argv, envp) == -1)
1317 COIERROR ("Cannot execute file %s.", target_exe);
1318 }
1319
44799f87
IV
1320 /* Open main pipes. */
1321 int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_WRONLY);
1322 if (pipe_host2tgt < 0)
1323 COIERROR ("Cannot open host-to-target main pipe.");
1324 int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_RDONLY);
1325 if (pipe_tgt2host < 0)
1326 COIERROR ("Cannot open target-to-host main pipe.");
5f520819
KY
1327
1328 /* Create process handle. */
44799f87 1329 Process *proc = new Process;
5f520819 1330 proc->pid = pid;
44799f87
IV
1331 proc->pipe_host2tgt = pipe_host2tgt;
1332 proc->pipe_tgt2host = pipe_tgt2host;
5f520819 1333 proc->engine = eng;
44799f87 1334 proc->functions = NULL;
5f520819
KY
1335
1336 /* Prepare output arguments. */
44799f87 1337 *out_pProcess = (COIPROCESS) proc;
5f520819
KY
1338
1339 /* Clean up. */
44799f87 1340 for (unsigned i = 0; run_argv[i] != NULL; i++)
5f520819 1341 free (run_argv[i]);
44799f87 1342 for (unsigned i = 0; envp[i] != NULL; i++)
5f520819
KY
1343 free (envp[i]);
1344 free (envp);
44799f87
IV
1345 free (pipe_host2tgt_path);
1346 free (pipe_tgt2host_path);
5f520819
KY
1347 free (pipes_path);
1348 free (target_exe);
1349
1350 return COI_SUCCESS;
1351}
1352
1353
2eab9666
IV
1354COIRESULT
1355SYMBOL_VERSION (COIProcessCreateFromFile, 1) (COIENGINE in_Engine,
1356 const char *in_pBinaryName,
1357 int in_Argc,
1358 const char **in_ppArgv,
1359 uint8_t in_DupEnv,
1360 const char **in_ppAdditionalEnv,
1361 uint8_t in_ProxyActive,
1362 const char *in_Reserved,
1363 uint64_t in_BufferSpace,
1364 const char *in_LibrarySearchPath,
1365 COIPROCESS *out_pProcess)
1366{
1367 COITRACE ("COIProcessCreateFromFile");
1368
1369 /* liboffloadmic with GCC compiled binaries should never go here. */
1370 assert (false);
1371 return COI_ERROR;
1372}
1373
1374
5f520819 1375COIRESULT
44799f87
IV
1376SYMBOL_VERSION (COIProcessDestroy, 1) (COIPROCESS in_Process,
1377 int32_t in_WaitForMainTimeout, // Ignored
1378 uint8_t in_ForceDestroy,
1379 int8_t *out_pProcessReturn,
1380 uint32_t *out_pTerminationCode)
5f520819
KY
1381{
1382 COITRACE ("COIProcessDestroy");
1383
44799f87
IV
1384 assert (in_Process != NULL);
1385 assert (out_pProcessReturn != NULL);
1386 assert (out_pTerminationCode != NULL);
5f520819
KY
1387
1388 /* Convert input arguments. */
44799f87 1389 Process *proc = (Process *) in_Process;
5f520819 1390
44799f87
IV
1391 /* Destroy all undestroyed pipelines. */
1392 while (!pipelines.empty ())
1393 {
1394 std::set<Pipeline *>::iterator p = pipelines.begin ();
1395 COIPipelineDestroy ((COIPIPELINE) *p);
1396 }
1397
1398 /* Close main pipes. */
1399 if (close (proc->pipe_host2tgt) < 0)
1400 COIERROR ("Cannot close host-to-target main pipe.");
1401 if (close (proc->pipe_tgt2host) < 0)
1402 COIERROR ("Cannot close target-to-host main pipe.");
5f520819
KY
1403
1404 /* Shutdown target process by force. */
44799f87 1405 if (in_ForceDestroy)
5f520819
KY
1406 kill (proc->pid, SIGTERM);
1407
1408 /* Clean up. */
5f520819 1409 free (proc->engine->dir);
5f520819 1410 free (proc->functions);
44799f87
IV
1411 delete proc->engine;
1412 delete proc;
5f520819
KY
1413
1414 /* Prepare output arguments. */
44799f87
IV
1415 *out_pProcessReturn = 0;
1416 *out_pTerminationCode = 0;
5f520819
KY
1417
1418 return COI_SUCCESS;
1419}
1420
1421
1422COIRESULT
44799f87
IV
1423SYMBOL_VERSION (COIProcessGetFunctionHandles, 1) (COIPROCESS in_Process,
1424 uint32_t in_NumFunctions,
1425 const char **in_ppFunctionNameArray,
1426 COIFUNCTION *out_pFunctionHandleArray)
5f520819
KY
1427{
1428 COITRACE ("COIProcessGetFunctionHandles");
1429
44799f87
IV
1430 assert (in_Process != NULL);
1431 assert (in_ppFunctionNameArray != NULL);
1432 assert (out_pFunctionHandleArray != NULL);
5f520819
KY
1433
1434 /* Convert input arguments. */
44799f87 1435 Process *proc = (Process *) in_Process;
5f520819
KY
1436
1437 /* This function should be called once for the process. */
44799f87 1438 assert (proc->functions == NULL);
5f520819 1439
44799f87
IV
1440 /* Create array of function pointers. Last element is 0, what shows the end
1441 of the array. This array is used to free memory when process is
1442 destroyed. */
1443 proc->functions = (void **) calloc (in_NumFunctions + 1, sizeof (void *));
5f520819
KY
1444 if (proc->functions == NULL)
1445 COIERROR ("Cannot allocate memory.");
1446
1447 /* Get handles for functions. */
44799f87 1448 for (uint32_t i = 0; i < in_NumFunctions; i++)
5f520819 1449 {
44799f87 1450 size_t len = strlen (in_ppFunctionNameArray[i]) + 1;
5f520819 1451
44799f87 1452 start_critical_section ();
5f520819
KY
1453
1454 /* Send data to target. */
44799f87
IV
1455 const cmd_t cmd = CMD_GET_FUNCTION_HANDLE;
1456 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1457 WRITE (proc->pipe_host2tgt, &len, sizeof (size_t));
1458 WRITE (proc->pipe_host2tgt, in_ppFunctionNameArray[i], len);
5f520819 1459
44799f87
IV
1460 /* Receive data from target. */
1461 void *fn_ptr;
1462 READ (proc->pipe_tgt2host, &fn_ptr, sizeof (void *));
5f520819 1463
44799f87 1464 finish_critical_section ();
5f520819
KY
1465
1466 /* Save function pointer. */
44799f87
IV
1467 proc->functions[i] = fn_ptr;
1468
1469 /* Prepare output arguments. */
1470 out_pFunctionHandleArray[i] = (COIFUNCTION) fn_ptr;
5f520819
KY
1471 }
1472
1473 return COI_SUCCESS;
1474}
1475
1476
1477COIRESULT
2eab9666
IV
1478SYMBOL_VERSION (COIProcessLoadLibraryFromMemory, 2) (COIPROCESS in_Process,
1479 const void *in_pLibraryBuffer,
1480 uint64_t in_LibraryBufferLength,
1481 const char *in_pLibraryName,
1482 const char *in_LibrarySearchPath, // Ignored
1483 const char *in_FileOfOrigin, // Ignored
1484 uint64_t in_FileOfOriginOffset, // Ignored
1485 uint32_t in_Flags, // Ignored
1486 COILIBRARY *out_pLibrary)
5f520819
KY
1487{
1488 COITRACE ("COIProcessLoadLibraryFromMemory");
1489
44799f87
IV
1490 assert (in_Process != NULL);
1491 assert (in_pLibraryBuffer != NULL);
1492 assert (out_pLibrary != NULL);
5f520819
KY
1493
1494 /* Convert input arguments. */
2eab9666 1495 Process *proc = (Process *) in_Process;
5f520819
KY
1496
1497 /* Create target library file. */
44799f87
IV
1498 char *lib_path;
1499 size_t len = strlen (proc->engine->dir) + strlen (in_pLibraryName) + 2;
1500 MALLOC (char *, lib_path, len);
2eab9666 1501 sprintf (lib_path, "%s/%s", proc->engine->dir, in_pLibraryName);
44799f87 1502 int fd = open (lib_path, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
5f520819
KY
1503 if (fd < 0)
1504 COIERROR ("Cannot create file %s.", lib_path);
44799f87 1505 FILE *file = fdopen (fd, "wb");
5f520819
KY
1506 if (file == NULL)
1507 COIERROR ("Cannot associate stream with file descriptor.");
2eab9666
IV
1508 if (fwrite (in_pLibraryBuffer, 1, in_LibraryBufferLength, file)
1509 != in_LibraryBufferLength)
5f520819
KY
1510 COIERROR ("Cannot write in file %s.", lib_path);
1511 if (fclose (file) != 0)
1512 COIERROR ("Cannot close file %s.", lib_path);
1513
44799f87 1514 start_critical_section ();
5f520819
KY
1515
1516 /* Make target open library. */
44799f87
IV
1517 const cmd_t cmd = CMD_OPEN_LIBRARY;
1518 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1519 WRITE (proc->pipe_host2tgt, &len, sizeof (size_t));
1520 WRITE (proc->pipe_host2tgt, lib_path, len);
5f520819 1521
2eab9666
IV
1522 /* Receive data from target. */
1523 void *handle;
44799f87 1524 READ (proc->pipe_tgt2host, &handle, sizeof (void *));
2eab9666 1525
44799f87 1526 finish_critical_section ();
5f520819
KY
1527
1528 /* Clean up. */
1529 free (lib_path);
1530
2eab9666 1531 *out_pLibrary = (COILIBRARY) handle;
5f520819
KY
1532 return COI_SUCCESS;
1533}
1534
1535
1536COIRESULT
44799f87
IV
1537SYMBOL_VERSION (COIProcessRegisterLibraries, 1) (uint32_t in_NumLibraries, // Ignored
1538 const void **in_ppLibraryArray, // Ignored
1539 const uint64_t *in_pLibrarySizeArray, // Ignored
1540 const char **in_ppFileOfOriginArray, // Ignored
1541 const uint64_t *in_pFileOfOriginOffSetArray) // Ignored
5f520819
KY
1542{
1543 COITRACE ("COIProcessRegisterLibraries");
1544
1545 /* Looks like we have nothing to do here. */
1546
1547 return COI_SUCCESS;
1548}
1549
1550
2eab9666
IV
1551COIRESULT
1552SYMBOL_VERSION (COIProcessUnloadLibrary, 1) (COIPROCESS in_Process,
1553 COILIBRARY in_Library)
1554{
1555 COITRACE ("COIProcessUnloadLibrary");
1556
44799f87
IV
1557 assert (in_Process != NULL);
1558 assert (in_Library != NULL);
1559
2eab9666
IV
1560 const cmd_t cmd = CMD_CLOSE_LIBRARY;
1561
1562 /* Convert input arguments. */
1563 Process *proc = (Process *) in_Process;
1564
44799f87 1565 start_critical_section ();
2eab9666
IV
1566
1567 /* Make target close library. */
44799f87
IV
1568 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1569 WRITE (proc->pipe_host2tgt, &in_Library, sizeof (void *));
2eab9666 1570
44799f87 1571 finish_critical_section ();
2eab9666
IV
1572
1573 return COI_SUCCESS;
1574}
1575
1576
5f520819
KY
1577uint64_t
1578SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
1579{
1580 COITRACE ("COIPerfGetCycleFrequency");
1581
1582 return (uint64_t) CYCLE_FREQUENCY;
1583}
1584
2eab9666
IV
1585
1586COIRESULT
1587SYMBOL_VERSION (COIPipelineClearCPUMask, 1) (COI_CPU_MASK *in_Mask)
1588{
1589 COITRACE ("COIPipelineClearCPUMask");
1590
1591 /* Looks like we have nothing to do here. */
1592
1593 return COI_SUCCESS;
1594}
1595
1596
1597COIRESULT
1598SYMBOL_VERSION (COIPipelineSetCPUMask, 1) (COIPROCESS in_Process,
1599 uint32_t in_CoreID,
1600 uint8_t in_ThreadID,
1601 COI_CPU_MASK *out_pMask)
1602{
1603 COITRACE ("COIPipelineSetCPUMask");
1604
1605 /* Looks like we have nothing to do here. */
1606
1607 return COI_SUCCESS;
1608}
1609
1610
1611COIRESULT
44799f87
IV
1612SYMBOL_VERSION (COIEngineGetInfo, 1) (COIENGINE in_EngineHandle, // Ignored
1613 uint32_t in_EngineInfoSize, // Ignored
2eab9666
IV
1614 COI_ENGINE_INFO *out_pEngineInfo)
1615{
1616 COITRACE ("COIEngineGetInfo");
1617
44799f87
IV
1618 assert (out_pEngineInfo != NULL);
1619
df26a50d 1620 out_pEngineInfo->ISA = COI_DEVICE_KNL;
2eab9666
IV
1621 out_pEngineInfo->NumCores = 1;
1622 out_pEngineInfo->NumThreads = 8;
1623 out_pEngineInfo->CoreMaxFrequency = SYMBOL_VERSION(COIPerfGetCycleFrequency,1)() / 1000000;
1624 out_pEngineInfo->PhysicalMemory = 1024;
1625 out_pEngineInfo->PhysicalMemoryFree = 1024;
1626 out_pEngineInfo->SwapMemory = 1024;
1627 out_pEngineInfo->SwapMemoryFree = 1024;
1628 out_pEngineInfo->MiscFlags = COI_ENG_ECC_DISABLED;
1629
1630 return COI_SUCCESS;
1631}
1632
5f520819
KY
1633} // extern "C"
1634