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