[RS6000] rs6000_output_mi_thunk tidy
[official-gcc.git] / liboffloadmic / runtime / emulator / coi_host.cpp
blob6170d8d7f3d669bdde009bfaaf32a5cd9ab0878c
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.
30 #include <set>
31 #include <map>
32 #include <queue>
34 #include "coi_host.h"
36 #include "coi_version_asm.h"
38 #define CYCLE_FREQUENCY 1000000000
40 enum buffer_t
42 BUFFER_NORMAL,
43 BUFFER_MEMORY
46 struct Engine
48 COI_ISA_TYPE type;
49 uint32_t index;
50 char *dir;
53 struct Function
55 void *ptr;
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;
66 struct Callback
68 COI_EVENT_CALLBACK ptr;
69 const void *data;
72 struct Process
74 pid_t pid;
75 int pipe_host2tgt;
76 int pipe_tgt2host;
77 Engine *engine;
78 void **functions;
81 struct Pipeline
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;
94 struct Buffer
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;
107 /* Environment variables. */
108 extern char **environ;
110 /* List of directories for removing on exit. */
111 static char **tmp_dirs;
112 static unsigned tmp_dirs_num;
114 /* Number of emulated MIC engines. */
115 static long num_engines;
117 /* Number of the last COI pipeline. */
118 static uint32_t max_pipeline_num;
120 /* Set of undestroyed pipelines. */
121 static std::set<Pipeline *> pipelines;
123 /* Number of the last COI event, the event #0 is always signalled. */
124 static uint64_t max_event_num = 1;
126 /* Set of created COI events, which are not signalled. */
127 static std::set<uint64_t> non_signalled_events;
129 /* Set of COI events, which encountered errors. */
130 static std::map<uint64_t, COIRESULT> errored_events;
132 /* Set of registered callbacks, indexed by event number. */
133 static std::map<uint64_t, Callback> callbacks;
135 /* Mutex to sync parallel execution. */
136 static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
139 static COIRESULT
140 read_long_env (const char *env_name, long *var, long var_default)
142 char *str = getenv (env_name);
143 char *s;
145 if (!str || *str == '\0')
146 *var = var_default;
147 else
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);
155 return COI_SUCCESS;
158 __attribute__((constructor))
159 static void
160 init ()
162 if (read_long_env (OFFLOAD_EMUL_NUM_ENV, &num_engines, 1) == COI_ERROR)
163 exit (0);
167 /* Helper function for directory removing. */
168 static COIRESULT remove_directory (char *path)
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);
177 while (entry = readdir (dir))
179 if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
180 continue;
182 MALLOC (char *, file, strlen (path) + strlen (entry->d_name) + 2);
183 sprintf (file, "%s/%s", path, entry->d_name);
185 if (stat (file, &statfile) < 0)
186 COIERROR ("Cannot retrieve information about file %s.", file);
188 if (S_ISDIR (statfile.st_mode))
190 if (remove_directory (file) == COI_ERROR)
191 return COI_ERROR;
193 else
195 if (unlink (file) < 0)
196 COIERROR ("Cannot unlink file %s.", file);
199 free (file);
202 if (closedir (dir) < 0)
203 COIERROR ("Cannot close directory %s.", path);
204 if (rmdir (path) < 0)
205 COIERROR ("Cannot remove directory %s.", path);
207 return COI_SUCCESS;
210 __attribute__((destructor))
211 static void
212 cleanup ()
214 for (unsigned i = 0; i < tmp_dirs_num; i++)
216 remove_directory (tmp_dirs[i]);
217 free (tmp_dirs[i]);
219 free (tmp_dirs);
222 static COIRESULT
223 start_critical_section ()
225 if (pthread_mutex_lock (&mutex) != 0)
226 COIERROR ("Cannot lock mutex.");
227 return COI_SUCCESS;
230 static COIRESULT
231 finish_critical_section ()
233 if (pthread_mutex_unlock (&mutex) != 0)
234 COIERROR ("Cannot unlock mutex.");
235 return COI_SUCCESS;
238 static bool
239 pipeline_is_destroyed (const Pipeline *pipeline)
241 start_critical_section ();
242 bool res = pipeline->is_destroyed;
243 finish_critical_section ();
244 return res;
247 static void
248 maybe_invoke_callback (const COIEVENT event, const COIRESULT result)
250 std::map<uint64_t, Callback>::iterator cb = callbacks.find (event.opaque[0]);
252 if (cb != callbacks.end ())
254 Callback callback = cb->second;
255 callback.ptr (event, result, callback.data);
256 callbacks.erase (cb);
260 static void
261 signal_event (const COIEVENT event, const COIRESULT result)
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]);
268 maybe_invoke_callback (event, result);
271 static COIRESULT
272 get_event_result (const COIEVENT event)
274 COIRESULT res = COI_SUCCESS;
276 std::map<uint64_t, COIRESULT>::iterator ee
277 = errored_events.find (event.opaque[0]);
279 if (ee != errored_events.end ())
280 res = ee->second;
282 return res;
286 extern "C"
289 COIRESULT
290 SYMBOL_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)
300 COITRACE ("COIBufferCopy");
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);
308 /* Convert input arguments. */
309 Buffer *dest = (Buffer *) in_DestBuffer;
310 Buffer *source = (Buffer *) in_SourceBuffer;
312 start_critical_section ();
314 /* Map buffers if needed. */
315 if (dest->data == 0 && dest->type == BUFFER_NORMAL)
316 if (COIBufferMap (in_DestBuffer, 0, dest->size, (COI_MAP_TYPE) 0,
317 0, 0, 0, 0, 0) == COI_ERROR)
318 return COI_ERROR;
319 if (source->data == 0 && source->type == BUFFER_NORMAL)
320 if (COIBufferMap (in_SourceBuffer, 0, source->size, (COI_MAP_TYPE) 0,
321 0, 0, 0, 0, 0) == COI_ERROR)
322 return COI_ERROR;
324 /* Copy data. */
325 if (source->data != 0 && dest->data != 0)
326 memcpy ((void *) ((uintptr_t) dest->data + in_DestOffset),
327 (void *) ((uintptr_t) source->data + in_SourceOffset), in_Length);
328 else
330 assert (dest->process == source->process);
332 Buffer *buffer;
333 cmd_t cmd = CMD_BUFFER_COPY;
335 /* Create intermediary buffer. */
336 if (COIBufferCreate (in_Length, COI_BUFFER_NORMAL, 0, 0, 1,
337 (COIPROCESS*) &dest->process,
338 (COIBUFFER *) &buffer) == COI_ERROR)
339 return COI_ERROR;
341 int pipe_host2tgt = dest->process->pipe_host2tgt;
342 int pipe_tgt2host = dest->process->pipe_tgt2host;
344 /* Copy from source to intermediary buffer. */
345 if (source->data == 0)
347 assert (source->data_target != 0);
349 /* Send data to target. */
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));
355 /* Receive data from target. */
356 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
358 else
360 if (COIBufferCopy ((COIBUFFER) buffer, in_SourceBuffer, 0,
361 in_SourceOffset, in_Length, in_Type, 0, 0, 0)
362 == COI_ERROR)
363 return COI_ERROR;
366 /* Copy from intermediary buffer to dest. */
367 if (dest->data == 0)
369 assert (dest->data_target != 0);
371 /* Send data to target. */
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));
377 /* Receive data from target. */
378 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
380 else
382 if (COIBufferCopy (in_DestBuffer, (COIBUFFER) buffer, in_DestOffset,
383 0, in_Length, in_Type, 0, 0, 0) == COI_ERROR)
384 return COI_ERROR;
387 /* Unmap on target and destroy intermediary buffer. */
388 if (COIBufferDestroy ((COIBUFFER) buffer) == COI_ERROR)
389 return COI_ERROR;
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;
400 finish_critical_section ();
402 if (out_pCompletion)
403 out_pCompletion->opaque[0] = 0;
405 return COI_SUCCESS;
409 COIRESULT
410 SYMBOL_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)
418 COITRACE ("COIBufferCreate");
420 char *shm_name;
421 int shm_fd;
422 const int ullong_max_len = 20;
424 /* Features of liboffloadmic. */
425 assert (in_Type == COI_BUFFER_NORMAL || in_Type == COI_BUFFER_OPENCL);
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);
434 /* Create shared memory with an unique name. */
435 MALLOC (char *, shm_name, strlen (SHM_NAME) + ullong_max_len + 1);
436 for (unsigned long long i = 0; i >= 0; i++)
438 sprintf (shm_name, SHM_NAME "%lu", i);
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;
444 if (ftruncate (shm_fd, in_Size) < 0)
445 COIERROR ("Cannot truncate shared memory file.");
447 /* Create buffer. */
448 Buffer *buf = new Buffer;
449 buf->data = 0;
450 buf->fd = shm_fd;
451 buf->process = (Process *) in_pProcesses[0];
452 buf->size = in_Size;
453 buf->type = BUFFER_NORMAL;
454 STRDUP (buf->name, shm_name);
456 /* Map buffer on target. */
457 size_t len = strlen (buf->name) + 1;
459 start_critical_section ();
461 /* Send data to target. */
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));
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 *));
474 finish_critical_section ();
476 /* Prepare output arguments. */
477 *out_pBuffer = (COIBUFFER) buf;
479 /* Clean up. */
480 free (shm_name);
482 return COI_SUCCESS;
486 COIRESULT
487 SYMBOL_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)
495 COITRACE ("COIBufferCreateFromMemory");
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);
505 /* Create buffer. */
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;
511 buf->type = BUFFER_MEMORY;
513 /* Prepare output argument. */
514 *out_pBuffer = (COIBUFFER) buf;
516 return COI_SUCCESS;
520 COIRESULT
521 SYMBOL_VERSION (COIBufferDestroy, 1) (COIBUFFER in_Buffer)
523 COITRACE ("COIBufferDestroy");
525 cmd_t cmd = CMD_BUFFER_UNMAP;
527 assert (in_Buffer != NULL);
529 /* Convert input arguments. */
530 Buffer *buf = (Buffer *) in_Buffer;
532 /* Unmap buffer on host. */
533 if (buf->data != 0 && buf->type == BUFFER_NORMAL)
534 if (COIBufferUnmap ((COIMAPINSTANCE) in_Buffer, 0, 0, 0) == COI_ERROR)
535 return COI_ERROR;
537 /* Unmap buffer on target. */
538 if (buf->data_target != 0)
540 start_critical_section ();
542 /* Send data to target. */
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));
549 /* Receive data from target. */
550 READ (buf->process->pipe_tgt2host, &cmd, sizeof (cmd_t));
552 finish_critical_section ();
555 /* Unlink shared memory. */
556 if (buf->type == BUFFER_NORMAL)
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);
565 /* Clean up. */
566 delete buf;
568 return COI_SUCCESS;
572 COIRESULT
573 SYMBOL_VERSION (COIBufferGetSinkAddress, 1) (COIBUFFER in_Buffer,
574 uint64_t *out_pAddress)
576 COITRACE ("COIBufferGetSinkAddress");
578 assert (in_Buffer != NULL);
579 assert (out_pAddress != NULL);
581 /* Convert input arguments. */
582 Buffer *buf = (Buffer *) in_Buffer;
584 /* Here should come BUFFER_NORMAL buffer. */
585 assert (buf->type == BUFFER_NORMAL);
587 /* Prepare output argument. */
588 *out_pAddress = (uint64_t) buf->data_target;
590 return COI_SUCCESS;
594 COIRESULT
595 SYMBOL_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)
605 COITRACE ("COIBufferMap");
607 /* Features of liboffloadmic. */
608 assert (in_Offset == 0);
609 assert (in_NumDependencies == 0);
611 /* Convert input arguments. */
612 Buffer *buf = (Buffer *) in_Buffer;
614 /* Only BUFFER_NORMAL buffers should come here. */
615 assert (buf->type == BUFFER_NORMAL);
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.");
623 /* Prepare output arguments. */
624 if (out_pMapInstance != 0)
625 *out_pMapInstance = (COIMAPINSTANCE) buf;
626 if (out_ppData != 0)
627 *out_ppData = buf->data;
629 if (out_pCompletion)
630 out_pCompletion->opaque[0] = 0;
632 return COI_SUCCESS;
636 COIRESULT
637 SYMBOL_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)
646 COITRACE ("COIBufferRead");
648 /* Features of liboffloadmic. */
649 assert (in_pDestData != NULL);
650 assert (in_Type == COI_COPY_UNSPECIFIED);
651 assert (in_NumDependencies == 0);
653 /* Convert input arguments. */
654 Buffer *buf = (Buffer *) in_SourceBuffer;
656 start_critical_section ();
658 /* Map buffers if needed. */
659 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
660 if (COIBufferMap (in_SourceBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0,
661 0, 0) == COI_ERROR)
662 return COI_ERROR;
664 /* Copy data. */
665 memcpy (in_pDestData, (void *) ((uintptr_t) buf->data + in_Offset),
666 in_Length);
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;
673 finish_critical_section ();
675 if (out_pCompletion)
676 out_pCompletion->opaque[0] = 0;
678 return COI_SUCCESS;
682 COIRESULT
683 SYMBOL_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)
691 COITRACE ("COIBufferSetState");
693 /* Features of liboffloadmic. */
694 assert (in_DataMove == COI_BUFFER_NO_MOVE);
695 assert (in_NumDependencies == 0);
697 /* Looks like we have nothing to do here. */
699 if (out_pCompletion)
700 out_pCompletion->opaque[0] = 0;
702 return COI_SUCCESS;
706 COIRESULT
707 SYMBOL_VERSION (COIBufferUnmap, 1) (COIMAPINSTANCE in_MapInstance,
708 uint32_t in_NumDependencies,
709 const COIEVENT *in_pDependencies, // Ignored
710 COIEVENT *out_pCompletion)
712 COITRACE ("COIBufferUnmap");
714 /* Features of liboffloadmic. */
715 assert (in_MapInstance != NULL);
716 assert (in_NumDependencies == 0);
718 /* Convert input arguments. */
719 Buffer *buffer = (Buffer *) in_MapInstance;
721 /* Only BUFFER_NORMAL buffers should come here. */
722 assert (buffer->type == BUFFER_NORMAL);
724 /* Unmap shared memory. */
725 if (munmap (buffer->data, buffer->size) < 0)
726 COIERROR ("Cannot unmap shared memory.");
728 buffer->data = 0;
730 if (out_pCompletion)
731 out_pCompletion->opaque[0] = 0;
733 return COI_SUCCESS;
737 COIRESULT
738 SYMBOL_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)
747 COITRACE ("COIBufferWrite");
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);
755 /* Convert input arguments. */
756 Buffer *buf = (Buffer *) in_DestBuffer;
758 start_critical_section ();
760 /* Map buffers if needed. */
761 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
762 if (COIBufferMap (in_DestBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0, 0,
763 0) == COI_ERROR)
764 return COI_ERROR;
766 /* Copy data. */
767 memcpy ((void *) ((uintptr_t) buf->data + in_Offset), in_pSourceData,
768 in_Length);
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;
775 finish_critical_section ();
777 if (out_pCompletion)
778 out_pCompletion->opaque[0] = 0;
780 return COI_SUCCESS;
784 COIRESULT
785 SYMBOL_VERSION (COIEngineGetCount, 1) (COI_ISA_TYPE isa,
786 uint32_t *count)
788 COITRACE ("COIEngineGetCount");
790 /* Features of liboffloadmic. */
791 assert (isa == COI_ISA_MIC);
792 assert (count != NULL);
794 /* Prepare output arguments. */
795 *count = num_engines;
797 return COI_SUCCESS;
801 COIRESULT
802 SYMBOL_VERSION (COIEngineGetHandle, 1) (COI_ISA_TYPE in_ISA,
803 uint32_t in_EngineIndex,
804 COIENGINE *out_pEngineHandle)
806 COITRACE ("COIEngineGetHandle");
808 /* Features of liboffloadmic. */
809 assert (in_ISA == COI_ISA_MIC);
810 assert (out_pEngineHandle != NULL);
812 /* Check engine index. */
813 if (in_EngineIndex >= num_engines)
814 COIERROR ("Wrong engine index.");
816 /* Create engine handle. */
817 Engine *engine = new Engine;
818 engine->dir = NULL;
819 engine->index = in_EngineIndex;
820 engine->type = in_ISA;
822 /* Prepare output argument. */
823 *out_pEngineHandle = (COIENGINE) engine;
825 return COI_SUCCESS;
829 COIRESULT
830 SYMBOL_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)
837 COITRACE ("COIEventWait");
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);
846 if (in_TimeoutMilliseconds == 0)
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
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;
862 else
864 /* Wait indefinitely for all events. */
865 for (uint16_t i = 0; i < in_NumEvents; i++)
867 while (non_signalled_events.count (in_pEvents[i].opaque[0]) > 0)
868 usleep (1000);
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;
879 return COI_SUCCESS;
883 COIRESULT
884 SYMBOL_VERSION (COIEventRegisterCallback, 1) (const COIEVENT in_Event,
885 COI_EVENT_CALLBACK in_Callback,
886 const void *in_UserData,
887 const uint64_t in_Flags)
889 COITRACE ("COIEventRegisterCallback");
891 /* Features of liboffloadmic. */
892 assert (in_Callback != NULL);
893 assert (in_UserData != NULL);
894 assert (in_Flags == 0);
896 start_critical_section ();
897 if (non_signalled_events.count (in_Event.opaque[0]) == 0)
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);
903 else
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));
911 finish_critical_section ();
913 return COI_SUCCESS;
917 /* The start routine for the COI pipeline thread. */
919 static void *
920 pipeline_thread_routine (void *in_Pipeline)
922 /* Convert input arguments. */
923 Pipeline *pipeline = (Pipeline *) in_Pipeline;
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.");
935 free (pipeline->pipe_host2tgt_path);
936 free (pipeline->pipe_tgt2host_path);
937 pipeline->pipe_host2tgt_path = NULL;
938 pipeline->pipe_tgt2host_path = NULL;
940 while (!pipeline->destroy)
941 if (pipeline->queue.empty ())
942 usleep (1000);
943 else
945 Function func = pipeline->queue.front ();
946 start_critical_section ();
947 pipeline->queue.pop ();
948 finish_critical_section ();
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++)
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 *));
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));
969 delete [] func.bufs_size;
970 delete [] func.bufs_data_target;
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)
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;
987 else if (ret_len != (has_return_value ? func.return_value_len
988 : sizeof (cmd_t)))
989 COIERRORN ("Cannot read from pipe.");
991 start_critical_section ();
992 signal_event (func.completion_event, COI_SUCCESS);
993 finish_critical_section ();
996 /* Send data to target. */
997 const cmd_t cmd = CMD_PIPELINE_DESTROY;
998 WRITEN (pipeline->pipe_host2tgt, &cmd, sizeof (cmd_t));
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.");
1006 start_critical_section ();
1007 pipeline->is_destroyed = true;
1008 finish_critical_section ();
1009 return NULL;
1013 COIRESULT
1014 SYMBOL_VERSION (COIPipelineCreate, 1) (COIPROCESS in_Process,
1015 COI_CPU_MASK in_Mask,
1016 uint32_t in_StackSize, // Ignored
1017 COIPIPELINE *out_pPipeline)
1019 COITRACE ("COIPipelineCreate");
1021 /* Features of liboffloadmic. */
1022 assert (in_Process != NULL);
1023 assert (in_Mask == 0);
1024 assert (out_pPipeline != NULL);
1026 /* Convert input arguments. */
1027 Process *proc = (Process *) in_Process;
1029 start_critical_section ();
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);
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);
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));
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.");
1064 finish_critical_section ();
1066 /* Prepare output arguments. */
1067 *out_pPipeline = (COIPIPELINE) pipeline;
1069 return COI_SUCCESS;
1073 COIRESULT
1074 SYMBOL_VERSION (COIPipelineDestroy, 1) (COIPIPELINE in_Pipeline)
1076 COITRACE ("COIPipelineDestroy");
1078 assert (in_Pipeline != NULL);
1080 /* Convert input arguments. */
1081 Pipeline *pipeline = (Pipeline *) in_Pipeline;
1083 start_critical_section ();
1084 /* Remove pipeline from the set of undestroyed pipelines. */
1085 pipelines.erase (pipeline);
1087 /* Exit pipeline thread. */
1088 pipeline->destroy = true;
1089 finish_critical_section ();
1091 while (!pipeline_is_destroyed (pipeline))
1092 usleep (1000);
1094 /* Join with a destroyed thread. */
1095 if (pthread_join (pipeline->thread, NULL))
1096 COIERROR ("Cannot join with a thread.");
1098 delete pipeline;
1100 return COI_SUCCESS;
1104 COIRESULT
1105 SYMBOL_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)
1118 COITRACE ("COIPipelineRunFunction");
1120 /* Features of liboffloadmic. */
1121 assert (in_Pipeline != NULL);
1122 assert (in_Function != NULL);
1123 assert (in_NumDependencies == 0);
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++)
1132 Buffer **bufs = (Buffer **) in_Buffers;
1133 func.bufs_size[i] = bufs[i]->size;
1134 func.bufs_data_target[i] = bufs[i]->data_target;
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;
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 ();
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;
1153 return COI_SUCCESS;
1157 COIRESULT
1158 SYMBOL_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)
1174 COITRACE ("COIProcessCreateFromMemory");
1176 const int run_max_args_num = 128;
1177 char *run_argv[run_max_args_num];
1178 char *emul_run = getenv (OFFLOAD_EMUL_RUN_ENV);
1179 const int uint_max_len = 11;
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);
1191 /* Convert input arguments. */
1192 Engine *eng = (Engine *) in_Engine;
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);
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);
1207 /* Create target executable file. */
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);
1212 if (fd < 0)
1213 COIERROR ("Cannot create file %s.", target_exe);
1214 FILE *file = fdopen (fd, "wb");
1215 if (file == NULL)
1216 COIERROR ("Cannot associate stream with file descriptor.");
1217 if (fwrite (in_pBinaryBuffer, 1, in_BinaryBufferLength, file)
1218 != in_BinaryBufferLength)
1219 COIERROR ("Cannot write in file %s.", target_exe);
1220 if (fclose (file) != 0)
1221 COIERROR ("Cannot close file %s.", target_exe);
1223 /* Fix file permissions. */
1224 if (chmod (target_exe, S_IRWXU) < 0)
1225 COIERROR ("Cannot change permissions for file %s.", target_exe);
1227 /* Create directory for pipes to prevent names collision. */
1228 char *pipes_path;
1229 MALLOC (char *, pipes_path, strlen (eng->dir) + sizeof (PIPES_PATH));
1230 sprintf (pipes_path, "%s" PIPES_PATH, eng->dir);
1231 if (mkdir (pipes_path, S_IRWXU) < 0)
1232 COIERROR ("Cannot create folder %s.", pipes_path);
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);
1247 /* Prepare argv. */
1248 if (emul_run == NULL || strcmp (emul_run, "") == 0)
1250 STRDUP (run_argv[0], target_exe);
1251 run_argv[1] = (char *) NULL;
1253 else
1255 char *ptr, *tmp;
1256 int i = 0;
1257 STRDUP (tmp, emul_run);
1258 char *tok = strtok_r (tmp, " ", &ptr);
1259 while (tok != NULL)
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);
1266 STRDUP (run_argv[i], target_exe);
1267 run_argv[i + 1] = (char *) NULL;
1268 free (tmp);
1271 /* Prepare envp. */
1272 int env_num = 0;
1273 if (in_DupEnv == true)
1274 while (environ[env_num++]);
1275 env_num += 4; // LD_LIBRARY_PATH, MIC_DIR, MIC_INDEX, NULL
1277 char **envp;
1278 MALLOC (char **, envp, env_num * sizeof (char *));
1280 int env_i = 0;
1281 if (in_DupEnv == true)
1282 for (unsigned i = 0; environ[i] != NULL; i++)
1284 unsigned j;
1285 char *env_name;
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);
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);
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);
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);
1306 envp[env_i + 3] = (char *) NULL;
1308 /* Create target process. */
1309 pid_t pid = vfork ();
1310 if (pid < 0)
1311 COIERROR ("Cannot create child process.");
1313 if (pid == 0)
1315 /* Run target executable. */
1316 if (execvpe (run_argv[0], run_argv, envp) == -1)
1317 COIERROR ("Cannot execute file %s.", target_exe);
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.");
1328 /* Create process handle. */
1329 Process *proc = new Process;
1330 proc->pid = pid;
1331 proc->pipe_host2tgt = pipe_host2tgt;
1332 proc->pipe_tgt2host = pipe_tgt2host;
1333 proc->engine = eng;
1334 proc->functions = NULL;
1336 /* Prepare output arguments. */
1337 *out_pProcess = (COIPROCESS) proc;
1339 /* Clean up. */
1340 for (unsigned i = 0; run_argv[i] != NULL; i++)
1341 free (run_argv[i]);
1342 for (unsigned i = 0; envp[i] != NULL; i++)
1343 free (envp[i]);
1344 free (envp);
1345 free (pipe_host2tgt_path);
1346 free (pipe_tgt2host_path);
1347 free (pipes_path);
1348 free (target_exe);
1350 return COI_SUCCESS;
1354 COIRESULT
1355 SYMBOL_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)
1367 COITRACE ("COIProcessCreateFromFile");
1369 /* liboffloadmic with GCC compiled binaries should never go here. */
1370 assert (false);
1371 return COI_ERROR;
1375 COIRESULT
1376 SYMBOL_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)
1382 COITRACE ("COIProcessDestroy");
1384 assert (in_Process != NULL);
1385 assert (out_pProcessReturn != NULL);
1386 assert (out_pTerminationCode != NULL);
1388 /* Convert input arguments. */
1389 Process *proc = (Process *) in_Process;
1391 /* Destroy all undestroyed pipelines. */
1392 while (!pipelines.empty ())
1394 std::set<Pipeline *>::iterator p = pipelines.begin ();
1395 COIPipelineDestroy ((COIPIPELINE) *p);
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.");
1404 /* Shutdown target process by force. */
1405 if (in_ForceDestroy)
1406 kill (proc->pid, SIGTERM);
1408 /* Clean up. */
1409 free (proc->engine->dir);
1410 free (proc->functions);
1411 delete proc->engine;
1412 delete proc;
1414 /* Prepare output arguments. */
1415 *out_pProcessReturn = 0;
1416 *out_pTerminationCode = 0;
1418 return COI_SUCCESS;
1422 COIRESULT
1423 SYMBOL_VERSION (COIProcessGetFunctionHandles, 1) (COIPROCESS in_Process,
1424 uint32_t in_NumFunctions,
1425 const char **in_ppFunctionNameArray,
1426 COIFUNCTION *out_pFunctionHandleArray)
1428 COITRACE ("COIProcessGetFunctionHandles");
1430 assert (in_Process != NULL);
1431 assert (in_ppFunctionNameArray != NULL);
1432 assert (out_pFunctionHandleArray != NULL);
1434 /* Convert input arguments. */
1435 Process *proc = (Process *) in_Process;
1437 /* This function should be called once for the process. */
1438 assert (proc->functions == NULL);
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 *));
1444 if (proc->functions == NULL)
1445 COIERROR ("Cannot allocate memory.");
1447 /* Get handles for functions. */
1448 for (uint32_t i = 0; i < in_NumFunctions; i++)
1450 size_t len = strlen (in_ppFunctionNameArray[i]) + 1;
1452 start_critical_section ();
1454 /* Send data to target. */
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);
1460 /* Receive data from target. */
1461 void *fn_ptr;
1462 READ (proc->pipe_tgt2host, &fn_ptr, sizeof (void *));
1464 finish_critical_section ();
1466 /* Save function pointer. */
1467 proc->functions[i] = fn_ptr;
1469 /* Prepare output arguments. */
1470 out_pFunctionHandleArray[i] = (COIFUNCTION) fn_ptr;
1473 return COI_SUCCESS;
1477 COIRESULT
1478 SYMBOL_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)
1488 COITRACE ("COIProcessLoadLibraryFromMemory");
1490 assert (in_Process != NULL);
1491 assert (in_pLibraryBuffer != NULL);
1492 assert (out_pLibrary != NULL);
1494 /* Convert input arguments. */
1495 Process *proc = (Process *) in_Process;
1497 /* Create target library file. */
1498 char *lib_path;
1499 size_t len = strlen (proc->engine->dir) + strlen (in_pLibraryName) + 2;
1500 MALLOC (char *, lib_path, len);
1501 sprintf (lib_path, "%s/%s", proc->engine->dir, in_pLibraryName);
1502 int fd = open (lib_path, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
1503 if (fd < 0)
1504 COIERROR ("Cannot create file %s.", lib_path);
1505 FILE *file = fdopen (fd, "wb");
1506 if (file == NULL)
1507 COIERROR ("Cannot associate stream with file descriptor.");
1508 if (fwrite (in_pLibraryBuffer, 1, in_LibraryBufferLength, file)
1509 != in_LibraryBufferLength)
1510 COIERROR ("Cannot write in file %s.", lib_path);
1511 if (fclose (file) != 0)
1512 COIERROR ("Cannot close file %s.", lib_path);
1514 start_critical_section ();
1516 /* Make target open library. */
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);
1522 /* Receive data from target. */
1523 void *handle;
1524 READ (proc->pipe_tgt2host, &handle, sizeof (void *));
1526 finish_critical_section ();
1528 /* Clean up. */
1529 free (lib_path);
1531 *out_pLibrary = (COILIBRARY) handle;
1532 return COI_SUCCESS;
1536 COIRESULT
1537 SYMBOL_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
1543 COITRACE ("COIProcessRegisterLibraries");
1545 /* Looks like we have nothing to do here. */
1547 return COI_SUCCESS;
1551 COIRESULT
1552 SYMBOL_VERSION (COIProcessUnloadLibrary, 1) (COIPROCESS in_Process,
1553 COILIBRARY in_Library)
1555 COITRACE ("COIProcessUnloadLibrary");
1557 assert (in_Process != NULL);
1558 assert (in_Library != NULL);
1560 const cmd_t cmd = CMD_CLOSE_LIBRARY;
1562 /* Convert input arguments. */
1563 Process *proc = (Process *) in_Process;
1565 start_critical_section ();
1567 /* Make target close library. */
1568 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1569 WRITE (proc->pipe_host2tgt, &in_Library, sizeof (void *));
1571 finish_critical_section ();
1573 return COI_SUCCESS;
1577 uint64_t
1578 SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
1580 COITRACE ("COIPerfGetCycleFrequency");
1582 return (uint64_t) CYCLE_FREQUENCY;
1586 COIRESULT
1587 SYMBOL_VERSION (COIPipelineClearCPUMask, 1) (COI_CPU_MASK *in_Mask)
1589 COITRACE ("COIPipelineClearCPUMask");
1591 /* Looks like we have nothing to do here. */
1593 return COI_SUCCESS;
1597 COIRESULT
1598 SYMBOL_VERSION (COIPipelineSetCPUMask, 1) (COIPROCESS in_Process,
1599 uint32_t in_CoreID,
1600 uint8_t in_ThreadID,
1601 COI_CPU_MASK *out_pMask)
1603 COITRACE ("COIPipelineSetCPUMask");
1605 /* Looks like we have nothing to do here. */
1607 return COI_SUCCESS;
1611 COIRESULT
1612 SYMBOL_VERSION (COIEngineGetInfo, 1) (COIENGINE in_EngineHandle, // Ignored
1613 uint32_t in_EngineInfoSize, // Ignored
1614 COI_ENGINE_INFO *out_pEngineInfo)
1616 COITRACE ("COIEngineGetInfo");
1618 assert (out_pEngineInfo != NULL);
1620 out_pEngineInfo->ISA = COI_DEVICE_KNL;
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;
1630 return COI_SUCCESS;
1633 } // extern "C"