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 int sigwrap_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 110 { 111 SIGWRAP_TIMEOUT To; 112 113 if (timeout != -1) 114 { 115 struct timespec Timeout; 116 117 Timeout.tv_sec = timeout / 1000; 118 Timeout.tv_nsec = (timeout % 1000) * 1000000; // Convert msec to nsec 119 120 sigwrap_InitTimeout(&To, &Timeout); 121 } 122 123 while (1) 124 { 125 int Result = epoll_wait(epfd, events, maxevents, timeout); 126 127 if (Result != -1) 128 return Result; 129 130 if (errno != EINTR) 131 return Result; 132 133 if (timeout == -1) 134 continue; 135 136 if (sigwrap_CheckTimeout(&To)) 137 return 0; 138 139 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 140 } 141 } 142 143 144 int sigwrap_epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask) 145 { 146 SIGWRAP_TIMEOUT To; 147 148 if (timeout != -1) 149 { 150 struct timespec Timeout; 151 152 Timeout.tv_sec = timeout / 1000; 153 Timeout.tv_nsec = (timeout % 1000) * 1000000; // Convert msec to nsec 154 155 sigwrap_InitTimeout(&To, &Timeout); 156 } 157 158 while (1) 159 { 160 int Result = epoll_pwait(epfd, events, maxevents, timeout, sigmask); 161 162 if (Result != -1) 163 return Result; 164 165 if (errno != EINTR) 166 return Result; 167 168 if (timeout == -1) 169 continue; 170 171 if (sigwrap_CheckTimeout(&To)) 172 return 0; 173 174 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 175 } 176 } 177 178 179 int sigwrap_sigwaitinfo(const sigset_t *set, siginfo_t *info) 180 { 181 while (1) 182 { 183 int Result = sigwaitinfo(set, info); 184 185 if (Result != -1) 186 return Result; 187 188 if (errno != EINTR) 189 return Result; 190 } 191 } 192 193 194 int sigwrap_sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) 195 { 196 SIGWRAP_TIMEOUT To; 197 198 sigwrap_InitTimeout(&To, timeout); 199 200 while (1) 201 { 202 int Result = sigtimedwait(set, info, &To.Timeout); 203 204 if (Result != -1) 205 return Result; 206 207 if (errno != EINTR) 208 return Result; 209 210 if (sigwrap_CheckTimeout(&To)) 211 return 0; 212 } 213 } 214 215 216 int sigwrap_nanosleep(const struct timespec *req, struct timespec *rem) 217 { 218 struct timespec Wait, Remain; 219 220 if (!rem) 221 rem = &Remain; 222 223 Wait = *req; 224 225 while (1) 226 { 227 if (nanosleep(&Wait, rem) == 0) 228 return 0; 229 230 if (errno != EINTR) 231 return -1; 232 233 Wait = *rem; 234 } 235 } 236 237 238 int sigwrap_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain) 239 { 240 struct timespec Wait, Remain; 241 242 if (!remain) 243 remain = &Remain; 244 245 Wait = *request; 246 247 while (1) 248 { 249 int Result = clock_nanosleep(clock_id, flags, &Wait, remain); 250 251 if (Result == 0) 252 return Result; 253 254 if (Result != EINTR) 255 return Result; 256 257 if (flags != TIMER_ABSTIME) 258 Wait = *remain; 259 } 260 } 261 262 263 int sigwrap_usleep(useconds_t usec) 264 { 265 SIGWRAP_TIMEOUT To; 266 267 struct timespec Timeout; 268 269 Timeout.tv_sec = usec / 1000000; 270 Timeout.tv_nsec = (usec % 1000000) * 1000; 271 272 sigwrap_InitTimeout(&To, &Timeout); 273 274 while (1) 275 { 276 if (usleep(usec) == 0) 277 return 0; 278 279 if (errno != EINTR) 280 return -1; 281 282 if (sigwrap_CheckTimeout(&To)) 283 return 0; 284 285 usec = To.Timeout.tv_sec * 1000000 + To.Timeout.tv_nsec / 1000; 286 } 287 } 288 289 290 int sigwrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) 291 { 292 SIGWRAP_TIMEOUT To; 293 294 if (timeout > 0) 295 { 296 struct timespec Timeout; 297 298 Timeout.tv_sec = timeout / 1000; 299 Timeout.tv_nsec = (timeout % 1000) * 1000000; 300 301 sigwrap_InitTimeout(&To, &Timeout); 302 } 303 304 while (1) 305 { 306 int Result = poll(fds, nfds, timeout); 307 308 if (Result != -1) 309 return Result; 310 311 if (errno != EINTR) 312 return Result; 313 314 if (timeout < 0) // Specifying a negative value in timeout means an infinite/no timeout. 315 continue; 316 else if (timeout == 0) 317 continue; // We want to make sure that at least one check was not aborted with EINTR 318 319 if (sigwrap_CheckTimeout(&To)) 320 return 0; 321 322 timeout = To.Timeout.tv_sec * 1000 + To.Timeout.tv_nsec / 1000000; 323 } 324 } 325 326 int sigwrap_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 327 { 328 while (1) 329 { 330 int Result = select(nfds, readfds, writefds, exceptfds, timeout); 331 332 if (Result != -1) 333 return Result; 334 335 if (errno != EINTR) 336 return Result; 337 } 338 } 339 340 341 int sigwrap_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, 342 const sigset_t *sigmask) 343 { 344 SIGWRAP_TIMEOUT To; 345 346 if (timeout != NULL) 347 { 348 sigwrap_InitTimeout(&To, timeout); 349 timeout = &To.Timeout; 350 } 351 352 while (1) 353 { 354 int Result = pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask); 355 356 if (Result != -1) 357 return Result; 358 359 if (errno != EINTR) 360 return Result; 361 362 if (timeout == NULL) 363 continue; 364 365 if (sigwrap_CheckTimeout(&To)) 366 return 0; 367 } 368 } 369 370 371 int sigwrap_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) 372 { 373 while (1) 374 { 375 int Result = msgsnd(msqid, msgp, msgsz, msgflg); 376 377 if (Result != -1) 378 return Result; 379 380 if (errno != EINTR) 381 return Result; 382 } 383 } 384 385 386 ssize_t sigwrap_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) 387 { 388 while (1) 389 { 390 ssize_t Result = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); 391 392 if (Result != -1) 393 return Result; 394 395 if (errno != EINTR) 396 return Result; 397 } 398 } 399 400 401 int sigwrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 402 { 403 while (1) 404 { 405 int Result = connect(sockfd, addr, addrlen); 406 407 if (Result != -1) 408 return Result; 409 410 if (errno != EINTR) 411 return Result; 412 } 413 } 414 415 416 ssize_t sigwrap_send(int sockfd, const void *buf, size_t len, int flags) 417 { 418 while (1) 419 { 420 ssize_t Result = send(sockfd, buf, len, flags); 421 422 if (Result != -1) 423 return Result; 424 425 if (errno != EINTR) 426 return Result; 427 } 428 } 429 430 431 ssize_t sigwrap_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, 432 socklen_t addrlen) 433 { 434 while (1) 435 { 436 ssize_t Result = sendto(sockfd, buf, len, flags, dest_addr, addrlen); 437 438 if (Result != -1) 439 return Result; 440 441 if (errno != EINTR) 442 return Result; 443 } 444 } 445 446 447 ssize_t sigwrap_sendsendmsg(int sockfd, const struct msghdr *msg, int flags) 448 { 449 while (1) 450 { 451 ssize_t Result = sendmsg(sockfd, msg, flags); 452 453 if (Result != -1) 454 return Result; 455 456 if (errno != EINTR) 457 return Result; 458 } 459 } 460 461 462 int sigwrap_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 463 { 464 while (1) 465 { 466 int Result = accept(sockfd, addr, addrlen); 467 468 if (Result != -1) 469 return Result; 470 471 if (errno != EINTR) 472 return Result; 473 } 474 } 475 476 // EINTR wrapper for the standard read() function. Can be used for sockets that are the to non-blocking mode. 477 // The length of the returned data can be shorter than the requested one! 478 479 ssize_t sigwrap_read(int fd, void *buf, size_t count) 480 { 481 while (1) 482 { 483 ssize_t Result = read(fd, buf, count); 484 485 if (Result != -1) 486 return (Result); 487 488 if (errno != EINTR) 489 return (Result); 490 } 491 } 492 493 494 // EINTR wrapper for the standard read() function. Waits until ALL requested data is available. Use the non-blocking version (sigwrap_read) 495 // for sockets that are set to non-blocking mode or when partial data is okay 496 // Although the description for the read() function describes it differently, it seems possible that the original function may already return 497 // even though partial data has already been read. This implementation makes sure that all requested data have been read. 498 // See the comment in the signal description https://linux.die.net/man/7/signal 499 //* read(2), readv(2), write(2), writev(2), and ioctl(2) calls on "slow" devices. 500 //* A "slow" device is one where the I/O call may block for an indefinite time, for example, a terminal, pipe, or socket. 501 //* (A disk is not a slow device according to this definition.) If an I/O call on a slow device has already transferred 502 //* 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). 503 504 ssize_t sigwrap_blocking_read(int hFile, void *pData, size_t RdLen) 505 { 506 ssize_t Transfered; 507 ssize_t Len = RdLen; 508 509 while ((Transfered = read(hFile, pData, Len)) != Len) 510 { 511 if (Transfered == 0) // EOF reached? 512 return 0; 513 514 if (Transfered != -1) 515 { 516 pData += Transfered; 517 Len -= Transfered; 518 continue; 519 } 520 521 if (errno != EINTR) 522 return -1; 523 } 524 525 return RdLen; 526 } 527 528 529 ssize_t sigwrap_readv(int fd, const struct iovec *iov, int iovcnt) 530 { 531 while (1) 532 { 533 ssize_t Result = readv(fd, iov, iovcnt); 534 535 if (Result != -1) 536 return (Result); 537 538 if (errno != EINTR) 539 return (Result); 540 } 541 } 542 543 544 ssize_t sigwrap_recv(int sockfd, void *buf, size_t len, int flags) 545 { 546 while (1) 547 { 548 ssize_t Result = recv(sockfd, buf, len, flags); 549 550 if (Result != -1) 551 return (Result); 552 553 if (errno != EINTR) 554 return (Result); 555 } 556 } 557 558 559 ssize_t sigwrap_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) 560 { 561 while (1) 562 { 563 ssize_t Result = recvfrom(sockfd, buf, len, flags, src_addr, addrlen); 564 565 if (Result != -1) 566 return (Result); 567 568 if (errno != EINTR) 569 return (Result); 570 } 571 } 572 573 574 ssize_t sigwrap_recvmsg(int sockfd, struct msghdr *msg, int flags) 575 { 576 while (1) 577 { 578 ssize_t Result = recvmsg(sockfd, msg, flags); 579 580 if (Result != -1) 581 return (Result); 582 583 if (errno != EINTR) 584 return (Result); 585 } 586 } 587 588 589 // EINTR wrapper for the standard write() function. Can be used for sockets that are the to non-blocking mode. 590 // The length of the effectively written data can be shorter than the length specified at the function call! 591 592 ssize_t sigwrap_write(int fd, const void *buf, size_t count) 593 { 594 while (1) 595 { 596 ssize_t Result = write(fd, buf, count); 597 598 if (Result != -1) 599 return (Result); 600 601 if (errno != EINTR) 602 return (Result); 603 } 604 } 605 606 // EINTR wrapper for the standard write() function. Waits until ALL data is written! Use the non-blocking version (sigwrap_write) 607 // for sockets that are set to non-blocking mode, or when it is OK to write only partial data. 608 // Although the description for the write() function describes it differently, it seems possible that the original function may already return 609 // even though partial data has already been written. This implementation makes sure that all requested data have been written. 610 // See the comment in the signal description https://linux.die.net/man/7/signal 611 //* read(2), readv(2), write(2), writev(2), and ioctl(2) calls on "slow" devices. 612 //* A "slow" device is one where the I/O call may block for an indefinite time, for example, a terminal, pipe, or socket. 613 //* (A disk is not a slow device according to this definition.) If an I/O call on a slow device has already transferred 614 //* 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). 615 616 ssize_t sigwrap_blocking_write(int hFile, const void *pData, ssize_t WrtLen) 617 { 618 ssize_t Written; 619 ssize_t Len = WrtLen; 620 621 while ((Written = write(hFile, pData, Len)) != Len) 622 { 623 if (Written != -1) 624 { 625 pData += Written; 626 Len -= Written; 627 continue; 628 } 629 630 if (errno != EINTR) 631 return -1; 632 } 633 634 return WrtLen; 635 } 636 637 638 ssize_t sigwrap_writev(int fd, const struct iovec *iov, int iovcnt) 639 { 640 while (1) 641 { 642 ssize_t Result = writev(fd, iov, iovcnt); 643 644 if (Result != -1) 645 return (Result); 646 647 if (errno != EINTR) 648 return (Result); 649 } 650 } 651 652 653 int sigwrap_close(int hFile) 654 { 655 while (close(hFile) == -1) 656 { 657 if (errno != EINTR) 658 return -1; 659 } 660 661 return 0; 662 } 663 664 665 int sigwrap_open_mode(const char *pathname, int flags, mode_t mode) 666 { 667 while (1) 668 { 669 int hFile = open(pathname, flags, mode); 670 671 if(hFile != -1) 672 return hFile; 673 674 if (errno != EINTR) 675 return hFile; 676 } 677 } 678 679 int sigwrap_open(const char *pathname, int flags) 680 { 681 while (1) 682 { 683 int hFile = open(pathname, flags); 684 685 if(hFile != -1) 686 return hFile; 687 688 if (errno != EINTR) 689 return hFile; 690 } 691 } 692 693 694 pid_t sigwrap_wait(int *status) 695 { 696 while(1) 697 { 698 pid_t Result = wait(status); 699 700 if(Result != -1) 701 return Result; 702 703 if(errno != EINTR) 704 return Result; 705 } 706 } 707 708 709 pid_t sigwrap_waitpid(pid_t pid, int *status, int options) 710 { 711 while(1) 712 { 713 pid_t Result = waitpid(pid, status, options); 714 715 if(Result != -1) 716 return Result; 717 718 if(errno != EINTR) 719 return Result; 720 } 721 } 722 723 724 int sigwrap_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) 725 { 726 while(1) 727 { 728 int Result = waitid(idtype, id, infop, options); 729 730 if(Result != -1) 731 return Result; 732 733 if(errno != EINTR) 734 return Result; 735 } 736 } 737 738 739 int sigwrap_flock(int fd, int operation) 740 { 741 while(1) 742 { 743 int Result = flock(fd, operation); 744 745 if(Result != -1) 746 return Result; 747 748 if(errno != EINTR) 749 return Result; 750 } 751 } 752 753 754