opendir change: refinement
[minix.git] / lib / libasyn / asyn_special.c
blob544bc429903fafe1db11dc2fb749fbff58756fa0
1 /* asyn_special(), asyn_result() Author: Kees J. Bot
2 * 8 Jul 1997
3 */
4 #include "asyn.h"
5 #include <signal.h>
7 /* Saved signal mask between asyn_special() and asyn_result(). */
8 static sigset_t mask;
10 int asyn_special(asynchio_t *asyn, int fd, int op)
11 /* Wait for an operation. This is an odd one out compared to asyn_read()
12 * and asyn_write(). It does not do an operation itself, but together with
13 * asyn_result() it is a set of brackets around a system call xxx that has
14 * no asyn_xxx() for itself. It can be used to build an asyn_accept() or
15 * asyn_connect() for instance. (Minix-vmd has asyn_ioctl() instead,
16 * which is used for any other event like TCP/IP listen/connect. BSD has
17 * a myriad of calls that can't be given an asyn_xxx() counterpart each.)
18 * Asyn_special() returns -1 for "forget it", 0 for "try it", and 1 for
19 * "very first call, maybe you should try it once, maybe not". Errno is
20 * set to EAGAIN if the result is -1 or 1. After trying the system call
21 * make sure errno equals EAGAIN if the call is still in progress and call
22 * asyn_result with the result of the system call. Asyn_result() must be
23 * called if asyn_special() returns 0 or 1.
25 * Example use:
27 * int asyn_accept(asynchio_t *asyn, int s, struct sockaddr *addr, int *addrlen)
28 * {
29 * int r;
30 * if ((r= asyn_special(asyn, fd, SEL_READ)) < 0) return -1;
31 * r= r == 0 ? accept(fd, addr, addrlen) : -1;
32 * return asyn_result(asyn, fd, SEL_READ, r);
33 * }
35 * int asyn_connect(asynchio_t *asyn, int s, struct sockaddr *name, int namelen)
36 * {
37 * int r;
38 * if ((r= asyn_special(asyn, fd, SEL_WRITE)) < 0) return -1;
39 * if (r == 1 && (r= connect(fd, name, namelen)) < 0) {
40 * if (errno == EINPROGRESS) errno= EAGAIN;
41 * }
42 * return asyn_result(asyn, fd, SEL_WRITE, r);
43 * }
46 asynfd_t *afd;
47 int seen;
49 asyn->asyn_more++;
51 if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; }
52 afd= &asyn->asyn_afd[fd];
54 /* If this is the first async call on this filedescriptor then
55 * remember its file flags.
57 if (!(seen= afd->afd_seen)) {
58 if ((afd->afd_flags= fcntl(fd, F_GETFL)) < 0) return -1;
59 afd->afd_seen= 1;
62 /* Try to read if I/O is pending. */
63 if (!seen || afd->afd_state[op] == PENDING) {
64 sigemptyset(&mask);
65 if (sigprocmask(SIG_SETMASK, &mask, &mask) < 0) return -1;
66 (void) fcntl(fd, F_SETFL, afd->afd_flags | O_NONBLOCK);
68 /* Let the caller try the system call. */
69 errno= EAGAIN;
70 return seen ? 0 : 1;
73 /* Record this read as "waiting". */
74 afd->afd_state[op]= WAITING;
75 FD_SET(fd, &asyn->asyn_fdset[op]);
76 errno= EAGAIN;
77 asyn->asyn_more--;
78 return -1;
81 int asyn_result(asynchio_t *asyn, int fd, int op, int result)
82 /* The caller has tried the system call with the given result. Finish up. */
84 int err;
85 asynfd_t *afd= &asyn->asyn_afd[fd];
87 err= errno;
89 (void) fcntl(fd, F_SETFL, afd->afd_flags);
90 (void) sigprocmask(SIG_SETMASK, &mask, nil);
92 errno= err;
93 if (result != -1 || errno != EAGAIN) {
94 afd->afd_state[op]= IDLE;
95 return result;
98 /* Record this operation as "waiting". */
99 afd->afd_state[op]= WAITING;
100 FD_SET(fd, &asyn->asyn_fdset[op]);
101 errno= EAGAIN;
102 asyn->asyn_more--;
103 return -1;