]>
Commit | Line | Data |
---|---|---|
5f520819 | 1 | /* |
df26a50d | 2 | Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved. |
5f520819 KY |
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 | ||
44799f87 IV |
30 | #include <set> |
31 | #include <map> | |
32 | #include <queue> | |
33 | ||
5f520819 KY |
34 | #include "coi_host.h" |
35 | ||
36 | #include "coi_version_asm.h" | |
37 | ||
38 | #define CYCLE_FREQUENCY 1000000000 | |
39 | ||
44799f87 | 40 | enum buffer_t |
5f520819 KY |
41 | { |
42 | BUFFER_NORMAL, | |
43 | BUFFER_MEMORY | |
44799f87 | 44 | }; |
5f520819 | 45 | |
44799f87 | 46 | struct Engine |
5f520819 KY |
47 | { |
48 | COI_ISA_TYPE type; | |
49 | uint32_t index; | |
50 | char *dir; | |
44799f87 | 51 | }; |
5f520819 | 52 | |
44799f87 | 53 | struct Function |
5f520819 | 54 | { |
5f520819 | 55 | void *ptr; |
44799f87 IV |
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 | |
5f520819 | 67 | { |
44799f87 IV |
68 | COI_EVENT_CALLBACK ptr; |
69 | const void *data; | |
70 | }; | |
5f520819 | 71 | |
44799f87 | 72 | struct Process |
5f520819 KY |
73 | { |
74 | pid_t pid; | |
44799f87 IV |
75 | int pipe_host2tgt; |
76 | int pipe_tgt2host; | |
5f520819 | 77 | Engine *engine; |
44799f87 IV |
78 | void **functions; |
79 | }; | |
5f520819 | 80 | |
44799f87 IV |
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 | |
5f520819 KY |
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; | |
44799f87 IV |
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; | |
5f520819 KY |
137 | |
138 | ||
139 | static COIRESULT | |
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 | |
160 | init () | |
161 | { | |
2eab9666 | 162 | if (read_long_env (OFFLOAD_EMUL_NUM_ENV, &num_engines, 1) == COI_ERROR) |
5f520819 KY |
163 | exit (0); |
164 | } | |
165 | ||
166 | ||
167 | /* Helper function for directory removing. */ | |
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 | |
212 | cleanup () | |
213 | { | |
44799f87 | 214 | for (unsigned i = 0; i < tmp_dirs_num; i++) |
5f520819 KY |
215 | { |
216 | remove_directory (tmp_dirs[i]); | |
217 | free (tmp_dirs[i]); | |
218 | } | |
44799f87 IV |
219 | free (tmp_dirs); |
220 | } | |
221 | ||
222 | static COIRESULT | |
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 | |
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 | |
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 | |
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 | |
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 | |
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; | |
5f520819 KY |
283 | } |
284 | ||
285 | ||
286 | extern "C" | |
287 | { | |
288 | ||
289 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
299 | { |
300 | COITRACE ("COIBufferCopy"); | |
301 | ||
44799f87 IV |
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 | ||
5f520819 | 308 | /* Convert input arguments. */ |
44799f87 IV |
309 | Buffer *dest = (Buffer *) in_DestBuffer; |
310 | Buffer *source = (Buffer *) in_SourceBuffer; | |
5f520819 | 311 | |
44799f87 | 312 | start_critical_section (); |
5f520819 KY |
313 | |
314 | /* Map buffers if needed. */ | |
315 | if (dest->data == 0 && dest->type == BUFFER_NORMAL) | |
44799f87 | 316 | if (COIBufferMap (in_DestBuffer, 0, dest->size, (COI_MAP_TYPE) 0, |
5f520819 KY |
317 | 0, 0, 0, 0, 0) == COI_ERROR) |
318 | return COI_ERROR; | |
319 | if (source->data == 0 && source->type == BUFFER_NORMAL) | |
44799f87 | 320 | if (COIBufferMap (in_SourceBuffer, 0, source->size, (COI_MAP_TYPE) 0, |
5f520819 KY |
321 | 0, 0, 0, 0, 0) == COI_ERROR) |
322 | return COI_ERROR; | |
323 | ||
324 | /* Copy data. */ | |
325 | if (source->data != 0 && dest->data != 0) | |
44799f87 IV |
326 | memcpy ((void *) ((uintptr_t) dest->data + in_DestOffset), |
327 | (void *) ((uintptr_t) source->data + in_SourceOffset), in_Length); | |
5f520819 KY |
328 | else |
329 | { | |
330 | assert (dest->process == source->process); | |
331 | ||
332 | Buffer *buffer; | |
333 | cmd_t cmd = CMD_BUFFER_COPY; | |
5f520819 KY |
334 | |
335 | /* Create intermediary buffer. */ | |
44799f87 | 336 | if (COIBufferCreate (in_Length, COI_BUFFER_NORMAL, 0, 0, 1, |
5f520819 KY |
337 | (COIPROCESS*) &dest->process, |
338 | (COIBUFFER *) &buffer) == COI_ERROR) | |
339 | return COI_ERROR; | |
340 | ||
44799f87 IV |
341 | int pipe_host2tgt = dest->process->pipe_host2tgt; |
342 | int pipe_tgt2host = dest->process->pipe_tgt2host; | |
343 | ||
5f520819 KY |
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. */ | |
44799f87 IV |
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)); | |
5f520819 | 354 | |
44799f87 IV |
355 | /* Receive data from target. */ |
356 | READ (pipe_tgt2host, &cmd, sizeof (cmd_t)); | |
5f520819 KY |
357 | } |
358 | else | |
359 | { | |
44799f87 IV |
360 | if (COIBufferCopy ((COIBUFFER) buffer, in_SourceBuffer, 0, |
361 | in_SourceOffset, in_Length, in_Type, 0, 0, 0) | |
362 | == COI_ERROR) | |
5f520819 KY |
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. */ | |
44799f87 IV |
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)); | |
5f520819 | 376 | |
44799f87 IV |
377 | /* Receive data from target. */ |
378 | READ (pipe_tgt2host, &cmd, sizeof (cmd_t)); | |
5f520819 KY |
379 | } |
380 | else | |
381 | { | |
44799f87 IV |
382 | if (COIBufferCopy (in_DestBuffer, (COIBUFFER) buffer, in_DestOffset, |
383 | 0, in_Length, in_Type, 0, 0, 0) == COI_ERROR) | |
5f520819 KY |
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 | ||
44799f87 IV |
400 | finish_critical_section (); |
401 | ||
402 | if (out_pCompletion) | |
403 | out_pCompletion->opaque[0] = 0; | |
5f520819 KY |
404 | |
405 | return COI_SUCCESS; | |
406 | } | |
407 | ||
408 | ||
409 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
417 | { |
418 | COITRACE ("COIBufferCreate"); | |
419 | ||
420 | char *shm_name; | |
5f520819 KY |
421 | int shm_fd; |
422 | const int ullong_max_len = 20; | |
5f520819 | 423 | |
44799f87 | 424 | /* Features of liboffloadmic. */ |
df26a50d | 425 | assert (in_Type == COI_BUFFER_NORMAL || in_Type == COI_BUFFER_OPENCL); |
44799f87 IV |
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); | |
5f520819 KY |
433 | |
434 | /* Create shared memory with an unique name. */ | |
435 | MALLOC (char *, shm_name, strlen (SHM_NAME) + ullong_max_len + 1); | |
44799f87 | 436 | for (unsigned long long i = 0; i >= 0; i++) |
5f520819 | 437 | { |
44799f87 | 438 | sprintf (shm_name, SHM_NAME "%lu", i); |
5f520819 KY |
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 | } | |
44799f87 | 444 | if (ftruncate (shm_fd, in_Size) < 0) |
5f520819 KY |
445 | COIERROR ("Cannot truncate shared memory file."); |
446 | ||
447 | /* Create buffer. */ | |
44799f87 | 448 | Buffer *buf = new Buffer; |
5f520819 KY |
449 | buf->data = 0; |
450 | buf->fd = shm_fd; | |
44799f87 IV |
451 | buf->process = (Process *) in_pProcesses[0]; |
452 | buf->size = in_Size; | |
5f520819 KY |
453 | buf->type = BUFFER_NORMAL; |
454 | STRDUP (buf->name, shm_name); | |
455 | ||
456 | /* Map buffer on target. */ | |
44799f87 | 457 | size_t len = strlen (buf->name) + 1; |
5f520819 | 458 | |
44799f87 | 459 | start_critical_section (); |
5f520819 KY |
460 | |
461 | /* Send data to target. */ | |
44799f87 IV |
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)); | |
5f520819 | 468 | |
44799f87 IV |
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 *)); | |
5f520819 | 473 | |
44799f87 | 474 | finish_critical_section (); |
5f520819 KY |
475 | |
476 | /* Prepare output arguments. */ | |
44799f87 | 477 | *out_pBuffer = (COIBUFFER) buf; |
5f520819 KY |
478 | |
479 | /* Clean up. */ | |
480 | free (shm_name); | |
481 | ||
482 | return COI_SUCCESS; | |
483 | } | |
484 | ||
485 | ||
486 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
494 | { |
495 | COITRACE ("COIBufferCreateFromMemory"); | |
496 | ||
44799f87 IV |
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); | |
5f520819 KY |
504 | |
505 | /* Create buffer. */ | |
44799f87 IV |
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; | |
5f520819 KY |
511 | buf->type = BUFFER_MEMORY; |
512 | ||
513 | /* Prepare output argument. */ | |
44799f87 | 514 | *out_pBuffer = (COIBUFFER) buf; |
5f520819 KY |
515 | |
516 | return COI_SUCCESS; | |
517 | } | |
518 | ||
519 | ||
520 | COIRESULT | |
44799f87 | 521 | SYMBOL_VERSION (COIBufferDestroy, 1) (COIBUFFER in_Buffer) |
5f520819 KY |
522 | { |
523 | COITRACE ("COIBufferDestroy"); | |
524 | ||
525 | cmd_t cmd = CMD_BUFFER_UNMAP; | |
526 | ||
44799f87 IV |
527 | assert (in_Buffer != NULL); |
528 | ||
5f520819 | 529 | /* Convert input arguments. */ |
44799f87 | 530 | Buffer *buf = (Buffer *) in_Buffer; |
5f520819 KY |
531 | |
532 | /* Unmap buffer on host. */ | |
533 | if (buf->data != 0 && buf->type == BUFFER_NORMAL) | |
44799f87 | 534 | if (COIBufferUnmap ((COIMAPINSTANCE) in_Buffer, 0, 0, 0) == COI_ERROR) |
5f520819 KY |
535 | return COI_ERROR; |
536 | ||
537 | /* Unmap buffer on target. */ | |
538 | if (buf->data_target != 0) | |
539 | { | |
44799f87 | 540 | start_critical_section (); |
5f520819 KY |
541 | |
542 | /* Send data to target. */ | |
44799f87 IV |
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)); | |
5f520819 | 548 | |
44799f87 IV |
549 | /* Receive data from target. */ |
550 | READ (buf->process->pipe_tgt2host, &cmd, sizeof (cmd_t)); | |
5f520819 | 551 | |
44799f87 | 552 | finish_critical_section (); |
5f520819 KY |
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. */ | |
44799f87 | 566 | delete buf; |
5f520819 KY |
567 | |
568 | return COI_SUCCESS; | |
569 | } | |
570 | ||
571 | ||
572 | COIRESULT | |
44799f87 IV |
573 | SYMBOL_VERSION (COIBufferGetSinkAddress, 1) (COIBUFFER in_Buffer, |
574 | uint64_t *out_pAddress) | |
5f520819 KY |
575 | { |
576 | COITRACE ("COIBufferGetSinkAddress"); | |
577 | ||
44799f87 IV |
578 | assert (in_Buffer != NULL); |
579 | assert (out_pAddress != NULL); | |
580 | ||
5f520819 | 581 | /* Convert input arguments. */ |
44799f87 | 582 | Buffer *buf = (Buffer *) in_Buffer; |
5f520819 KY |
583 | |
584 | /* Here should come BUFFER_NORMAL buffer. */ | |
585 | assert (buf->type == BUFFER_NORMAL); | |
586 | ||
587 | /* Prepare output argument. */ | |
44799f87 | 588 | *out_pAddress = (uint64_t) buf->data_target; |
5f520819 KY |
589 | |
590 | return COI_SUCCESS; | |
591 | } | |
592 | ||
593 | ||
594 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
604 | { |
605 | COITRACE ("COIBufferMap"); | |
606 | ||
44799f87 IV |
607 | /* Features of liboffloadmic. */ |
608 | assert (in_Offset == 0); | |
609 | assert (in_NumDependencies == 0); | |
5f520819 KY |
610 | |
611 | /* Convert input arguments. */ | |
44799f87 | 612 | Buffer *buf = (Buffer *) in_Buffer; |
5f520819 KY |
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. */ | |
44799f87 IV |
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; | |
5f520819 KY |
631 | |
632 | return COI_SUCCESS; | |
633 | } | |
634 | ||
635 | ||
636 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
645 | { |
646 | COITRACE ("COIBufferRead"); | |
647 | ||
44799f87 IV |
648 | /* Features of liboffloadmic. */ |
649 | assert (in_pDestData != NULL); | |
650 | assert (in_Type == COI_COPY_UNSPECIFIED); | |
651 | assert (in_NumDependencies == 0); | |
5f520819 | 652 | |
44799f87 IV |
653 | /* Convert input arguments. */ |
654 | Buffer *buf = (Buffer *) in_SourceBuffer; | |
5f520819 | 655 | |
44799f87 | 656 | start_critical_section (); |
5f520819 KY |
657 | |
658 | /* Map buffers if needed. */ | |
659 | if (buf->data == 0 && buf->type == BUFFER_NORMAL) | |
44799f87 IV |
660 | if (COIBufferMap (in_SourceBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0, |
661 | 0, 0) == COI_ERROR) | |
5f520819 KY |
662 | return COI_ERROR; |
663 | ||
664 | /* Copy data. */ | |
44799f87 IV |
665 | memcpy (in_pDestData, (void *) ((uintptr_t) buf->data + in_Offset), |
666 | in_Length); | |
5f520819 KY |
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 | ||
44799f87 IV |
673 | finish_critical_section (); |
674 | ||
675 | if (out_pCompletion) | |
676 | out_pCompletion->opaque[0] = 0; | |
5f520819 KY |
677 | |
678 | return COI_SUCCESS; | |
679 | } | |
680 | ||
681 | ||
682 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
690 | { |
691 | COITRACE ("COIBufferSetState"); | |
692 | ||
44799f87 IV |
693 | /* Features of liboffloadmic. */ |
694 | assert (in_DataMove == COI_BUFFER_NO_MOVE); | |
695 | assert (in_NumDependencies == 0); | |
5f520819 KY |
696 | |
697 | /* Looks like we have nothing to do here. */ | |
698 | ||
44799f87 IV |
699 | if (out_pCompletion) |
700 | out_pCompletion->opaque[0] = 0; | |
701 | ||
5f520819 KY |
702 | return COI_SUCCESS; |
703 | } | |
704 | ||
705 | ||
706 | COIRESULT | |
44799f87 IV |
707 | SYMBOL_VERSION (COIBufferUnmap, 1) (COIMAPINSTANCE in_MapInstance, |
708 | uint32_t in_NumDependencies, | |
709 | const COIEVENT *in_pDependencies, // Ignored | |
710 | COIEVENT *out_pCompletion) | |
5f520819 KY |
711 | { |
712 | COITRACE ("COIBufferUnmap"); | |
713 | ||
44799f87 IV |
714 | /* Features of liboffloadmic. */ |
715 | assert (in_MapInstance != NULL); | |
716 | assert (in_NumDependencies == 0); | |
717 | ||
5f520819 | 718 | /* Convert input arguments. */ |
44799f87 | 719 | Buffer *buffer = (Buffer *) in_MapInstance; |
5f520819 KY |
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 | ||
44799f87 IV |
730 | if (out_pCompletion) |
731 | out_pCompletion->opaque[0] = 0; | |
732 | ||
5f520819 KY |
733 | return COI_SUCCESS; |
734 | } | |
735 | ||
736 | ||
737 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
746 | { |
747 | COITRACE ("COIBufferWrite"); | |
748 | ||
44799f87 IV |
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 | ||
5f520819 | 755 | /* Convert input arguments. */ |
44799f87 | 756 | Buffer *buf = (Buffer *) in_DestBuffer; |
5f520819 | 757 | |
44799f87 | 758 | start_critical_section (); |
5f520819 KY |
759 | |
760 | /* Map buffers if needed. */ | |
761 | if (buf->data == 0 && buf->type == BUFFER_NORMAL) | |
44799f87 IV |
762 | if (COIBufferMap (in_DestBuffer, 0, buf->size, (COI_MAP_TYPE) 0, 0, 0, 0, 0, |
763 | 0) == COI_ERROR) | |
5f520819 KY |
764 | return COI_ERROR; |
765 | ||
766 | /* Copy data. */ | |
44799f87 IV |
767 | memcpy ((void *) ((uintptr_t) buf->data + in_Offset), in_pSourceData, |
768 | in_Length); | |
5f520819 KY |
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 | ||
44799f87 IV |
775 | finish_critical_section (); |
776 | ||
777 | if (out_pCompletion) | |
778 | out_pCompletion->opaque[0] = 0; | |
5f520819 KY |
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 | ||
44799f87 | 790 | /* Features of liboffloadmic. */ |
2eab9666 | 791 | assert (isa == COI_ISA_MIC); |
44799f87 | 792 | assert (count != NULL); |
5f520819 KY |
793 | |
794 | /* Prepare output arguments. */ | |
2eab9666 | 795 | *count = num_engines; |
5f520819 KY |
796 | |
797 | return COI_SUCCESS; | |
798 | } | |
799 | ||
800 | ||
801 | COIRESULT | |
44799f87 IV |
802 | SYMBOL_VERSION (COIEngineGetHandle, 1) (COI_ISA_TYPE in_ISA, |
803 | uint32_t in_EngineIndex, | |
804 | COIENGINE *out_pEngineHandle) | |
5f520819 KY |
805 | { |
806 | COITRACE ("COIEngineGetHandle"); | |
807 | ||
44799f87 IV |
808 | /* Features of liboffloadmic. */ |
809 | assert (in_ISA == COI_ISA_MIC); | |
810 | assert (out_pEngineHandle != NULL); | |
5f520819 KY |
811 | |
812 | /* Check engine index. */ | |
44799f87 | 813 | if (in_EngineIndex >= num_engines) |
5f520819 KY |
814 | COIERROR ("Wrong engine index."); |
815 | ||
816 | /* Create engine handle. */ | |
44799f87 | 817 | Engine *engine = new Engine; |
5f520819 | 818 | engine->dir = NULL; |
44799f87 IV |
819 | engine->index = in_EngineIndex; |
820 | engine->type = in_ISA; | |
5f520819 KY |
821 | |
822 | /* Prepare output argument. */ | |
44799f87 | 823 | *out_pEngineHandle = (COIENGINE) engine; |
5f520819 KY |
824 | |
825 | return COI_SUCCESS; | |
826 | } | |
827 | ||
828 | ||
829 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
836 | { |
837 | COITRACE ("COIEventWait"); | |
838 | ||
44799f87 IV |
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); | |
5f520819 | 845 | |
44799f87 IV |
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 | } | |
5f520819 KY |
878 | |
879 | return COI_SUCCESS; | |
880 | } | |
881 | ||
882 | ||
883 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 | 888 | { |
44799f87 | 889 | COITRACE ("COIEventRegisterCallback"); |
5f520819 | 890 | |
44799f87 IV |
891 | /* Features of liboffloadmic. */ |
892 | assert (in_Callback != NULL); | |
893 | assert (in_UserData != NULL); | |
894 | assert (in_Flags == 0); | |
5f520819 | 895 | |
44799f87 IV |
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 (); | |
5f520819 KY |
912 | |
913 | return COI_SUCCESS; | |
914 | } | |
915 | ||
916 | ||
44799f87 IV |
917 | /* The start routine for the COI pipeline thread. */ |
918 | ||
919 | static void * | |
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 | ||
5f520819 | 1013 | COIRESULT |
44799f87 IV |
1014 | SYMBOL_VERSION (COIPipelineCreate, 1) (COIPROCESS in_Process, |
1015 | COI_CPU_MASK in_Mask, | |
1016 | uint32_t in_StackSize, // Ignored | |
1017 | COIPIPELINE *out_pPipeline) | |
5f520819 | 1018 | { |
44799f87 IV |
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); | |
5f520819 | 1053 | |
44799f87 IV |
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; | |
5f520819 KY |
1068 | |
1069 | return COI_SUCCESS; | |
1070 | } | |
1071 | ||
1072 | ||
1073 | COIRESULT | |
44799f87 | 1074 | SYMBOL_VERSION (COIPipelineDestroy, 1) (COIPIPELINE in_Pipeline) |
5f520819 | 1075 | { |
44799f87 | 1076 | COITRACE ("COIPipelineDestroy"); |
5f520819 | 1077 | |
44799f87 | 1078 | assert (in_Pipeline != NULL); |
5f520819 KY |
1079 | |
1080 | /* Convert input arguments. */ | |
44799f87 | 1081 | Pipeline *pipeline = (Pipeline *) in_Pipeline; |
5f520819 | 1082 | |
44799f87 IV |
1083 | start_critical_section (); |
1084 | /* Remove pipeline from the set of undestroyed pipelines. */ | |
1085 | pipelines.erase (pipeline); | |
5f520819 | 1086 | |
44799f87 IV |
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++) | |
5f520819 | 1131 | { |
44799f87 IV |
1132 | Buffer **bufs = (Buffer **) in_Buffers; |
1133 | func.bufs_size[i] = bufs[i]->size; | |
1134 | func.bufs_data_target[i] = bufs[i]->data_target; | |
5f520819 | 1135 | } |
44799f87 IV |
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; | |
5f520819 KY |
1152 | |
1153 | return COI_SUCCESS; | |
1154 | } | |
1155 | ||
1156 | ||
1157 | COIRESULT | |
44799f87 IV |
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) | |
5f520819 KY |
1173 | { |
1174 | COITRACE ("COIProcessCreateFromMemory"); | |
1175 | ||
1176 | const int run_max_args_num = 128; | |
5f520819 KY |
1177 | char *run_argv[run_max_args_num]; |
1178 | char *emul_run = getenv (OFFLOAD_EMUL_RUN_ENV); | |
5f520819 | 1179 | const int uint_max_len = 11; |
5f520819 | 1180 | |
44799f87 IV |
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); | |
5f520819 KY |
1190 | |
1191 | /* Convert input arguments. */ | |
44799f87 | 1192 | Engine *eng = (Engine *) in_Engine; |
5f520819 KY |
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. */ | |
44799f87 IV |
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); | |
5f520819 KY |
1212 | if (fd < 0) |
1213 | COIERROR ("Cannot create file %s.", target_exe); | |
44799f87 | 1214 | FILE *file = fdopen (fd, "wb"); |
5f520819 KY |
1215 | if (file == NULL) |
1216 | COIERROR ("Cannot associate stream with file descriptor."); | |
44799f87 IV |
1217 | if (fwrite (in_pBinaryBuffer, 1, in_BinaryBufferLength, file) |
1218 | != in_BinaryBufferLength) | |
5f520819 KY |
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. */ | |
44799f87 IV |
1228 | char *pipes_path; |
1229 | MALLOC (char *, pipes_path, strlen (eng->dir) + sizeof (PIPES_PATH)); | |
2eab9666 | 1230 | sprintf (pipes_path, "%s" PIPES_PATH, eng->dir); |
5f520819 KY |
1231 | if (mkdir (pipes_path, S_IRWXU) < 0) |
1232 | COIERROR ("Cannot create folder %s.", pipes_path); | |
1233 | ||
44799f87 IV |
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); | |
5f520819 KY |
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; | |
44799f87 | 1256 | int i = 0; |
5f520819 | 1257 | STRDUP (tmp, emul_run); |
44799f87 | 1258 | char *tok = strtok_r (tmp, " ", &ptr); |
5f520819 KY |
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); | |
44799f87 | 1267 | run_argv[i + 1] = (char *) NULL; |
5f520819 KY |
1268 | free (tmp); |
1269 | } | |
1270 | ||
1271 | /* Prepare envp. */ | |
44799f87 IV |
1272 | int env_num = 0; |
1273 | if (in_DupEnv == true) | |
5f520819 KY |
1274 | while (environ[env_num++]); |
1275 | env_num += 4; // LD_LIBRARY_PATH, MIC_DIR, MIC_INDEX, NULL | |
1276 | ||
44799f87 | 1277 | char **envp; |
5f520819 KY |
1278 | MALLOC (char **, envp, env_num * sizeof (char *)); |
1279 | ||
44799f87 IV |
1280 | int env_i = 0; |
1281 | if (in_DupEnv == true) | |
1282 | for (unsigned i = 0; environ[i] != NULL; i++) | |
5f520819 | 1283 | { |
44799f87 IV |
1284 | unsigned j; |
1285 | char *env_name; | |
5f520819 KY |
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 | ||
44799f87 IV |
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); | |
5f520819 | 1301 | |
44799f87 IV |
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); | |
5f520819 | 1305 | |
44799f87 | 1306 | envp[env_i + 3] = (char *) NULL; |
5f520819 KY |
1307 | |
1308 | /* Create target process. */ | |
44799f87 | 1309 | pid_t pid = vfork (); |
5f520819 KY |
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 | ||
44799f87 IV |
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."); | |
5f520819 KY |
1327 | |
1328 | /* Create process handle. */ | |
44799f87 | 1329 | Process *proc = new Process; |
5f520819 | 1330 | proc->pid = pid; |
44799f87 IV |
1331 | proc->pipe_host2tgt = pipe_host2tgt; |
1332 | proc->pipe_tgt2host = pipe_tgt2host; | |
5f520819 | 1333 | proc->engine = eng; |
44799f87 | 1334 | proc->functions = NULL; |
5f520819 KY |
1335 | |
1336 | /* Prepare output arguments. */ | |
44799f87 | 1337 | *out_pProcess = (COIPROCESS) proc; |
5f520819 KY |
1338 | |
1339 | /* Clean up. */ | |
44799f87 | 1340 | for (unsigned i = 0; run_argv[i] != NULL; i++) |
5f520819 | 1341 | free (run_argv[i]); |
44799f87 | 1342 | for (unsigned i = 0; envp[i] != NULL; i++) |
5f520819 KY |
1343 | free (envp[i]); |
1344 | free (envp); | |
44799f87 IV |
1345 | free (pipe_host2tgt_path); |
1346 | free (pipe_tgt2host_path); | |
5f520819 KY |
1347 | free (pipes_path); |
1348 | free (target_exe); | |
1349 | ||
1350 | return COI_SUCCESS; | |
1351 | } | |
1352 | ||
1353 | ||
2eab9666 IV |
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 | ||
5f520819 | 1375 | COIRESULT |
44799f87 IV |
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) | |
5f520819 KY |
1381 | { |
1382 | COITRACE ("COIProcessDestroy"); | |
1383 | ||
44799f87 IV |
1384 | assert (in_Process != NULL); |
1385 | assert (out_pProcessReturn != NULL); | |
1386 | assert (out_pTerminationCode != NULL); | |
5f520819 KY |
1387 | |
1388 | /* Convert input arguments. */ | |
44799f87 | 1389 | Process *proc = (Process *) in_Process; |
5f520819 | 1390 | |
44799f87 IV |
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."); | |
5f520819 KY |
1403 | |
1404 | /* Shutdown target process by force. */ | |
44799f87 | 1405 | if (in_ForceDestroy) |
5f520819 KY |
1406 | kill (proc->pid, SIGTERM); |
1407 | ||
1408 | /* Clean up. */ | |
5f520819 | 1409 | free (proc->engine->dir); |
5f520819 | 1410 | free (proc->functions); |
44799f87 IV |
1411 | delete proc->engine; |
1412 | delete proc; | |
5f520819 KY |
1413 | |
1414 | /* Prepare output arguments. */ | |
44799f87 IV |
1415 | *out_pProcessReturn = 0; |
1416 | *out_pTerminationCode = 0; | |
5f520819 KY |
1417 | |
1418 | return COI_SUCCESS; | |
1419 | } | |
1420 | ||
1421 | ||
1422 | COIRESULT | |
44799f87 IV |
1423 | SYMBOL_VERSION (COIProcessGetFunctionHandles, 1) (COIPROCESS in_Process, |
1424 | uint32_t in_NumFunctions, | |
1425 | const char **in_ppFunctionNameArray, | |
1426 | COIFUNCTION *out_pFunctionHandleArray) | |
5f520819 KY |
1427 | { |
1428 | COITRACE ("COIProcessGetFunctionHandles"); | |
1429 | ||
44799f87 IV |
1430 | assert (in_Process != NULL); |
1431 | assert (in_ppFunctionNameArray != NULL); | |
1432 | assert (out_pFunctionHandleArray != NULL); | |
5f520819 KY |
1433 | |
1434 | /* Convert input arguments. */ | |
44799f87 | 1435 | Process *proc = (Process *) in_Process; |
5f520819 KY |
1436 | |
1437 | /* This function should be called once for the process. */ | |
44799f87 | 1438 | assert (proc->functions == NULL); |
5f520819 | 1439 | |
44799f87 IV |
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 *)); | |
5f520819 KY |
1444 | if (proc->functions == NULL) |
1445 | COIERROR ("Cannot allocate memory."); | |
1446 | ||
1447 | /* Get handles for functions. */ | |
44799f87 | 1448 | for (uint32_t i = 0; i < in_NumFunctions; i++) |
5f520819 | 1449 | { |
44799f87 | 1450 | size_t len = strlen (in_ppFunctionNameArray[i]) + 1; |
5f520819 | 1451 | |
44799f87 | 1452 | start_critical_section (); |
5f520819 KY |
1453 | |
1454 | /* Send data to target. */ | |
44799f87 IV |
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); | |
5f520819 | 1459 | |
44799f87 IV |
1460 | /* Receive data from target. */ |
1461 | void *fn_ptr; | |
1462 | READ (proc->pipe_tgt2host, &fn_ptr, sizeof (void *)); | |
5f520819 | 1463 | |
44799f87 | 1464 | finish_critical_section (); |
5f520819 KY |
1465 | |
1466 | /* Save function pointer. */ | |
44799f87 IV |
1467 | proc->functions[i] = fn_ptr; |
1468 | ||
1469 | /* Prepare output arguments. */ | |
1470 | out_pFunctionHandleArray[i] = (COIFUNCTION) fn_ptr; | |
5f520819 KY |
1471 | } |
1472 | ||
1473 | return COI_SUCCESS; | |
1474 | } | |
1475 | ||
1476 | ||
1477 | COIRESULT | |
2eab9666 IV |
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) | |
5f520819 KY |
1487 | { |
1488 | COITRACE ("COIProcessLoadLibraryFromMemory"); | |
1489 | ||
44799f87 IV |
1490 | assert (in_Process != NULL); |
1491 | assert (in_pLibraryBuffer != NULL); | |
1492 | assert (out_pLibrary != NULL); | |
5f520819 KY |
1493 | |
1494 | /* Convert input arguments. */ | |
2eab9666 | 1495 | Process *proc = (Process *) in_Process; |
5f520819 KY |
1496 | |
1497 | /* Create target library file. */ | |
44799f87 IV |
1498 | char *lib_path; |
1499 | size_t len = strlen (proc->engine->dir) + strlen (in_pLibraryName) + 2; | |
1500 | MALLOC (char *, lib_path, len); | |
2eab9666 | 1501 | sprintf (lib_path, "%s/%s", proc->engine->dir, in_pLibraryName); |
44799f87 | 1502 | int fd = open (lib_path, O_CLOEXEC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); |
5f520819 KY |
1503 | if (fd < 0) |
1504 | COIERROR ("Cannot create file %s.", lib_path); | |
44799f87 | 1505 | FILE *file = fdopen (fd, "wb"); |
5f520819 KY |
1506 | if (file == NULL) |
1507 | COIERROR ("Cannot associate stream with file descriptor."); | |
2eab9666 IV |
1508 | if (fwrite (in_pLibraryBuffer, 1, in_LibraryBufferLength, file) |
1509 | != in_LibraryBufferLength) | |
5f520819 KY |
1510 | COIERROR ("Cannot write in file %s.", lib_path); |
1511 | if (fclose (file) != 0) | |
1512 | COIERROR ("Cannot close file %s.", lib_path); | |
1513 | ||
44799f87 | 1514 | start_critical_section (); |
5f520819 KY |
1515 | |
1516 | /* Make target open library. */ | |
44799f87 IV |
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); | |
5f520819 | 1521 | |
2eab9666 IV |
1522 | /* Receive data from target. */ |
1523 | void *handle; | |
44799f87 | 1524 | READ (proc->pipe_tgt2host, &handle, sizeof (void *)); |
2eab9666 | 1525 | |
44799f87 | 1526 | finish_critical_section (); |
5f520819 KY |
1527 | |
1528 | /* Clean up. */ | |
1529 | free (lib_path); | |
1530 | ||
2eab9666 | 1531 | *out_pLibrary = (COILIBRARY) handle; |
5f520819 KY |
1532 | return COI_SUCCESS; |
1533 | } | |
1534 | ||
1535 | ||
1536 | COIRESULT | |
44799f87 IV |
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 | |
5f520819 KY |
1542 | { |
1543 | COITRACE ("COIProcessRegisterLibraries"); | |
1544 | ||
1545 | /* Looks like we have nothing to do here. */ | |
1546 | ||
1547 | return COI_SUCCESS; | |
1548 | } | |
1549 | ||
1550 | ||
2eab9666 IV |
1551 | COIRESULT |
1552 | SYMBOL_VERSION (COIProcessUnloadLibrary, 1) (COIPROCESS in_Process, | |
1553 | COILIBRARY in_Library) | |
1554 | { | |
1555 | COITRACE ("COIProcessUnloadLibrary"); | |
1556 | ||
44799f87 IV |
1557 | assert (in_Process != NULL); |
1558 | assert (in_Library != NULL); | |
1559 | ||
2eab9666 IV |
1560 | const cmd_t cmd = CMD_CLOSE_LIBRARY; |
1561 | ||
1562 | /* Convert input arguments. */ | |
1563 | Process *proc = (Process *) in_Process; | |
1564 | ||
44799f87 | 1565 | start_critical_section (); |
2eab9666 IV |
1566 | |
1567 | /* Make target close library. */ | |
44799f87 IV |
1568 | WRITE (proc->pipe_host2tgt, &cmd, sizeof (cmd_t)); |
1569 | WRITE (proc->pipe_host2tgt, &in_Library, sizeof (void *)); | |
2eab9666 | 1570 | |
44799f87 | 1571 | finish_critical_section (); |
2eab9666 IV |
1572 | |
1573 | return COI_SUCCESS; | |
1574 | } | |
1575 | ||
1576 | ||
5f520819 KY |
1577 | uint64_t |
1578 | SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) () | |
1579 | { | |
1580 | COITRACE ("COIPerfGetCycleFrequency"); | |
1581 | ||
1582 | return (uint64_t) CYCLE_FREQUENCY; | |
1583 | } | |
1584 | ||
2eab9666 IV |
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 | |
44799f87 IV |
1612 | SYMBOL_VERSION (COIEngineGetInfo, 1) (COIENGINE in_EngineHandle, // Ignored |
1613 | uint32_t in_EngineInfoSize, // Ignored | |
2eab9666 IV |
1614 | COI_ENGINE_INFO *out_pEngineInfo) |
1615 | { | |
1616 | COITRACE ("COIEngineGetInfo"); | |
1617 | ||
44799f87 IV |
1618 | assert (out_pEngineInfo != NULL); |
1619 | ||
df26a50d | 1620 | out_pEngineInfo->ISA = COI_DEVICE_KNL; |
2eab9666 IV |
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 | ||
5f520819 KY |
1633 | } // extern "C" |
1634 |