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.  */
37extern char **environ;
38
39/* List of directories for removing on exit.  */
40char **tmp_dirs;
41unsigned tmp_dirs_num = 0;
42
43/* Number of KNC engines.  */
44long knc_engines_num;
45
46/* Mutex to sync parallel execution.  */
47pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
48
49
50typedef enum
51{
52  BUFFER_NORMAL,
53  BUFFER_MEMORY
54} buffer_t;
55
56typedef struct
57{
58  COI_ISA_TYPE type;
59  uint32_t index;
60  char *dir;
61} Engine;
62
63typedef struct
64{
65  char *name;
66  void *ptr;
67} Function;
68
69typedef struct
70{
71  int pipe_host;
72  int pipe_target;
73} Pipeline;
74
75typedef struct
76{
77  pid_t pid;
78  Engine *engine;
79  Function **functions;
80  Pipeline *pipeline;
81} Process;
82
83typedef 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
96static COIRESULT
97read_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))
116static void
117init ()
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.  */
126static 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))
169static void
170cleanup ()
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
183extern "C"
184{
185
186COIRESULT
187SYMBOL_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
301COIRESULT
302SYMBOL_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
384COIRESULT
385SYMBOL_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
418COIRESULT
419SYMBOL_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
472COIRESULT
473SYMBOL_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
491COIRESULT
492SYMBOL_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
529COIRESULT
530SYMBOL_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
573COIRESULT
574SYMBOL_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
593COIRESULT
594SYMBOL_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
617COIRESULT
618SYMBOL_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
661COIRESULT
662SYMBOL_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
677COIRESULT
678SYMBOL_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
706COIRESULT
707SYMBOL_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
727COIRESULT
728SYMBOL_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
745COIRESULT
746SYMBOL_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
756COIRESULT
757SYMBOL_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
818COIRESULT
819SYMBOL_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
1021COIRESULT
1022SYMBOL_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
1065COIRESULT
1066SYMBOL_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
1131COIRESULT
1132SYMBOL_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
1190COIRESULT
1191SYMBOL_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
1205uint64_t
1206SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
1207{
1208  COITRACE ("COIPerfGetCycleFrequency");
1209
1210  return (uint64_t) CYCLE_FREQUENCY;
1211}
1212
1213} // extern "C"
1214
1215