1 2 /* 3 * File: EINTR_wrappers.c 4 * 5 * This file implements the wrapper functions for some of the System APIs 6 * 7 * Copyright (C) <2019> <American Megatrends International LLC> 8 * 9 */ 10 11 #include "EINTR_wrappers.h" 12 #if defined(__linux__) 13 #include <sys/msg.h> 14 #include <sys/file.h> 15 #endif 16 #include <errno.h> 17 #include <unistd.h> 18 19 static const int OneSecondasNS = 1000000000; 20 21 #ifndef bool 22 typedef int bool; 23 #endif 24 25 #ifndef TRUE 26 #define TRUE (1) 27 #endif 28 29 #ifndef FALSE 30 #define FALSE (0) 31 #endif 32 33 typedef struct 34 { 35 bool OnePoll; 36 struct timespec EndTime, Timeout; 37 } SIGWRAP_TIMEOUT; 38 39 static void sigwrap_InitTimeout(SIGWRAP_TIMEOUT *pDst, const struct timespec *timeout) 40 { 41 pDst->Timeout = *timeout; 42 43 if ((timeout->tv_sec == 0) && (timeout->tv_nsec == 0)) // If both value are zero than only a single poll is requested! 44 { 45 pDst->OnePoll = 1; 46 return; 47 } 48 49 pDst->OnePoll = 0; 50 51 struct timespec Now; 52 53 (void)clock_gettime(CLOCK_MONOTONIC_RAW, &Now); // CLOCK_MONOTONIC_RAW is not affected by NTP etc. 54 55 pDst->EndTime.tv_sec = Now.tv_sec + pDst->Timeout.tv_sec; // Check necessary in 2038 due to signed integer variables 56 pDst->EndTime.tv_nsec = Now.tv_nsec + pDst->Timeout.tv_nsec; 57 58 if (pDst->EndTime.tv_nsec >= OneSecondasNS) 59 { 60 pDst->EndTime.tv_sec += (pDst->EndTime.tv_nsec / OneSecondasNS); 61 pDst->EndTime.tv_nsec = (pDst->EndTime.tv_nsec % OneSecondasNS); 62 } 63 } 64 65 66 static bool sigwrap_CheckTimeout(SIGWRAP_TIMEOUT *pTo) 67 { 68 if (pTo->OnePoll == TRUE) // Make sure, that in the case that a single poll is requested at least one call is not terminated with EINTR 69 return FALSE; 70 71 struct timespec Now; 72 73 (void)clock_gettime(CLOCK_MONOTONIC_RAW, &Now); 74 75 if (Now.tv_sec > pTo->EndTime.tv_sec) // Can become a problem already in 2038 due to signed integer variables 76 return TRUE; 77 78 pTo->Timeout.tv_nsec = pTo->EndTime.tv_nsec - Now.tv_nsec; 79 pTo->Timeout.tv_sec = pTo->EndTime.tv_sec - Now.tv_sec; 80 81 if (pTo->Timeout.tv_sec == 0) 82 { 83 if (pTo->Timeout.tv_nsec <= 0) 84 return TRUE; 85 } 86 else if (pTo->Timeout.tv_nsec < 0) 87 { 88 pTo->Timeout.tv_nsec += OneSecondasNS; 89 pTo->Timeout.tv_sec--; 90 } 91 92 return FALSE; 93 } 94 95 96 97 int sigwrap_semop(int semid, struct sembuf *sops, size_t nsops) 98 { 99 while (1) 100 { 101 if (semop(semid, sops, nsops) == 0) 102 return 0; 103 104 if (errno != EINTR) 105 return -1; 106 } 107 } 108 109 #if 0 110 int sigwrap_semtimedop(int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout) 111 { 112 SIGWRAP_TIMEOUT To; 113 114 if (timeout == NULL) 115 return (sigwrap_semop(semid, sops, nsops)); 116 117 sigwrap_InitTimeout(&To, timeout); 118 119 while (1) 120 { 121 if (semtimedop(semid, sops, nsops, &To.Timeout) == 0) 122 return 0; 123 124 if (errno != EINTR) 125 return -1; 126 127 if (sigwrap_CheckTimeout(&To)) 128 { 129 errno = EAGAIN; 130 return -1; 131 } 132 } 133 } 134 #endif 135 136 int sigwrap_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 137 { 138 SIGWRAP_TIMEOUT To; 139 140 if (timeout != -1) 141 { 142 struct timespec Timeout; 143 144 Timeout.tv_sec = timeout / 1000; 145 Timeout.tv_nsec = (timeout % 1000) * 1000000; // Convert msec to nsec 146 147 sigwrap_InitTimeout(&To, &Timeout); 148 } 149 150 while (1) 151 { 152 int Result = epoll_wait(epfd, events, maxevents, timeout); 153 154 if (Result != -1) 155 return Result; 156 157 if (errno != EINTR) 158 return Result; 159 160 if (timeout == -1) 161 continue; 162 163 if (sigwrap_CheckTimeout(&To)) 164 return 0; 165 166 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 167 } 168 } 169 170 171 int sigwrap_epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask) 172 { 173 SIGWRAP_TIMEOUT To; 174 175 if (timeout != -1) 176 { 177 struct timespec Timeout; 178 179 Timeout.tv_sec = timeout / 1000; 180 Timeout.tv_nsec = (timeout % 1000) * 1000000; // Convert msec to nsec 181 182 sigwrap_InitTimeout(&To, &Timeout); 183 } 184 185 while (1) 186 { 187 int Result = epoll_pwait(epfd, events, maxevents, timeout, sigmask); 188 189 if (Result != -1) 190 return Result; 191 192 if (errno != EINTR) 193 return Result; 194 195 if (timeout == -1) 196 continue; 197 198 if (sigwrap_CheckTimeout(&To)) 199 return 0; 200 201 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 202 } 203 } 204 205 206 int sigwrap_sigwaitinfo(const sigset_t *set, siginfo_t *info) 207 { 208 while (1) 209 { 210 int Result = sigwaitinfo(set, info); 211 212 if (Result != -1) 213 return Result; 214 215 if (errno != EINTR) 216 return Result; 217 } 218 } 219 220 221 int sigwrap_sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) 222 { 223 SIGWRAP_TIMEOUT To; 224 225 sigwrap_InitTimeout(&To, timeout); 226 227 while (1) 228 { 229 int Result = sigtimedwait(set, info, &To.Timeout); 230 231 if (Result != -1) 232 return Result; 233 234 if (errno != EINTR) 235 return Result; 236 237 if (sigwrap_CheckTimeout(&To)) 238 return 0; 239 } 240 } 241 242 243 int sigwrap_nanosleep(const struct timespec *req, struct timespec *rem) 244 { 245 struct timespec Wait, Remain; 246 247 if (!rem) 248 rem = &Remain; 249 250 Wait = *req; 251 252 while (1) 253 { 254 if (nanosleep(&Wait, rem) == 0) 255 return 0; 256 257 if (errno != EINTR) 258 return -1; 259 260 Wait = *rem; 261 } 262 } 263 264 265 int sigwrap_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain) 266 { 267 struct timespec Wait, Remain; 268 269 if (!remain) 270 remain = &Remain; 271 272 Wait = *request; 273 274 while (1) 275 { 276 int Result = clock_nanosleep(clock_id, flags, &Wait, remain); 277 278 if (Result == 0) 279 return Result; 280 281 if (Result != EINTR) 282 return Result; 283 284 if (flags != TIMER_ABSTIME) 285 Wait = *remain; 286 } 287 } 288 289 290 int sigwrap_usleep(useconds_t usec) 291 { 292 SIGWRAP_TIMEOUT To; 293 294 struct timespec Timeout; 295 296 Timeout.tv_sec = usec / 1000000; 297 Timeout.tv_nsec = (usec % 1000000) * 1000; 298 299 sigwrap_InitTimeout(&To, &Timeout); 300 301 while (1) 302 { 303 if (usleep(usec) == 0) 304 return 0; 305 306 if (errno != EINTR) 307 return -1; 308 309 if (sigwrap_CheckTimeout(&To)) 310 return 0; 311 312 usec = To.Timeout.tv_sec * 1000000 + To.Timeout.tv_nsec / 1000; 313 } 314 } 315 316 317 int sigwrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) 318 { 319 SIGWRAP_TIMEOUT To; 320 321 if (timeout > 0) 322 { 323 struct timespec Timeout; 324 325 Timeout.tv_sec = timeout / 1000; 326 Timeout.tv_nsec = (timeout % 1000) * 1000000; 327 328 sigwrap_InitTimeout(&To, &Timeout); 329 } 330 331 while (1) 332 { 333 int Result = poll(fds, nfds, timeout); 334 335 if (Result != -1) 336 return Result; 337 338 if (errno != EINTR) 339 return Result; 340 341 if (timeout < 0) // Specifying a negative value in timeout means an infinite/no timeout. 342 continue; 343 else if (timeout == 0) 344 continue; // We want to make sure that at least one check was not aborted with EINTR 345 346 if (sigwrap_CheckTimeout(&To)) 347 return 0; 348 349 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 350 } 351 } 352 353 #if 0 354 int sigwrap_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask) 355 { 356 SIGWRAP_TIMEOUT To; 357 358 if (tmo_p != NULL) 359 { 360 sigwrap_InitTimeout(&To, tmo_p); 361 tmo_p = &To.Timeout; 362 } 363 364 while (1) 365 { 366 int Result = ppoll(fds, nfds, tmo_p, sigmask); 367 368 if (Result != -1) 369 return Result; 370 371 if (errno != EINTR) 372 return Result; 373 374 if (tmo_p == NULL) 375 continue; 376 377 if (sigwrap_CheckTimeout(&To)) 378 return 0; 379 } 380 } 381 #endif 382 383 int sigwrap_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 384 { 385 while (1) 386 { 387 int Result = select(nfds, readfds, writefds, exceptfds, timeout); 388 389 if (Result != -1) 390 return Result; 391 392 if (errno != EINTR) 393 return Result; 394 } 395 } 396 397 398 int sigwrap_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, 399 const sigset_t *sigmask) 400 { 401 SIGWRAP_TIMEOUT To; 402 403 if (timeout != NULL) 404 { 405 sigwrap_InitTimeout(&To, timeout); 406 timeout = &To.Timeout; 407 } 408 409 while (1) 410 { 411 int Result = pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask); 412 413 if (Result != -1) 414 return Result; 415 416 if (errno != EINTR) 417 return Result; 418 419 if (timeout == NULL) 420 continue; 421 422 if (sigwrap_CheckTimeout(&To)) 423 return 0; 424 } 425 } 426 427 428 int sigwrap_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) 429 { 430 while (1) 431 { 432 int Result = msgsnd(msqid, msgp, msgsz, msgflg); 433 434 if (Result != -1) 435 return Result; 436 437 if (errno != EINTR) 438 return Result; 439 } 440 } 441 442 443 ssize_t sigwrap_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) 444 { 445 while (1) 446 { 447 ssize_t Result = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); 448 449 if (Result != -1) 450 return Result; 451 452 if (errno != EINTR) 453 return Result; 454 } 455 } 456 457 458 int sigwrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 459 { 460 while (1) 461 { 462 int Result = connect(sockfd, addr, addrlen); 463 464 if (Result != -1) 465 return Result; 466 467 if (errno != EINTR) 468 return Result; 469 } 470 } 471 472 473 ssize_t sigwrap_send(int sockfd, const void *buf, size_t len, int flags) 474 { 475 while (1) 476 { 477 ssize_t Result = send(sockfd, buf, len, flags); 478 479 if (Result != -1) 480 return Result; 481 482 if (errno != EINTR) 483 return Result; 484 } 485 } 486 487 488 ssize_t sigwrap_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, 489 socklen_t addrlen) 490 { 491 while (1) 492 { 493 ssize_t Result = sendto(sockfd, buf, len, flags, dest_addr, addrlen); 494 495 if (Result != -1) 496 return Result; 497 498 if (errno != EINTR) 499 return Result; 500 } 501 } 502 503 504 ssize_t sigwrap_sendsendmsg(int sockfd, const struct msghdr *msg, int flags) 505 { 506 while (1) 507 { 508 ssize_t Result = sendmsg(sockfd, msg, flags); 509 510 if (Result != -1) 511 return Result; 512 513 if (errno != EINTR) 514 return Result; 515 } 516 } 517 518 519 int sigwrap_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 520 { 521 while (1) 522 { 523 int Result = accept(sockfd, addr, addrlen); 524 525 if (Result != -1) 526 return Result; 527 528 if (errno != EINTR) 529 return Result; 530 } 531 } 532 533 #if 0 534 int sigwrap_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) 535 { 536 while (1) 537 { 538 int Result = accept4(sockfd, addr, addrlen, flags); 539 540 if (Result != -1) 541 return Result; 542 543 if (errno != EINTR) 544 return Result; 545 } 546 } 547 #endif 548 549 // EINTR wrapper for the standard read() function. Can be used for sockets that are the to non-blocking mode. 550 // The length of the returned data can be shorter than the requested one! 551 552 ssize_t sigwrap_read(int fd, void *buf, size_t count) 553 { 554 while (1) 555 { 556 ssize_t Result = read(fd, buf, count); 557 558 if (Result != -1) 559 return (Result); 560 561 if (errno != EINTR) 562 return (Result); 563 } 564 } 565 566 567 // EINTR wrapper for the standard read() function. Waits until ALL requested data is available. Use the non-blocking version (sigwrap_read) 568 // for sockets that are set to non-blocking mode or when partial data is okay 569 // Although the description for the read() function describes it differently, it seems possible that the original function may already return 570 // even though partial data has already been read. This implementation makes sure that all requested data have been read. 571 // See the comment in the signal description https://linux.die.net/man/7/signal 572 //* read(2), readv(2), write(2), writev(2), and ioctl(2) calls on "slow" devices. 573 //* A "slow" device is one where the I/O call may block for an indefinite time, for example, a terminal, pipe, or socket. 574 //* (A disk is not a slow device according to this definition.) If an I/O call on a slow device has already transferred 575 //* some data by the time it is interrupted by a signal handler, then the call will return a success status (normally, the number of bytes transferred). 576 577 ssize_t sigwrap_blocking_read(int hFile, void *pData, size_t RdLen) 578 { 579 ssize_t Transfered; 580 ssize_t Len = RdLen; 581 582 while ((Transfered = read(hFile, pData, Len)) != Len) 583 { 584 if (Transfered == 0) // EOF reached? 585 return 0; 586 587 if (Transfered != -1) 588 { 589 pData += Transfered; 590 Len -= Transfered; 591 continue; 592 } 593 594 if (errno != EINTR) 595 return -1; 596 } 597 598 return RdLen; 599 } 600 601 602 ssize_t sigwrap_readv(int fd, const struct iovec *iov, int iovcnt) 603 { 604 while (1) 605 { 606 ssize_t Result = readv(fd, iov, iovcnt); 607 608 if (Result != -1) 609 return (Result); 610 611 if (errno != EINTR) 612 return (Result); 613 } 614 } 615 616 617 ssize_t sigwrap_recv(int sockfd, void *buf, size_t len, int flags) 618 { 619 while (1) 620 { 621 ssize_t Result = recv(sockfd, buf, len, flags); 622 623 if (Result != -1) 624 return (Result); 625 626 if (errno != EINTR) 627 return (Result); 628 } 629 } 630 631 632 ssize_t sigwrap_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) 633 { 634 while (1) 635 { 636 ssize_t Result = recvfrom(sockfd, buf, len, flags, src_addr, addrlen); 637 638 if (Result != -1) 639 return (Result); 640 641 if (errno != EINTR) 642 return (Result); 643 } 644 } 645 646 647 ssize_t sigwrap_recvmsg(int sockfd, struct msghdr *msg, int flags) 648 { 649 while (1) 650 { 651 ssize_t Result = recvmsg(sockfd, msg, flags); 652 653 if (Result != -1) 654 return (Result); 655 656 if (errno != EINTR) 657 return (Result); 658 } 659 } 660 661 662 // EINTR wrapper for the standard write() function. Can be used for sockets that are the to non-blocking mode. 663 // The length of the effectively written data can be shorter than the length specified at the function call! 664 665 ssize_t sigwrap_write(int fd, const void *buf, size_t count) 666 { 667 while (1) 668 { 669 ssize_t Result = write(fd, buf, count); 670 671 if (Result != -1) 672 return (Result); 673 674 if (errno != EINTR) 675 return (Result); 676 } 677 } 678 679 // EINTR wrapper for the standard write() function. Waits until ALL data is written! Use the non-blocking version (sigwrap_write) 680 // for sockets that are set to non-blocking mode, or when it is OK to write only partial data. 681 // Although the description for the write() function describes it differently, it seems possible that the original function may already return 682 // even though partial data has already been written. This implementation makes sure that all requested data have been written. 683 // See the comment in the signal description https://linux.die.net/man/7/signal 684 //* read(2), readv(2), write(2), writev(2), and ioctl(2) calls on "slow" devices. 685 //* A "slow" device is one where the I/O call may block for an indefinite time, for example, a terminal, pipe, or socket. 686 //* (A disk is not a slow device according to this definition.) If an I/O call on a slow device has already transferred 687 //* some data by the time it is interrupted by a signal handler, then the call will return a success status (normally, the number of bytes transferred). 688 689 ssize_t sigwrap_blocking_write(int hFile, const void *pData, ssize_t WrtLen) 690 { 691 ssize_t Written; 692 ssize_t Len = WrtLen; 693 694 while ((Written = write(hFile, pData, Len)) != Len) 695 { 696 if (Written != -1) 697 { 698 pData += Written; 699 Len -= Written; 700 continue; 701 } 702 703 if (errno != EINTR) 704 return -1; 705 } 706 707 return WrtLen; 708 } 709 710 711 ssize_t sigwrap_writev(int fd, const struct iovec *iov, int iovcnt) 712 { 713 while (1) 714 { 715 ssize_t Result = writev(fd, iov, iovcnt); 716 717 if (Result != -1) 718 return (Result); 719 720 if (errno != EINTR) 721 return (Result); 722 } 723 } 724 725 726 int sigwrap_close(int hFile) 727 { 728 while (close(hFile) == -1) 729 { 730 if (errno != EINTR) 731 return -1; 732 } 733 734 return 0; 735 } 736 737 738 int sigwrap_open_mode(const char *pathname, int flags, mode_t mode) 739 { 740 while (1) 741 { 742 int hFile = open(pathname, flags, mode); 743 744 if(hFile != -1) 745 return hFile; 746 747 if (errno != EINTR) 748 return hFile; 749 } 750 } 751 752 int sigwrap_open(const char *pathname, int flags) 753 { 754 while (1) 755 { 756 int hFile = open(pathname, flags); 757 758 if(hFile != -1) 759 return hFile; 760 761 if (errno != EINTR) 762 return hFile; 763 } 764 } 765 766 767 pid_t sigwrap_wait(int *status) 768 { 769 while(1) 770 { 771 pid_t Result = wait(status); 772 773 if(Result != -1) 774 return Result; 775 776 if(errno != EINTR) 777 return Result; 778 } 779 } 780 781 782 pid_t sigwrap_waitpid(pid_t pid, int *status, int options) 783 { 784 while(1) 785 { 786 pid_t Result = waitpid(pid, status, options); 787 788 if(Result != -1) 789 return Result; 790 791 if(errno != EINTR) 792 return Result; 793 } 794 } 795 796 797 int sigwrap_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) 798 { 799 while(1) 800 { 801 int Result = waitid(idtype, id, infop, options); 802 803 if(Result != -1) 804 return Result; 805 806 if(errno != EINTR) 807 return Result; 808 } 809 } 810 811 812 int sigwrap_flock(int fd, int operation) 813 { 814 while(1) 815 { 816 int Result = flock(fd, operation); 817 818 if(Result != -1) 819 return Result; 820 821 if(errno != EINTR) 822 return Result; 823 } 824 } 825 826 827