xref: /minix3/minix/lib/libasyn/asyn_wait.c (revision b5e2faaaaf60a8b9a02f8d72f64caa56a87eb312)
1 /*	asyn_wait() - wait for asynch operations	Author: Kees J. Bot
2  *								7 Jul 1997
3  */
4 #define DEBUG 0
5 
6 #include "asyn.h"
7 #include <time.h>
8 #if DEBUG
9 #include <stdio.h>
10 #endif
11 
12 #define TBOUND_MIN	1
13 #define TBOUND_MAX	16
14 
15 int asyn_wait(asynchio_t *asyn, int flags, struct timeval *to)
16 /* Wait for one or more nonblocking operations to return a result. */
17 {
18 	int r;
19 	static struct timeval zero_time;
20 	struct timeval t;
21 	static time_t tbound= TBOUND_MIN;
22 
23 	/* Are there more things to do before we can block? */
24 	if (asyn->asyn_more > 0) { asyn->asyn_more= 0; return 0; }
25 
26 	if (flags & ASYN_NONBLOCK) {
27 		/* Don't block by using a zero second timeout. */
28 		to= &zero_time;
29 	} else
30 	if (to != nil) {
31 		/* asyn_wait() uses an absolute time. */
32 		if (to->tv_usec >= 1000000L) {
33 			to->tv_sec+= to->tv_usec / 1000000L;
34 			to->tv_usec%= 1000000L;
35 		}
36 		(void) gettimeofday(&t, nil);
37 		if (t.tv_sec > to->tv_sec || (t.tv_sec == to->tv_sec
38 						&& t.tv_usec >= to->tv_usec)) {
39 			to= &zero_time;
40 		} else {
41 			t.tv_sec= to->tv_sec - t.tv_sec;
42 			t.tv_usec= to->tv_usec - t.tv_usec;
43 			if (t.tv_usec < 0) {
44 				t.tv_sec--;
45 				t.tv_usec+= 1000000L;
46 			}
47 			to= &t;
48 		}
49 
50 		/* Don't sleep too long, we don't trust select(). */
51 		if (to->tv_sec > tbound) goto bound;
52 	} else {
53 	bound:
54 		/* No timeout?  Don't hang in (buggy?) select() forever. */
55 		to= &t;
56 		t.tv_sec= tbound;
57 		t.tv_usec= 0;
58 	}
59 
60 #if DEBUG
61 	{
62 		int op;
63 
64 		fprintf(stderr, "select: ");
65 		for (op= 0; op < SEL_NR; op++) {
66 			fd_set *fdsetp= &asyn->asyn_fdset[op];
67 			int fd;
68 
69 			for (fd= 0; fd < FD_SETSIZE; fd++) {
70 				if (FD_ISSET(fd, fdsetp)) {
71 					asyn->asyn_afd[fd].afd_state[op]=
72 								PENDING;
73 					fprintf(stderr, "%d%c", fd, "rwx"[op]);
74 				}
75 			}
76 		}
77 		fflush(stderr);
78 	}
79 #endif
80 	r= select(FD_SETSIZE, &asyn->asyn_fdset[SEL_READ],
81 				&asyn->asyn_fdset[SEL_WRITE],
82 				&asyn->asyn_fdset[SEL_EXCEPT], to);
83 #if DEBUG
84 	fprintf(stderr, " (%d) ", r);
85 #endif
86 	if (r > 0) {
87 		/* An event occurred on one or more file descriptors. */
88 		int op;
89 
90 		for (op= 0; op < SEL_NR; op++) {
91 			fd_set *fdsetp= &asyn->asyn_fdset[op];
92 			int fd;
93 
94 			for (fd= 0; fd < FD_SETSIZE; fd++) {
95 				if (FD_ISSET(fd, fdsetp)) {
96 					asyn->asyn_afd[fd].afd_state[op]=
97 								PENDING;
98 #if DEBUG
99 					fprintf(stderr, "%d%c", fd, "rwx"[op]);
100 #endif
101 				}
102 			}
103 		}
104 		tbound= TBOUND_MIN;
105 	} else
106 	if (r == 0) {
107 		/* If nothing happened then let the time boundary slip a bit. */
108 		if (tbound < TBOUND_MAX) tbound <<= 1;
109 	}
110 #if DEBUG
111 	fputc('\n', stderr);
112 #endif
113 
114 	FD_ZERO(&asyn->asyn_fdset[SEL_READ]);
115 	FD_ZERO(&asyn->asyn_fdset[SEL_WRITE]);
116 	FD_ZERO(&asyn->asyn_fdset[SEL_EXCEPT]);
117 
118 	return r == 0 ? (errno= EINTR, -1) : r;
119 }
120