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