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