1 /*
2 Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved.
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
30 #include <set>
31 #include <map>
32 #include <queue>
33
34 #include "coi_host.h"
35
36 #include "coi_version_asm.h"
37
38 #define CYCLE_FREQUENCY 1000000000
39
40 enum buffer_t
41 {
42 BUFFER_NORMAL,
43 BUFFER_MEMORY
44 };
45
46 struct Engine
47 {
48 COI_ISA_TYPE type;
49 uint32_t index;
50 char *dir;
51 };
52
53 struct Function
54 {
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;
64 };
65
66 struct Callback
67 {
68 COI_EVENT_CALLBACK ptr;
69 const void *data;
70 };
71
72 struct Process
73 {
74 pid_t pid;
75 int pipe_host2tgt;
76 int pipe_tgt2host;
77 Engine *engine;
78 void **functions;
79 };
80
81 struct 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
94 struct Buffer
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;
104 };
105
106
107 /* Environment variables. */
108 extern char **environ;
109
110 /* List of directories for removing on exit. */
111 static char **tmp_dirs;
112 static unsigned tmp_dirs_num;
113
114 /* Number of emulated MIC engines. */
115 static long num_engines;
116
117 /* Number of the last COI pipeline. */
118 static uint32_t max_pipeline_num;
119
120 /* Set of undestroyed pipelines. */
121 static std::set<Pipeline *> pipelines;
122
123 /* Number of the last COI event, the event #0 is always signalled. */
124 static uint64_t max_event_num = 1;
125
126 /* Set of created COI events, which are not signalled. */
127 static std::set<uint64_t> non_signalled_events;
128
129 /* Set of COI events, which encountered errors. */
130 static std::map<uint64_t, COIRESULT> errored_events;
131
132 /* Set of registered callbacks, indexed by event number. */
133 static std::map<uint64_t, Callback> callbacks;
134
135 /* Mutex to sync parallel execution. */
136 static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
137
138
139 static COIRESULT
read_long_env(const char * env_name,long * var,long var_default)140 read_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))
159 static void
init()160 init ()
161 {
162 if (read_long_env (OFFLOAD_EMUL_NUM_ENV, &num_engines, 1) == COI_ERROR)
163 exit (0);
164 }
165
166
167 /* Helper function for directory removing. */
remove_directory(char * path)168 static 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))
211 static void
cleanup()212 cleanup ()
213 {
214 for (unsigned i = 0; i < tmp_dirs_num; i++)
215 {
216 remove_directory (tmp_dirs[i]);
217 free (tmp_dirs[i]);
218 }
219 free (tmp_dirs);
220 }
221
222 static COIRESULT
start_critical_section()223 start_critical_section ()
224 {
225 if (pthread_mutex_lock (&mutex) != 0)
226 COIERROR ("Cannot lock mutex.");
227 return COI_SUCCESS;
228 }
229
230 static COIRESULT
finish_critical_section()231 finish_critical_section ()
232 {
233 if (pthread_mutex_unlock (&mutex) != 0)
234 COIERROR ("Cannot unlock mutex.");
235 return COI_SUCCESS;
236 }
237
238 static bool
pipeline_is_destroyed(const Pipeline * pipeline)239 pipeline_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
247 static void
maybe_invoke_callback(const COIEVENT event,const COIRESULT result)248 maybe_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
260 static void
signal_event(const COIEVENT event,const COIRESULT result)261 signal_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
271 static COIRESULT
get_event_result(const COIEVENT event)272 get_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;
283 }
284
285
286 extern "C"
287 {
288
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)
299 {
300 COITRACE ("COIBufferCopy");
301
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
308 /* Convert input arguments. */
309 Buffer *dest = (Buffer *) in_DestBuffer;
310 Buffer *source = (Buffer *) in_SourceBuffer;
311
312 start_critical_section ();
313
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;
323
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
329 {
330 assert (dest->process == source->process);
331
332 Buffer *buffer;
333 cmd_t cmd = CMD_BUFFER_COPY;
334
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;
340
341 int pipe_host2tgt = dest->process->pipe_host2tgt;
342 int pipe_tgt2host = dest->process->pipe_tgt2host;
343
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. */
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));
354
355 /* Receive data from target. */
356 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
357 }
358 else
359 {
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;
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. */
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));
376
377 /* Receive data from target. */
378 READ (pipe_tgt2host, &cmd, sizeof (cmd_t));
379 }
380 else
381 {
382 if (COIBufferCopy (in_DestBuffer, (COIBUFFER) buffer, in_DestOffset,
383 0, in_Length, in_Type, 0, 0, 0) == COI_ERROR)
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
400 finish_critical_section ();
401
402 if (out_pCompletion)
403 out_pCompletion->opaque[0] = 0;
404
405 return COI_SUCCESS;
406 }
407
408
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)
417 {
418 COITRACE ("COIBufferCreate");
419
420 char *shm_name;
421 int shm_fd;
422 const int ullong_max_len = 20;
423
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);
433
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++)
437 {
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;
443 }
444 if (ftruncate (shm_fd, in_Size) < 0)
445 COIERROR ("Cannot truncate shared memory file.");
446
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);
455
456 /* Map buffer on target. */
457 size_t len = strlen (buf->name) + 1;
458
459 start_critical_section ();
460
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));
468
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 *));
473
474 finish_critical_section ();
475
476 /* Prepare output arguments. */
477 *out_pBuffer = (COIBUFFER) buf;
478
479 /* Clean up. */
480 free (shm_name);
481
482 return COI_SUCCESS;
483 }
484
485
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)
494 {
495 COITRACE ("COIBufferCreateFromMemory");
496
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);
504
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;
512
513 /* Prepare output argument. */
514 *out_pBuffer = (COIBUFFER) buf;
515
516 return COI_SUCCESS;
517 }
518
519
520 COIRESULT
521 SYMBOL_VERSION (COIBufferDestroy, 1) (COIBUFFER in_Buffer)
522 {
523 COITRACE ("COIBufferDestroy");
524
525 cmd_t cmd = CMD_BUFFER_UNMAP;
526
527 assert (in_Buffer != NULL);
528
529 /* Convert input arguments. */
530 Buffer *buf = (Buffer *) in_Buffer;
531
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;
536
537 /* Unmap buffer on target. */
538 if (buf->data_target != 0)
539 {
540 start_critical_section ();
541
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));
548
549 /* Receive data from target. */
550 READ (buf->process->pipe_tgt2host, &cmd, sizeof (cmd_t));
551
552 finish_critical_section ();
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. */
566 delete buf;
567
568 return COI_SUCCESS;
569 }
570
571
572 COIRESULT
573 SYMBOL_VERSION (COIBufferGetSinkAddress, 1) (COIBUFFER in_Buffer,
574 uint64_t *out_pAddress)
575 {
576 COITRACE ("COIBufferGetSinkAddress");
577
578 assert (in_Buffer != NULL);
579 assert (out_pAddress != NULL);
580
581 /* Convert input arguments. */
582 Buffer *buf = (Buffer *) in_Buffer;
583
584 /* Here should come BUFFER_NORMAL buffer. */
585 assert (buf->type == BUFFER_NORMAL);
586
587 /* Prepare output argument. */
588 *out_pAddress = (uint64_t) buf->data_target;
589
590 return COI_SUCCESS;
591 }
592
593
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)
604 {
605 COITRACE ("COIBufferMap");
606
607 /* Features of liboffloadmic. */
608 assert (in_Offset == 0);
609 assert (in_NumDependencies == 0);
610
611 /* Convert input arguments. */
612 Buffer *buf = (Buffer *) in_Buffer;
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. */
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;
631
632 return COI_SUCCESS;
633 }
634
635
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)
645 {
646 COITRACE ("COIBufferRead");
647
648 /* Features of liboffloadmic. */
649 assert (in_pDestData != NULL);
650 assert (in_Type == COI_COPY_UNSPECIFIED);
651 assert (in_NumDependencies == 0);
652
653 /* Convert input arguments. */
654 Buffer *buf = (Buffer *) in_SourceBuffer;
655
656 start_critical_section ();
657
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;
663
664 /* Copy data. */
665 memcpy (in_pDestData, (void *) ((uintptr_t) buf->data + in_Offset),
666 in_Length);
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
673 finish_critical_section ();
674
675 if (out_pCompletion)
676 out_pCompletion->opaque[0] = 0;
677
678 return COI_SUCCESS;
679 }
680
681
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)
690 {
691 COITRACE ("COIBufferSetState");
692
693 /* Features of liboffloadmic. */
694 assert (in_DataMove == COI_BUFFER_NO_MOVE);
695 assert (in_NumDependencies == 0);
696
697 /* Looks like we have nothing to do here. */
698
699 if (out_pCompletion)
700 out_pCompletion->opaque[0] = 0;
701
702 return COI_SUCCESS;
703 }
704
705
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)
711 {
712 COITRACE ("COIBufferUnmap");
713
714 /* Features of liboffloadmic. */
715 assert (in_MapInstance != NULL);
716 assert (in_NumDependencies == 0);
717
718 /* Convert input arguments. */
719 Buffer *buffer = (Buffer *) in_MapInstance;
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
730 if (out_pCompletion)
731 out_pCompletion->opaque[0] = 0;
732
733 return COI_SUCCESS;
734 }
735
736
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)
746 {
747 COITRACE ("COIBufferWrite");
748
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
755 /* Convert input arguments. */
756 Buffer *buf = (Buffer *) in_DestBuffer;
757
758 start_critical_section ();
759
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;
765
766 /* Copy data. */
767 memcpy ((void *) ((uintptr_t) buf->data + in_Offset), in_pSourceData,
768 in_Length);
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
775 finish_critical_section ();
776
777 if (out_pCompletion)
778 out_pCompletion->opaque[0] = 0;
779
780 return COI_SUCCESS;
781 }
782
783
784 COIRESULT
785 SYMBOL_VERSION (COIEngineGetCount, 1) (COI_ISA_TYPE isa,
786 uint32_t *count)
787 {
788 COITRACE ("COIEngineGetCount");
789
790 /* Features of liboffloadmic. */
791 assert (isa == COI_ISA_MIC);
792 assert (count != NULL);
793
794 /* Prepare output arguments. */
795 *count = num_engines;
796
797 return COI_SUCCESS;
798 }
799
800
801 COIRESULT
802 SYMBOL_VERSION (COIEngineGetHandle, 1) (COI_ISA_TYPE in_ISA,
803 uint32_t in_EngineIndex,
804 COIENGINE *out_pEngineHandle)
805 {
806 COITRACE ("COIEngineGetHandle");
807
808 /* Features of liboffloadmic. */
809 assert (in_ISA == COI_ISA_MIC);
810 assert (out_pEngineHandle != NULL);
811
812 /* Check engine index. */
813 if (in_EngineIndex >= num_engines)
814 COIERROR ("Wrong engine index.");
815
816 /* Create engine handle. */
817 Engine *engine = new Engine;
818 engine->dir = NULL;
819 engine->index = in_EngineIndex;
820 engine->type = in_ISA;
821
822 /* Prepare output argument. */
823 *out_pEngineHandle = (COIENGINE) engine;
824
825 return COI_SUCCESS;
826 }
827
828
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)
836 {
837 COITRACE ("COIEventWait");
838
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);
845
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 }
878
879 return COI_SUCCESS;
880 }
881
882
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)
888 {
889 COITRACE ("COIEventRegisterCallback");
890
891 /* Features of liboffloadmic. */
892 assert (in_Callback != NULL);
893 assert (in_UserData != NULL);
894 assert (in_Flags == 0);
895
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 ();
912
913 return COI_SUCCESS;
914 }
915
916
917 /* The start routine for the COI pipeline thread. */
918
919 static void *
pipeline_thread_routine(void * in_Pipeline)920 pipeline_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
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)
1018 {
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);
1053
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;
1068
1069 return COI_SUCCESS;
1070 }
1071
1072
1073 COIRESULT
1074 SYMBOL_VERSION (COIPipelineDestroy, 1) (COIPIPELINE in_Pipeline)
1075 {
1076 COITRACE ("COIPipelineDestroy");
1077
1078 assert (in_Pipeline != NULL);
1079
1080 /* Convert input arguments. */
1081 Pipeline *pipeline = (Pipeline *) in_Pipeline;
1082
1083 start_critical_section ();
1084 /* Remove pipeline from the set of undestroyed pipelines. */
1085 pipelines.erase (pipeline);
1086
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
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)
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++)
1131 {
1132 Buffer **bufs = (Buffer **) in_Buffers;
1133 func.bufs_size[i] = bufs[i]->size;
1134 func.bufs_data_target[i] = bufs[i]->data_target;
1135 }
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;
1152
1153 return COI_SUCCESS;
1154 }
1155
1156
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)
1173 {
1174 COITRACE ("COIProcessCreateFromMemory");
1175
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;
1180
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);
1190
1191 /* Convert input arguments. */
1192 Engine *eng = (Engine *) in_Engine;
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. */
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);
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. */
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);
1233
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);
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;
1256 int i = 0;
1257 STRDUP (tmp, emul_run);
1258 char *tok = strtok_r (tmp, " ", &ptr);
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);
1267 run_argv[i + 1] = (char *) NULL;
1268 free (tmp);
1269 }
1270
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
1276
1277 char **envp;
1278 MALLOC (char **, envp, env_num * sizeof (char *));
1279
1280 int env_i = 0;
1281 if (in_DupEnv == true)
1282 for (unsigned i = 0; environ[i] != NULL; i++)
1283 {
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);
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
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);
1301
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);
1305
1306 envp[env_i + 3] = (char *) NULL;
1307
1308 /* Create target process. */
1309 pid_t pid = vfork ();
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
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.");
1327
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;
1335
1336 /* Prepare output arguments. */
1337 *out_pProcess = (COIPROCESS) proc;
1338
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);
1349
1350 return COI_SUCCESS;
1351 }
1352
1353
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)
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
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)
1381 {
1382 COITRACE ("COIProcessDestroy");
1383
1384 assert (in_Process != NULL);
1385 assert (out_pProcessReturn != NULL);
1386 assert (out_pTerminationCode != NULL);
1387
1388 /* Convert input arguments. */
1389 Process *proc = (Process *) in_Process;
1390
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.");
1403
1404 /* Shutdown target process by force. */
1405 if (in_ForceDestroy)
1406 kill (proc->pid, SIGTERM);
1407
1408 /* Clean up. */
1409 free (proc->engine->dir);
1410 free (proc->functions);
1411 delete proc->engine;
1412 delete proc;
1413
1414 /* Prepare output arguments. */
1415 *out_pProcessReturn = 0;
1416 *out_pTerminationCode = 0;
1417
1418 return COI_SUCCESS;
1419 }
1420
1421
1422 COIRESULT
1423 SYMBOL_VERSION (COIProcessGetFunctionHandles, 1) (COIPROCESS in_Process,
1424 uint32_t in_NumFunctions,
1425 const char **in_ppFunctionNameArray,
1426 COIFUNCTION *out_pFunctionHandleArray)
1427 {
1428 COITRACE ("COIProcessGetFunctionHandles");
1429
1430 assert (in_Process != NULL);
1431 assert (in_ppFunctionNameArray != NULL);
1432 assert (out_pFunctionHandleArray != NULL);
1433
1434 /* Convert input arguments. */
1435 Process *proc = (Process *) in_Process;
1436
1437 /* This function should be called once for the process. */
1438 assert (proc->functions == NULL);
1439
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.");
1446
1447 /* Get handles for functions. */
1448 for (uint32_t i = 0; i < in_NumFunctions; i++)
1449 {
1450 size_t len = strlen (in_ppFunctionNameArray[i]) + 1;
1451
1452 start_critical_section ();
1453
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);
1459
1460 /* Receive data from target. */
1461 void *fn_ptr;
1462 READ (proc->pipe_tgt2host, &fn_ptr, sizeof (void *));
1463
1464 finish_critical_section ();
1465
1466 /* Save function pointer. */
1467 proc->functions[i] = fn_ptr;
1468
1469 /* Prepare output arguments. */
1470 out_pFunctionHandleArray[i] = (COIFUNCTION) fn_ptr;
1471 }
1472
1473 return COI_SUCCESS;
1474 }
1475
1476
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)
1487 {
1488 COITRACE ("COIProcessLoadLibraryFromMemory");
1489
1490 assert (in_Process != NULL);
1491 assert (in_pLibraryBuffer != NULL);
1492 assert (out_pLibrary != NULL);
1493
1494 /* Convert input arguments. */
1495 Process *proc = (Process *) in_Process;
1496
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);
1513
1514 start_critical_section ();
1515
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);
1521
1522 /* Receive data from target. */
1523 void *handle;
1524 READ (proc->pipe_tgt2host, &handle, sizeof (void *));
1525
1526 finish_critical_section ();
1527
1528 /* Clean up. */
1529 free (lib_path);
1530
1531 *out_pLibrary = (COILIBRARY) handle;
1532 return COI_SUCCESS;
1533 }
1534
1535
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
1542 {
1543 COITRACE ("COIProcessRegisterLibraries");
1544
1545 /* Looks like we have nothing to do here. */
1546
1547 return COI_SUCCESS;
1548 }
1549
1550
1551 COIRESULT
1552 SYMBOL_VERSION (COIProcessUnloadLibrary, 1) (COIPROCESS in_Process,
1553 COILIBRARY in_Library)
1554 {
1555 COITRACE ("COIProcessUnloadLibrary");
1556
1557 assert (in_Process != NULL);
1558 assert (in_Library != NULL);
1559
1560 const cmd_t cmd = CMD_CLOSE_LIBRARY;
1561
1562 /* Convert input arguments. */
1563 Process *proc = (Process *) in_Process;
1564
1565 start_critical_section ();
1566
1567 /* Make target close library. */
1568 WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t));
1569 WRITE (proc->pipe_host2tgt, &in_Library, sizeof (void *));
1570
1571 finish_critical_section ();
1572
1573 return COI_SUCCESS;
1574 }
1575
1576
1577 uint64_t
1578 SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
1579 {
1580 COITRACE ("COIPerfGetCycleFrequency");
1581
1582 return (uint64_t) CYCLE_FREQUENCY;
1583 }
1584
1585
1586 COIRESULT
1587 SYMBOL_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
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)
1602 {
1603 COITRACE ("COIPipelineSetCPUMask");
1604
1605 /* Looks like we have nothing to do here. */
1606
1607 return COI_SUCCESS;
1608 }
1609
1610
1611 COIRESULT
1612 SYMBOL_VERSION (COIEngineGetInfo, 1) (COIENGINE in_EngineHandle, // Ignored
1613 uint32_t in_EngineInfoSize, // Ignored
1614 COI_ENGINE_INFO *out_pEngineInfo)
1615 {
1616 COITRACE ("COIEngineGetInfo");
1617
1618 assert (out_pEngineInfo != NULL);
1619
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;
1629
1630 return COI_SUCCESS;
1631 }
1632
1633 } // extern "C"
1634
1635