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