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