]> git.ipfire.org Git - thirdparty/gcc.git/blob - liboffloadmic/runtime/emulator/coi_host.cpp
3425920a4a1232bca2ef4cbd6efa48f0253df7a7
[thirdparty/gcc.git] / liboffloadmic / runtime / emulator / coi_host.cpp
1 /*
2 Copyright (c) 2014 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 "coi_host.h"
31
32 #include "coi_version_asm.h"
33
34 #define CYCLE_FREQUENCY 1000000000
35
36 /* Environment variables. */
37 extern char **environ;
38
39 /* List of directories for removing on exit. */
40 char **tmp_dirs;
41 unsigned tmp_dirs_num = 0;
42
43 /* Number of KNC engines. */
44 long knc_engines_num;
45
46 /* Mutex to sync parallel execution. */
47 pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
48
49
50 typedef enum
51 {
52 BUFFER_NORMAL,
53 BUFFER_MEMORY
54 } buffer_t;
55
56 typedef struct
57 {
58 COI_ISA_TYPE type;
59 uint32_t index;
60 char *dir;
61 } Engine;
62
63 typedef struct
64 {
65 char *name;
66 void *ptr;
67 } Function;
68
69 typedef struct
70 {
71 int pipe_host;
72 int pipe_target;
73 } Pipeline;
74
75 typedef struct
76 {
77 pid_t pid;
78 Engine *engine;
79 Function **functions;
80 Pipeline *pipeline;
81 } Process;
82
83 typedef struct
84 {
85 buffer_t type;
86 char *name;
87 int fd;
88 int fd_target;
89 uint64_t size;
90 void *data;
91 void *data_target;
92 Process *process;
93 } Buffer;
94
95
96 static COIRESULT
97 read_long_env (const char *env_name, long *var, long var_default)
98 {
99 char *str = getenv (env_name);
100 char *s;
101
102 if (!str || *str == '\0')
103 *var = var_default;
104 else
105 {
106 errno = 0;
107 *var = strtol (str, &s, 0);
108 if (errno != 0 || s == str || *s != '\0')
109 COIERROR ("Variable %s has invalid value.", env_name);
110 }
111
112 return COI_SUCCESS;
113 }
114
115 __attribute__((constructor))
116 static void
117 init ()
118 {
119 if (read_long_env (OFFLOAD_EMUL_KNC_NUM_ENV, &knc_engines_num, 1)
120 == COI_ERROR)
121 exit (0);
122 }
123
124
125 /* Helper function for directory removing. */
126 static COIRESULT remove_directory (char *path)
127 {
128 char *file;
129 struct dirent *entry;
130 struct stat statfile;
131 DIR *dir = opendir (path);
132 if (dir == NULL)
133 COIERROR ("Cannot open directory %s.", dir);
134
135 while (entry = readdir (dir))
136 {
137 if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
138 continue;
139
140 MALLOC (char *, file, strlen (path) + strlen (entry->d_name) + 2);
141 sprintf (file, "%s/%s", path, entry->d_name);
142
143 if (stat (file, &statfile) < 0)
144 COIERROR ("Cannot retrieve information about file %s.", file);
145
146 if (S_ISDIR (statfile.st_mode))
147 {
148 if (remove_directory (file) == COI_ERROR)
149 return COI_ERROR;
150 }
151 else
152 {
153 if (unlink (file) < 0)
154 COIERROR ("Cannot unlink file %s.", file);
155 }
156
157 free (file);
158 }
159
160 if (closedir (dir) < 0)
161 COIERROR ("Cannot close directory %s.", path);
162 if (rmdir (path) < 0)
163 COIERROR ("Cannot remove directory %s.", path);
164
165 return COI_SUCCESS;
166 }
167
168 __attribute__((destructor))
169 static void
170 cleanup ()
171 {
172 unsigned i;
173 for (i = 0; i < tmp_dirs_num; i++)
174 {
175 remove_directory (tmp_dirs[i]);
176 free (tmp_dirs[i]);
177 }
178 if (tmp_dirs)
179 free (tmp_dirs);
180 }
181
182
183 extern "C"
184 {
185
186 COIRESULT
187 SYMBOL_VERSION (COIBufferCopy, 1) (COIBUFFER dest_buffer,
188 COIBUFFER source_buffer,
189 uint64_t dest_offset,
190 uint64_t source_offset,
191 uint64_t length,
192 COI_COPY_TYPE type,
193 uint32_t dependencies_num, // Ignored
194 const COIEVENT *dependencies, // Ignored
195 COIEVENT *completion) // Ignored
196 {
197 COITRACE ("COIBufferCopy");
198
199 /* Convert input arguments. */
200 Buffer *dest = (Buffer *) dest_buffer;
201 Buffer *source = (Buffer *) source_buffer;
202
203 /* Features of liboffload. */
204 assert (type == COI_COPY_UNSPECIFIED);
205
206 /* Start critical section. */
207 if (pthread_mutex_lock (&mutex) != 0)
208 COIERROR ("Cannot lock mutex.");
209
210 /* Map buffers if needed. */
211 if (dest->data == 0 && dest->type == BUFFER_NORMAL)
212 if (COIBufferMap (dest_buffer, 0, dest->size, (COI_MAP_TYPE) 0,
213 0, 0, 0, 0, 0) == COI_ERROR)
214 return COI_ERROR;
215 if (source->data == 0 && source->type == BUFFER_NORMAL)
216 if (COIBufferMap (source_buffer, 0, source->size, (COI_MAP_TYPE) 0,
217 0, 0, 0, 0, 0) == COI_ERROR)
218 return COI_ERROR;
219
220 /* Copy data. */
221 if (source->data != 0 && dest->data != 0)
222 memcpy ((void *) ((uintptr_t) dest->data+dest_offset),
223 (void *) ((uintptr_t) source->data+source_offset), length);
224 else
225 {
226 assert (dest->process == source->process);
227
228 Buffer *buffer;
229 cmd_t cmd = CMD_BUFFER_COPY;
230 Pipeline *pipeline = dest->process->pipeline;
231
232 /* Create intermediary buffer. */
233 if (COIBufferCreate (length, COI_BUFFER_NORMAL, 0, 0, 1,
234 (COIPROCESS*) &dest->process,
235 (COIBUFFER *) &buffer) == COI_ERROR)
236 return COI_ERROR;
237
238 /* Copy from source to intermediary buffer. */
239 if (source->data == 0)
240 {
241 assert (source->data_target != 0);
242
243 /* Send data to target. */
244 WRITE (pipeline->pipe_target, &cmd, sizeof (cmd_t));
245 WRITE (pipeline->pipe_target, &(buffer->data_target), sizeof (void *));
246 WRITE (pipeline->pipe_target, &(source->data_target), sizeof (void *));
247 WRITE (pipeline->pipe_target, &(buffer->size), sizeof (uint64_t));
248
249 /* Receive data from target. */
250 READ (pipeline->pipe_host, &cmd, sizeof (cmd_t));
251 }
252 else
253 {
254 if (COIBufferCopy ((COIBUFFER) buffer, source_buffer, 0, source_offset,
255 length, type, 0, 0, 0) == COI_ERROR)
256 return COI_ERROR;
257 }
258
259 /* Copy from intermediary buffer to dest. */
260 if (dest->data == 0)
261 {
262 assert (dest->data_target != 0);
263
264 /* Send data to target. */
265 WRITE (pipeline->pipe_target, &cmd, sizeof (cmd_t));
266 WRITE (pipeline->pipe_target, &(dest->data_target), sizeof (void *));
267 WRITE (pipeline->pipe_target, &(buffer->data_target), sizeof (void *));
268 WRITE (pipeline->pipe_target, &(buffer->size), sizeof (uint64_t));
269
270 /* Receive data from target. */
271 READ (pipeline->pipe_host, &cmd, sizeof (cmd_t));
272 }
273 else
274 {
275 if (COIBufferCopy (dest_buffer, (COIBUFFER) buffer, dest_offset,
276 0, length, type, 0, 0, 0) == COI_ERROR)
277 return COI_ERROR;
278 }
279
280 /* Unmap on target and destroy intermediary buffer. */
281 if (COIBufferDestroy ((COIBUFFER) buffer) == COI_ERROR)
282 return COI_ERROR;
283 }
284
285 /* Unmap buffers if needed. */
286 if (dest->type == BUFFER_NORMAL)
287 if (COIBufferUnmap ((COIMAPINSTANCE) dest, 0, 0, 0) == COI_ERROR)
288 return COI_ERROR;
289 if (source->type == BUFFER_NORMAL)
290 if (COIBufferUnmap ((COIMAPINSTANCE) source, 0, 0, 0) == COI_ERROR)
291 return COI_ERROR;
292
293 /* Finish critical section. */
294 if (pthread_mutex_unlock (&mutex) != 0)
295 COIERROR ("Cannot unlock mutex.");
296
297 return COI_SUCCESS;
298 }
299
300
301 COIRESULT
302 SYMBOL_VERSION (COIBufferCreate, 1) (uint64_t size,
303 COI_BUFFER_TYPE type,
304 uint32_t flags,
305 const void *init_data,
306 uint32_t processes_num,
307 const COIPROCESS *processes,
308 COIBUFFER *buffer)
309 {
310 COITRACE ("COIBufferCreate");
311
312 char *shm_name;
313 cmd_t cmd = CMD_BUFFER_MAP;
314 int shm_fd;
315 const int ullong_max_len = 20;
316 size_t len;
317 unsigned long long i;
318
319 Buffer *buf;
320 Pipeline *pipeline;
321
322 /* Features of liboffload. */
323 assert (type == COI_BUFFER_NORMAL);
324 assert ((flags & COI_SINK_MEMORY) == 0);
325 assert ((flags & COI_SAME_ADDRESS_SINKS) == 0);
326 assert ((flags & COI_SAME_ADDRESS_SINKS_AND_SOURCE) == 0);
327 assert (init_data == 0);
328 assert (processes_num == 1);
329
330 /* Create shared memory with an unique name. */
331 MALLOC (char *, shm_name, strlen (SHM_NAME) + ullong_max_len + 1);
332 for (i = 0; i >= 0; i++)
333 {
334 sprintf (shm_name, SHM_NAME"%lu", i);
335 shm_fd = shm_open (shm_name, O_CLOEXEC | O_CREAT | O_EXCL | O_RDWR,
336 S_IRUSR | S_IWUSR);
337 if (shm_fd > 0)
338 break;
339 }
340 if (ftruncate (shm_fd, size) < 0)
341 COIERROR ("Cannot truncate shared memory file.");
342
343 /* Create buffer. */
344 MALLOC (Buffer *, buf, sizeof (Buffer));
345 buf->data = 0;
346 buf->fd = shm_fd;
347 buf->process = (Process *) processes[0];
348 buf->size = size;
349 buf->type = BUFFER_NORMAL;
350 STRDUP (buf->name, shm_name);
351
352 /* Map buffer on target. */
353 len = strlen (buf->name) + 1;
354 pipeline = buf->process->pipeline;
355
356 /* Start critical section. */
357 if (pthread_mutex_lock (&mutex) != 0)
358 COIERROR ("Cannot lock mutex.");
359
360 /* Send data to target. */
361 WRITE (pipeline->pipe_target, &cmd, sizeof (cmd_t));
362 WRITE (pipeline->pipe_target, &len, sizeof (size_t));
363 WRITE (pipeline->pipe_target, buf->name, len);
364 WRITE (pipeline->pipe_target, &(buf->size), sizeof (uint64_t));
365
366 /* Receive data from target. */
367 READ (pipeline->pipe_host, &(buf->fd_target), sizeof (int));
368 READ (pipeline->pipe_host, &(buf->data_target), sizeof (void *));
369
370 /* Finish critical section. */
371 if (pthread_mutex_unlock (&mutex) != 0)
372 COIERROR ("Cannot unlock mutex.");
373
374 /* Prepare output arguments. */
375 *buffer = (COIBUFFER) buf;
376
377 /* Clean up. */
378 free (shm_name);
379
380 return COI_SUCCESS;
381 }
382
383
384 COIRESULT
385 SYMBOL_VERSION (COIBufferCreateFromMemory, 1) (uint64_t size,
386 COI_BUFFER_TYPE type,
387 uint32_t flags,
388 void *memory,
389 uint32_t processes_num,
390 const COIPROCESS *processes,
391 COIBUFFER *buffer)
392 {
393 COITRACE ("COIBufferCreateFromMemory");
394
395 Buffer *buf;
396
397 /* Features of liboffload. */
398 assert (type == COI_BUFFER_NORMAL);
399 assert ((flags & COI_SAME_ADDRESS_SINKS) == 0);
400 assert ((flags & COI_SAME_ADDRESS_SINKS_AND_SOURCE) == 0);
401 assert (processes_num == 1);
402
403 /* Create buffer. */
404 MALLOC (Buffer *, buf, sizeof (Buffer));
405 buf->data = (flags & COI_SINK_MEMORY) == 0 ? memory : 0;
406 buf->data_target = (flags & COI_SINK_MEMORY) != 0 ? memory : 0;
407 buf->process = (Process *) processes[0];
408 buf->size = size;
409 buf->type = BUFFER_MEMORY;
410
411 /* Prepare output argument. */
412 *buffer = (COIBUFFER) buf;
413
414 return COI_SUCCESS;
415 }
416
417
418 COIRESULT
419 SYMBOL_VERSION (COIBufferDestroy, 1) (COIBUFFER buffer)
420 {
421 COITRACE ("COIBufferDestroy");
422
423 cmd_t cmd = CMD_BUFFER_UNMAP;
424
425 /* Convert input arguments. */
426 Buffer *buf = (Buffer *) buffer;
427 Pipeline *pipeline = buf->process->pipeline;
428
429 /* Unmap buffer on host. */
430 if (buf->data != 0 && buf->type == BUFFER_NORMAL)
431 if (COIBufferUnmap ((COIMAPINSTANCE) buffer, 0, 0, 0) == COI_ERROR)
432 return COI_ERROR;
433
434 /* Unmap buffer on target. */
435 if (buf->data_target != 0)
436 {
437 /* Start critical section. */
438 if (pthread_mutex_lock (&mutex) != 0)
439 COIERROR ("Cannot lock mutex.");
440
441 /* Send data to target. */
442 WRITE (pipeline->pipe_target, &cmd, sizeof (cmd_t));
443 WRITE (pipeline->pipe_target, &(buf->fd_target), sizeof (int));
444 WRITE (pipeline->pipe_target, &(buf->data_target), sizeof (void *));
445 WRITE (pipeline->pipe_target, &(buf->size), sizeof (uint64_t));
446
447 /* Receive data from target. */
448 READ (pipeline->pipe_host, &cmd, sizeof (cmd_t));
449
450 /* Finish critical section. */
451 if (pthread_mutex_unlock (&mutex) != 0)
452 COIERROR ("Cannot unlock mutex.");
453 }
454
455 /* Unlink shared memory. */
456 if (buf->type == BUFFER_NORMAL)
457 {
458 if (close (buf->fd) < 0)
459 COIERROR ("Cannot close shared memory file.");
460 if (shm_unlink (buf->name) < 0)
461 COIERROR ("Cannot unlink shared memory.");
462 free (buf->name);
463 }
464
465 /* Clean up. */
466 free (buf);
467
468 return COI_SUCCESS;
469 }
470
471
472 COIRESULT
473 SYMBOL_VERSION (COIBufferGetSinkAddress, 1) (COIBUFFER buffer,
474 uint64_t *data)
475 {
476 COITRACE ("COIBufferGetSinkAddress");
477
478 /* Convert input arguments. */
479 Buffer *buf = (Buffer *) buffer;
480
481 /* Here should come BUFFER_NORMAL buffer. */
482 assert (buf->type == BUFFER_NORMAL);
483
484 /* Prepare output argument. */
485 *data = (uint64_t) buf->data_target;
486
487 return COI_SUCCESS;
488 }
489
490
491 COIRESULT
492 SYMBOL_VERSION (COIBufferMap, 1) (COIBUFFER buffer,
493 uint64_t offset,
494 uint64_t length,
495 COI_MAP_TYPE type, // Ignored
496 uint32_t dependencies_num, // Ignored
497 const COIEVENT *dependencies, // Ignored
498 COIEVENT *completion, // Ignored
499 COIMAPINSTANCE *map_instance,
500 void **data)
501 {
502 COITRACE ("COIBufferMap");
503
504 /* Features of liboffload. */
505 assert (offset == 0);
506
507 /* Convert input arguments. */
508 Buffer *buf = (Buffer *) buffer;
509
510 /* Only BUFFER_NORMAL buffers should come here. */
511 assert (buf->type == BUFFER_NORMAL);
512
513 /* Map shared memory. */
514 buf->data = mmap (NULL, buf->size, PROT_READ | PROT_WRITE,
515 MAP_SHARED, buf->fd, 0);
516 if (buf->data == NULL)
517 COIERROR ("Cannot map shared memory.");
518
519 /* Prepare output arguments. */
520 if (map_instance != 0)
521 *map_instance = (COIMAPINSTANCE) buf;
522 if (data != 0)
523 *data = buf->data;
524
525 return COI_SUCCESS;
526 }
527
528
529 COIRESULT
530 SYMBOL_VERSION (COIBufferRead, 1) (COIBUFFER buffer,
531 uint64_t offset,
532 void *data,
533 uint64_t length,
534 COI_COPY_TYPE type,
535 uint32_t dependencies_num, // Ignored
536 const COIEVENT *dependencies, // Ignored
537 COIEVENT *completion) // Ignored
538 {
539 COITRACE ("COIBufferRead");
540
541 /* Convert input arguments. */
542 Buffer *buf = (Buffer *) buffer;
543
544 /* Features of liboffload. */
545 assert (type == COI_COPY_UNSPECIFIED);
546
547 /* Start critical section. */
548 if (pthread_mutex_lock (&mutex) != 0)
549 COIERROR ("Cannot lock mutex.");
550
551 /* Map buffers if needed. */
552 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
553 if (COIBufferMap (buffer, 0, buf->size, (COI_MAP_TYPE) 0,
554 0, 0, 0, 0, 0) == COI_ERROR)
555 return COI_ERROR;
556
557 /* Copy data. */
558 memcpy (data, (void *) ((uintptr_t) buf->data+offset), length);
559
560 /* Unmap buffers if needed. */
561 if (buf->type == BUFFER_NORMAL)
562 if (COIBufferUnmap ((COIMAPINSTANCE) buf, 0, 0, 0) == COI_ERROR)
563 return COI_ERROR;
564
565 /* Finish critical section. */
566 if (pthread_mutex_unlock (&mutex) != 0)
567 COIERROR ("Cannot unlock mutex.");
568
569 return COI_SUCCESS;
570 }
571
572
573 COIRESULT
574 SYMBOL_VERSION (COIBufferSetState, 1) (COIBUFFER buffer,
575 COIPROCESS process,
576 COI_BUFFER_STATE state,
577 COI_BUFFER_MOVE_FLAG flag,
578 uint32_t dependencies_num, // Ignored
579 const COIEVENT *dependencies, // Ignored
580 COIEVENT *completion) // Ignored
581 {
582 COITRACE ("COIBufferSetState");
583
584 /* Features of liboffload. */
585 assert (flag == COI_BUFFER_NO_MOVE);
586
587 /* Looks like we have nothing to do here. */
588
589 return COI_SUCCESS;
590 }
591
592
593 COIRESULT
594 SYMBOL_VERSION (COIBufferUnmap, 1) (COIMAPINSTANCE map_instance,
595 uint32_t dependencies_num, // Ignored
596 const COIEVENT *dependencies, // Ignored
597 COIEVENT *completion) // Ignored
598 {
599 COITRACE ("COIBufferUnmap");
600
601 /* Convert input arguments. */
602 Buffer *buffer = (Buffer *) map_instance;
603
604 /* Only BUFFER_NORMAL buffers should come here. */
605 assert (buffer->type == BUFFER_NORMAL);
606
607 /* Unmap shared memory. */
608 if (munmap (buffer->data, buffer->size) < 0)
609 COIERROR ("Cannot unmap shared memory.");
610
611 buffer->data = 0;
612
613 return COI_SUCCESS;
614 }
615
616
617 COIRESULT
618 SYMBOL_VERSION (COIBufferWrite, 1) (COIBUFFER buffer,
619 uint64_t offset,
620 const void *data,
621 uint64_t length,
622 COI_COPY_TYPE type,
623 uint32_t dependencies_num, // Ignored
624 const COIEVENT *dependencies, // Ignored
625 COIEVENT *completion) // Ignored
626 {
627 COITRACE ("COIBufferWrite");
628
629 /* Convert input arguments. */
630 Buffer *buf = (Buffer *) buffer;
631
632 /* Features of liboffload. */
633 assert (type == COI_COPY_UNSPECIFIED);
634
635 /* Start critical section. */
636 if (pthread_mutex_lock (&mutex) != 0)
637 COIERROR ("Cannot lock mutex.");
638
639 /* Map buffers if needed. */
640 if (buf->data == 0 && buf->type == BUFFER_NORMAL)
641 if (COIBufferMap (buffer, 0, buf->size, (COI_MAP_TYPE) 0,
642 0, 0, 0, 0, 0) == COI_ERROR)
643 return COI_ERROR;
644
645 /* Copy data. */
646 memcpy ((void *) ((uintptr_t) buf->data+offset), data, length);
647
648 /* Unmap buffers if needed. */
649 if (buf->type == BUFFER_NORMAL)
650 if (COIBufferUnmap ((COIMAPINSTANCE) buf, 0, 0, 0) == COI_ERROR)
651 return COI_ERROR;
652
653 /* Finish critical section. */
654 if (pthread_mutex_unlock (&mutex) != 0)
655 COIERROR ("Cannot unlock mutex.");
656
657 return COI_SUCCESS;
658 }
659
660
661 COIRESULT
662 SYMBOL_VERSION (COIEngineGetCount, 1) (COI_ISA_TYPE isa,
663 uint32_t *count)
664 {
665 COITRACE ("COIEngineGetCount");
666
667 /* Features of liboffload. */
668 assert (isa == COI_ISA_KNC);
669
670 /* Prepare output arguments. */
671 *count = knc_engines_num;
672
673 return COI_SUCCESS;
674 }
675
676
677 COIRESULT
678 SYMBOL_VERSION (COIEngineGetHandle, 1) (COI_ISA_TYPE isa,
679 uint32_t index,
680 COIENGINE *handle)
681 {
682 COITRACE ("COIEngineGetHandle");
683
684 Engine *engine;
685
686 /* Features of liboffload. */
687 assert (isa == COI_ISA_KNC);
688
689 /* Check engine index. */
690 if (index >= knc_engines_num)
691 COIERROR ("Wrong engine index.");
692
693 /* Create engine handle. */
694 MALLOC (Engine *, engine, sizeof (Engine));
695 engine->dir = NULL;
696 engine->index = index;
697 engine->type = isa;
698
699 /* Prepare output argument. */
700 *handle = (COIENGINE) engine;
701
702 return COI_SUCCESS;
703 }
704
705
706 COIRESULT
707 SYMBOL_VERSION (COIEventWait, 1) (uint16_t events_num, // Ignored
708 const COIEVENT *events, // Ignored
709 int32_t timeout, // Ignored
710 uint8_t wait_all,
711 uint32_t *signaled_num,
712 uint32_t *signaled_indices)
713 {
714 COITRACE ("COIEventWait");
715
716 /* Features of liboffload. */
717 assert (wait_all == 1);
718 assert (signaled_num == 0);
719 assert (signaled_indices == 0);
720
721 /* Looks like we have nothing to do here. */
722
723 return COI_SUCCESS;
724 }
725
726
727 COIRESULT
728 SYMBOL_VERSION (COIPipelineCreate, 1) (COIPROCESS process,
729 COI_CPU_MASK mask,
730 uint32_t stack_size, // Ignored
731 COIPIPELINE *pipeline)
732 {
733 COITRACE ("COIPipelineCreate");
734
735 /* Features of liboffload. */
736 assert (mask == 0);
737
738 /* Prepare output arguments. */
739 *pipeline = (COIPIPELINE) ((Process *) process)->pipeline;
740
741 return COI_SUCCESS;
742 }
743
744
745 COIRESULT
746 SYMBOL_VERSION (COIPipelineDestroy, 1) (COIPIPELINE pipeline)
747 {
748 COITRACE ("COIPipelineDestroy");
749
750 /* Do nothing here. Pipeline will be closed during COIProcessDestroy. */
751
752 return COI_SUCCESS;
753 }
754
755
756 COIRESULT
757 SYMBOL_VERSION (COIPipelineRunFunction, 1) (COIPIPELINE pipeline,
758 COIFUNCTION function,
759 uint32_t buffers_num,
760 const COIBUFFER *buffers,
761 const COI_ACCESS_FLAGS *access_flags, // Ignored
762 uint32_t dependencies_num, // Ignored
763 const COIEVENT *dependencies, // Ignored
764 const void *misc_data,
765 uint16_t misc_data_len,
766 void *return_data,
767 uint16_t return_data_len,
768 COIEVENT *completion) // Ignored
769 {
770 COITRACE ("COIPipelineRunFunction");
771
772 cmd_t cmd = CMD_RUN_FUNCTION;
773 int ret_len;
774 uint32_t i;
775 uint64_t size;
776 void *ptr;
777
778 /* Convert input arguments. */
779 Buffer **bufs = (Buffer **) buffers;
780 Function *func = (Function *) function;
781 Pipeline *pipe = (Pipeline *) pipeline;
782
783 /* Start critical section. */
784 if (pthread_mutex_lock (&mutex) != 0)
785 COIERROR ("Cannot lock mutex.");
786
787 /* Send data to target. */
788 WRITE (pipe->pipe_target, &cmd, sizeof (cmd_t));
789 WRITE (pipe->pipe_target, &(func->ptr), sizeof (void *));
790 WRITE (pipe->pipe_target, &buffers_num, sizeof (uint32_t));
791 for (i = 0; i < buffers_num; i++)
792 {
793 WRITE (pipe->pipe_target, &(bufs[i]->size), sizeof (uint64_t));
794 WRITE (pipe->pipe_target, &(bufs[i]->data_target), sizeof (void *));
795 }
796 WRITE (pipe->pipe_target, &misc_data_len, sizeof (uint16_t));
797 if (misc_data_len > 0)
798 WRITE (pipe->pipe_target, misc_data, misc_data_len);
799 WRITE (pipe->pipe_target, &return_data_len, sizeof (uint16_t));
800
801 /* Receive data from target. In emulator we don't need any asynchronous data
802 transfer, so we wait for target process whether it has any data or not. */
803 ret_len = read (pipe->pipe_host, return_data_len > 0 ? return_data : &cmd,
804 return_data_len > 0 ? return_data_len : sizeof (cmd_t));
805 if (ret_len == 0)
806 return COI_PROCESS_DIED;
807 else if (ret_len != (return_data_len > 0 ? return_data_len : sizeof (cmd_t)))
808 COIERROR ("Cannot read from pipe.");
809
810 /* Finish critical section. */
811 if (pthread_mutex_unlock (&mutex) != 0)
812 COIERROR ("Cannot unlock mutex.");
813
814 return COI_SUCCESS;
815 }
816
817
818 COIRESULT
819 SYMBOL_VERSION (COIProcessCreateFromMemory, 1) (COIENGINE engine,
820 const char *bin_name,
821 const void *bin_buffer,
822 uint64_t bin_buffer_len,
823 int argc,
824 const char **argv,
825 uint8_t inherit_env,
826 const char **additional_env,
827 uint8_t proxy_active, // Ignored
828 const char *proxyfs_root, // Ignored
829 uint64_t buffer_space, // Ignored
830 const char *lib_search_path,
831 const char *file_of_origin, // Ignored
832 uint64_t file_of_origin_offset, // Ignored
833 COIPROCESS *process)
834 {
835 COITRACE ("COIProcessCreateFromMemory");
836
837 const int run_max_args_num = 128;
838 char **envp;
839 char *run_argv[run_max_args_num];
840 char *emul_run = getenv (OFFLOAD_EMUL_RUN_ENV);
841 char *env_name, *tok;
842 char *pipe_host_path, *pipe_target_path, *pipes_path, *target_exe;
843 FILE *file;
844 int fd;
845 int i, j, env_i, env_num;
846 int pipe_host, pipe_target;
847 const int uint_max_len = 11;
848 pid_t pid;
849 Pipeline *pipeline;
850 Process *proc;
851
852 /* Features of liboffload. */
853 assert (argc == 0);
854 assert (argv == 0);
855
856 /* Convert input arguments. */
857 Engine *eng = (Engine *) engine;
858
859 /* Create temporary directory for engine files. */
860 assert (eng->dir == NULL);
861 STRDUP (eng->dir, ENGINE_PATH);
862 if (mkdtemp (eng->dir) == NULL)
863 COIERROR ("Cannot create temporary directory %s.", eng->dir);
864
865 /* Save path to engine directory for clean up on exit. */
866 tmp_dirs_num++;
867 tmp_dirs = (char **) realloc (tmp_dirs, tmp_dirs_num * sizeof (char *));
868 if (!tmp_dirs)
869 COIERROR ("Cannot allocate memory.");
870 STRDUP (tmp_dirs[tmp_dirs_num - 1], eng->dir);
871
872 /* Create target executable file. */
873 MALLOC (char *, target_exe, strlen (eng->dir) + strlen (bin_name) + 2);
874 sprintf (target_exe, "%s/%s", eng->dir, bin_name);
875 fd = open (target_exe, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
876 if (fd < 0)
877 COIERROR ("Cannot create file %s.", target_exe);
878 file = fdopen (fd, "wb");
879 if (file == NULL)
880 COIERROR ("Cannot associate stream with file descriptor.");
881 if (fwrite (bin_buffer, 1, bin_buffer_len, file) != bin_buffer_len)
882 COIERROR ("Cannot write in file %s.", target_exe);
883 if (fclose (file) != 0)
884 COIERROR ("Cannot close file %s.", target_exe);
885
886 /* Fix file permissions. */
887 if (chmod (target_exe, S_IRWXU) < 0)
888 COIERROR ("Cannot change permissions for file %s.", target_exe);
889
890 /* Create directory for pipes to prevent names collision. */
891 MALLOC (char *, pipes_path, strlen (PIPES_PATH) + strlen (eng->dir) + 1);
892 sprintf (pipes_path, "%s"PIPES_PATH, eng->dir);
893 if (mkdir (pipes_path, S_IRWXU) < 0)
894 COIERROR ("Cannot create folder %s.", pipes_path);
895
896 /* Create pipes. */
897 MALLOC (char *, pipe_host_path,
898 strlen (PIPE_HOST_PATH) + strlen (eng->dir) + 1);
899 MALLOC (char *, pipe_target_path,
900 strlen (PIPE_TARGET_PATH) + strlen (eng->dir) + 1);
901 if (pipe_target_path == NULL)
902 COIERROR ("Cannot allocate memory.");
903 sprintf (pipe_host_path, "%s"PIPE_HOST_PATH, eng->dir);
904 sprintf (pipe_target_path, "%s"PIPE_TARGET_PATH, eng->dir);
905 if (mkfifo (pipe_host_path, S_IRUSR | S_IWUSR) < 0)
906 COIERROR ("Cannot create pipe %s.", pipe_host_path);
907 if (mkfifo (pipe_target_path, S_IRUSR | S_IWUSR) < 0)
908 COIERROR ("Cannot create pipe %s.", pipe_target_path);
909
910 /* Prepare argv. */
911 if (emul_run == NULL || strcmp (emul_run, "") == 0)
912 {
913 STRDUP (run_argv[0], target_exe);
914 run_argv[1] = (char *) NULL;
915 }
916 else
917 {
918 char *ptr, *tmp;
919 i = 0;
920 STRDUP (tmp, emul_run);
921 tok = strtok_r (tmp, " ", &ptr);
922 while (tok != NULL)
923 {
924 if (i >= run_max_args_num)
925 COIERROR ("Run command has too many arguments.");
926 STRDUP (run_argv[i++], tok);
927 tok = strtok_r (NULL, " ", &ptr);
928 }
929 STRDUP (run_argv[i], target_exe);
930 run_argv[i+1] = (char *) NULL;
931 free (tmp);
932 }
933
934 /* Prepare envp. */
935 /* FIXME: take into account additional_env. */
936 assert (additional_env == NULL);
937
938 env_num = 0;
939 if (inherit_env == true)
940 while (environ[env_num++]);
941 env_num += 4; // LD_LIBRARY_PATH, MIC_DIR, MIC_INDEX, NULL
942
943 MALLOC (char **, envp, env_num * sizeof (char *));
944
945 env_i = 0;
946 if (inherit_env == true)
947 for (i = 0; environ[i] != NULL; i++)
948 {
949 STRDUP (env_name, environ[i]);
950 for (j = 0; env_name[j] != '=' && env_name[j] != '\0'; j++);
951 env_name[j] = '\0';
952 if (strcmp (env_name, "LD_LIBRARY_PATH") != 0
953 && strcmp (env_name, MIC_DIR_ENV) != 0
954 && strcmp (env_name, MIC_INDEX_ENV) != 0)
955 STRDUP (envp[env_i++], environ[i]);
956 free (env_name);
957 }
958
959 MALLOC (char *, envp[env_i], strlen (MIC_DIR_ENV) + strlen (eng->dir) + 2);
960 sprintf (envp[env_i], "%s=%s", MIC_DIR_ENV, eng->dir);
961
962 MALLOC (char *, envp[env_i+1], strlen (MIC_INDEX_ENV) + uint_max_len + 1);
963 sprintf (envp[env_i+1], "%s=%u", MIC_INDEX_ENV, eng->index);
964
965 MALLOC (char *, envp[env_i+2],
966 strlen ("LD_LIBRARY_PATH=") + strlen (lib_search_path) + 1);
967 sprintf (envp[env_i+2], "LD_LIBRARY_PATH=%s", lib_search_path);
968
969 envp[env_i+3] = (char *) NULL;
970
971 /* Create target process. */
972 pid = vfork ();
973 if (pid < 0)
974 COIERROR ("Cannot create child process.");
975
976 if (pid == 0)
977 {
978 /* Run target executable. */
979 if (execvpe (run_argv[0], run_argv, envp) == -1)
980 COIERROR ("Cannot execute file %s.", target_exe);
981 }
982
983 /* Open pipes. */
984 pipe_host = open (pipe_host_path, O_CLOEXEC | O_RDONLY);
985 if (pipe_host < 0)
986 COIERROR ("Cannot open target-to-host pipe.");
987 pipe_target = open (pipe_target_path, O_CLOEXEC | O_WRONLY);
988 if (pipe_target < 0)
989 COIERROR ("Cannot open host-to-target pipe.");
990
991 /* Create pipeline handle. */
992 MALLOC (Pipeline *, pipeline, sizeof (Pipeline));
993 pipeline->pipe_host = pipe_host;
994 pipeline->pipe_target = pipe_target;
995
996 /* Create process handle. */
997 MALLOC (Process *, proc, sizeof (Process));
998 proc->pid = pid;
999 proc->engine = eng;
1000 proc->functions = 0;
1001 proc->pipeline = pipeline;
1002
1003 /* Prepare output arguments. */
1004 *process = (COIPROCESS) proc;
1005
1006 /* Clean up. */
1007 for (i = 0; run_argv[i] != NULL; i++)
1008 free (run_argv[i]);
1009 for (i = 0; envp[i] != NULL; i++)
1010 free (envp[i]);
1011 free (envp);
1012 free (pipe_host_path);
1013 free (pipe_target_path);
1014 free (pipes_path);
1015 free (target_exe);
1016
1017 return COI_SUCCESS;
1018 }
1019
1020
1021 COIRESULT
1022 SYMBOL_VERSION (COIProcessDestroy, 1) (COIPROCESS process,
1023 int32_t wait_timeout, // Ignored
1024 uint8_t force,
1025 int8_t *proc_return,
1026 uint32_t *reason)
1027 {
1028 COITRACE ("COIProcessDestroy");
1029
1030 int i;
1031
1032 /* Convert input arguments. */
1033 Process *proc = (Process *) process;
1034
1035 /* Close pipeline. */
1036 if (close (proc->pipeline->pipe_host) < 0)
1037 COIERROR ("Cannot close target-to-host pipe.");
1038 if (close (proc->pipeline->pipe_target) < 0)
1039 COIERROR ("Cannot close host-to-target pipe.");
1040 free (proc->pipeline);
1041
1042 /* Shutdown target process by force. */
1043 if (force)
1044 kill (proc->pid, SIGTERM);
1045
1046 /* Clean up. */
1047 for (i = 0; proc->functions[i] != 0; i++)
1048 {
1049 free (proc->functions[i]->name);
1050 free (proc->functions[i]);
1051 }
1052 free (proc->engine->dir);
1053 free (proc->engine);
1054 free (proc->functions);
1055 free (proc);
1056
1057 /* Prepare output arguments. */
1058 *proc_return = 0;
1059 *reason = 0;
1060
1061 return COI_SUCCESS;
1062 }
1063
1064
1065 COIRESULT
1066 SYMBOL_VERSION (COIProcessGetFunctionHandles, 1) (COIPROCESS process,
1067 uint32_t functions_num,
1068 const char **function_names,
1069 COIFUNCTION *function_handles)
1070 {
1071 COITRACE ("COIProcessGetFunctionHandles");
1072
1073 cmd_t cmd = CMD_GET_FUNCTION_HANDLE;
1074 Function *function;
1075 size_t len;
1076 void *ptr;
1077 uint32_t i;
1078
1079 /* Convert input arguments. */
1080 Process *proc = (Process *) process;
1081
1082 /* This function should be called once for the process. */
1083 assert (proc->functions == 0);
1084
1085 /* Create array of function pointers. Last element is 0, what shows
1086 the end of the array. This array is used to free memory when process
1087 is destroyed. */
1088 proc->functions = (Function **) calloc (functions_num + 1,
1089 sizeof (Function *));
1090 if (proc->functions == NULL)
1091 COIERROR ("Cannot allocate memory.");
1092
1093 /* Get handles for functions. */
1094 for (i = 0; i < functions_num; i++)
1095 {
1096 MALLOC (Function *, function, sizeof (Function));
1097
1098 len = strlen (function_names[i]) + 1;
1099
1100 /* Start critical section. */
1101 if (pthread_mutex_lock (&mutex) != 0)
1102 COIERROR ("Cannot lock mutex.");
1103
1104 /* Send data to target. */
1105 WRITE (proc->pipeline->pipe_target, &cmd, sizeof (cmd_t));
1106 WRITE (proc->pipeline->pipe_target, &len, sizeof (size_t));
1107 WRITE (proc->pipeline->pipe_target, function_names[i], len);
1108
1109 /* Receive data from target. */
1110 READ (proc->pipeline->pipe_host, &ptr, sizeof (void *));
1111
1112 /* Finish critical section. */
1113 if (pthread_mutex_unlock (&mutex) != 0)
1114 COIERROR ("Cannot unlock mutex.");
1115
1116 /* Prepare output arguments. */
1117 STRDUP (function->name, function_names[i]);
1118 if (function->name == NULL)
1119 COIERROR ("Cannot allocate memory.");
1120 function->ptr = ptr;
1121 function_handles[i] = (COIFUNCTION) function;
1122
1123 /* Save function pointer. */
1124 proc->functions[i] = function;
1125 }
1126
1127 return COI_SUCCESS;
1128 }
1129
1130
1131 COIRESULT
1132 SYMBOL_VERSION (COIProcessLoadLibraryFromMemory, 2) (COIPROCESS process,
1133 const void *lib_buffer,
1134 uint64_t lib_buffer_len,
1135 const char *lib_name,
1136 const char *lib_search_path,
1137 const char *file_of_origin, // Ignored
1138 uint64_t file_from_origin_offset, // Ignored
1139 uint32_t flags, // Ignored
1140 COILIBRARY *library) // Ignored
1141 {
1142 COITRACE ("COIProcessLoadLibraryFromMemory");
1143
1144 char *lib_path;
1145 cmd_t cmd = CMD_OPEN_LIBRARY;
1146 int fd;
1147 FILE *file;
1148 size_t len;
1149
1150 /* Convert input arguments. */
1151 Process *proc = (Process *) process;
1152
1153 /* Create target library file. */
1154 MALLOC (char *, lib_path,
1155 strlen (proc->engine->dir) + strlen (lib_name) + 2);
1156 sprintf (lib_path, "%s/%s", proc->engine->dir, lib_name);
1157 fd = open (lib_path, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
1158 if (fd < 0)
1159 COIERROR ("Cannot create file %s.", lib_path);
1160 file = fdopen (fd, "wb");
1161 if (file == NULL)
1162 COIERROR ("Cannot associate stream with file descriptor.");
1163 if (fwrite (lib_buffer, 1, lib_buffer_len, file) != lib_buffer_len)
1164 COIERROR ("Cannot write in file %s.", lib_path);
1165 if (fclose (file) != 0)
1166 COIERROR ("Cannot close file %s.", lib_path);
1167
1168 len = strlen (lib_path) + 1;
1169
1170 /* Start critical section. */
1171 if (pthread_mutex_lock (&mutex) != 0)
1172 COIERROR ("Cannot lock mutex.");
1173
1174 /* Make target open library. */
1175 WRITE (proc->pipeline->pipe_target, &cmd, sizeof (cmd_t));
1176 WRITE (proc->pipeline->pipe_target, &len, sizeof (size_t));
1177 WRITE (proc->pipeline->pipe_target, lib_path, len);
1178
1179 /* Finish critical section. */
1180 if (pthread_mutex_unlock (&mutex) != 0)
1181 COIERROR ("Cannot unlock mutex.");
1182
1183 /* Clean up. */
1184 free (lib_path);
1185
1186 return COI_SUCCESS;
1187 }
1188
1189
1190 COIRESULT
1191 SYMBOL_VERSION (COIProcessRegisterLibraries, 1) (uint32_t libraries_num,
1192 const void **libraries,
1193 const uint64_t *library_sizes,
1194 const char **files_of_origin,
1195 const uint64_t *file_of_origin_offsets)
1196 {
1197 COITRACE ("COIProcessRegisterLibraries");
1198
1199 /* Looks like we have nothing to do here. */
1200
1201 return COI_SUCCESS;
1202 }
1203
1204
1205 uint64_t
1206 SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
1207 {
1208 COITRACE ("COIPerfGetCycleFrequency");
1209
1210 return (uint64_t) CYCLE_FREQUENCY;
1211 }
1212
1213 } // extern "C"
1214