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