1 /*****************************************************************************\
2 * $Id$
3 *****************************************************************************
4 * Copyright (C) 2001-2006 The Regents of the University of California.
5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
6 * Written by Jim Garlick <garlick@llnl.gov>.
7 * UCRL-CODE-2003-005.
8 *
9 * This file is part of Pdsh, a parallel remote shell program.
10 * For details, see <http://www.llnl.gov/linux/pdsh/>.
11 *
12 * Pdsh is free software; you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with Pdsh; if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 \*****************************************************************************/
26
27 #if HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #if HAVE_POLL_H
32 #include <poll.h>
33 #else
34 #if HAVE_SYS_POLL_H
35 #include <sys/poll.h>
36 #endif /* HAVE_SYS_POLL_H */
37 #endif /* HAVE_POLL_H */
38
39 #include <sys/types.h>
40 #include <sys/select.h>
41 #include <sys/time.h>
42 #if HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48
49 #include "xpoll.h"
50 #include "xmalloc.h"
51
52 #if HAVE_POLL
53 static int
_poll(struct xpollfd * xfds,unsigned int nfds,int timeout)54 _poll(struct xpollfd *xfds, unsigned int nfds, int timeout) {
55 int i, rv;
56 struct pollfd *pfds = Malloc(nfds * sizeof(struct pollfd));
57
58 for (i = 0; i < nfds; i++) {
59 pfds[i].fd = xfds[i].fd;
60 pfds[i].events = 0;
61 pfds[i].revents = 0;
62
63 if (xfds[i].events & XPOLLREAD)
64 pfds[i].events |= POLLIN;
65 if (xfds[i].events & XPOLLWRITE)
66 pfds[i].events |= POLLOUT;
67 }
68
69 if ((rv = poll(pfds, nfds, timeout)) < 0) {
70 Free((void **)&pfds);
71 return -1;
72 }
73
74 for (i = 0; i < nfds; i++) {
75 if (pfds[i].revents & POLLIN)
76 xfds[i].revents |= XPOLLREAD;
77 if (pfds[i].revents & POLLOUT)
78 xfds[i].revents |= XPOLLWRITE;
79 if (pfds[i].revents & POLLERR || pfds[i].revents & POLLHUP)
80 xfds[i].revents |= XPOLLERR;
81 if (pfds[i].revents & POLLNVAL)
82 xfds[i].revents |= XPOLLINVAL;
83 }
84
85 Free((void **)&pfds);
86 errno = 0;
87 return rv;
88 }
89
90 #else /* !HAVE_POLL */
91
92 static int
_select(struct xpollfd * xfds,unsigned int nfds,int timeout)93 _select(struct xpollfd *xfds, unsigned int nfds, int timeout) {
94 int i, maxfd = -1, inval = 0, rv = -1;
95 struct timeval tv;
96 struct timeval *tptr = &tv;
97 fd_set reads, writes;
98
99 if (timeout < 0)
100 tptr = NULL;
101 else {
102 tv.tv_sec = timeout;
103 tv.tv_usec = 0;
104 }
105
106 /* setup for select() */
107 FD_ZERO(&reads);
108 FD_ZERO(&writes);
109 for (i = 0; i < nfds; i++) {
110 if (xfds[i].fd >= FD_SETSIZE || xfds[i].fd < 0) {
111 xfds[i].revents |= XPOLLINVAL;
112 inval++;
113 continue;
114 }
115 if (xfds[i].events & XPOLLREAD)
116 FD_SET(xfds[i].fd, &reads);
117 if (xfds[i].events & XPOLLWRITE)
118 FD_SET(xfds[i].fd, &writes);
119 if (xfds[i].fd > maxfd)
120 maxfd = xfds[i].fd;
121 }
122
123 while (rv == -1) {
124 if ((rv = select(maxfd + 1, &reads, &writes, NULL, tptr)) < 0) {
125 if (errno != EBADF)
126 return -1;
127 else {
128 /* check for and remove bad fds */
129 struct timeval ttv = {0, 1}; /* very very short timeout */
130 fd_set rds, wrs;
131
132 maxfd = -1;
133 FD_ZERO(&reads);
134 FD_ZERO(&writes);
135 for (i = 0; i < nfds; i++) {
136 if (xfds[i].revents & XPOLLINVAL)
137 continue;
138
139 FD_ZERO(&rds);
140 FD_ZERO(&wrs);
141 if (xfds[i].events & XPOLLREAD)
142 FD_SET(xfds[i].fd, &rds);
143 if (xfds[i].events & XPOLLWRITE)
144 FD_SET(xfds[i].fd, &wrs);
145
146 if (select(xfds[i].fd + 1, &rds, &wrs, NULL, &ttv) < 0) {
147 if (errno != EBADF)
148 return -1;
149 else {
150 xfds[i].revents |= XPOLLINVAL;
151 inval++;
152 }
153 }
154 else {
155 /* prepare for next select */
156 if (xfds[i].events & XPOLLREAD)
157 FD_SET(xfds[i].fd, &reads);
158 if (xfds[i].events & XPOLLWRITE)
159 FD_SET(xfds[i].fd, &writes);
160 if (xfds[i].fd > maxfd)
161 maxfd = xfds[i].fd;
162 }
163 }
164 }
165 }
166 }
167
168 for (i = 0; i < nfds; i++) {
169 /* protect segfault prone FD_ISSET */
170 if (xfds[i].revents & XPOLLINVAL)
171 continue;
172
173 if (FD_ISSET(xfds[i].fd, &reads))
174 xfds[i].revents |= XPOLLREAD;
175 if (FD_ISSET(xfds[i].fd, &writes))
176 xfds[i].revents |= XPOLLWRITE;
177 }
178
179 errno = 0;
180 return (rv + inval);
181 }
182 #endif /* HAVE_POLL */
183
xpoll(struct xpollfd * xfds,int nfds,int timeout)184 int xpoll(struct xpollfd *xfds, int nfds, int timeout) {
185 int i;
186
187 errno = 0;
188
189 if (xfds == NULL || nfds <= 0) {
190 errno = EINVAL;
191 return -1;
192 }
193
194 for (i = 0; i < nfds; i++) {
195 xfds[i].revents = 0;
196 }
197
198 #if HAVE_POLL
199 return _poll(xfds, nfds, timeout);
200 #else
201 return _select(xfds, nfds, timeout);
202 #endif
203 }
204
205 /*
206 * vi: tabstop=4 shiftwidth=4 expandtab
207 */
208