split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch]
[profile/ivi/pulseaudio.git] / src / polypcore / poll.c
1 /* $Id$ */
2
3 /***
4    Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
5    Copyright (C) 2005, Cendio AB.
6    This file is part of polypaudio.
7    Based on work for the GNU C Library.
8
9    polypaudio is free software; you can redistribute it and/or modify it
10    under the terms of the GNU Library General Public License as published
11    by the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    polypaudio is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Library General Public
20    License along with polypaudio; If not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22    USA.
23 ***/
24
25 /* Poll the file descriptors described by the NFDS structures starting at
26    FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
27    an event to occur; if TIMEOUT is -1, block until an event occurs.
28    Returns the number of file descriptors with events, zero if timed out,
29    or -1 for errors.  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <errno.h>
36
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
39 #endif
40
41 #include "winsock.h"
42
43 #ifndef HAVE_SYS_POLL_H
44
45 #include <polypcore/core-util.h>
46
47 #include "poll.h"
48
49 int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
50     struct timeval tv;
51     fd_set rset, wset, xset;
52     struct pollfd *f;
53     int ready;
54     int maxfd = 0;
55     char data[64];
56
57     FD_ZERO (&rset);
58     FD_ZERO (&wset);
59     FD_ZERO (&xset);
60
61     if (nfds == 0) {
62         if (timeout >= 0) {
63             pa_msleep(timeout);
64             return 0;
65         }
66
67 #ifdef OS_IS_WIN32
68         /*
69          * Windows does not support signals properly so waiting for them would
70          * mean a deadlock.
71          */
72         pa_msleep(100);
73         return 0;
74 #else
75         return select(0, NULL, NULL, NULL, NULL);
76 #endif
77     }
78
79     for (f = fds; f < &fds[nfds]; ++f) {
80         if (f->fd != -1) {
81             if (f->events & POLLIN)
82                 FD_SET (f->fd, &rset);
83             if (f->events & POLLOUT)
84                 FD_SET (f->fd, &wset);
85             if (f->events & POLLPRI)
86                 FD_SET (f->fd, &xset);
87             if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
88                 maxfd = f->fd;
89         }
90     }
91
92     tv.tv_sec = timeout / 1000;
93     tv.tv_usec = (timeout % 1000) * 1000;
94
95     ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
96                     SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
97                     SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
98     if ((ready == -1) && (errno == EBADF)) {
99         ready = 0;
100
101         FD_ZERO (&rset);
102         FD_ZERO (&wset);
103         FD_ZERO (&xset);
104
105         maxfd = -1;
106
107         for (f = fds; f < &fds[nfds]; ++f) {
108             if (f->fd != -1) {
109                 fd_set sngl_rset, sngl_wset, sngl_xset;
110
111                 FD_ZERO (&sngl_rset);
112                 FD_ZERO (&sngl_wset);
113                 FD_ZERO (&sngl_xset);
114
115                 if (f->events & POLLIN)
116                     FD_SET (f->fd, &sngl_rset);
117                 if (f->events & POLLOUT)
118                     FD_SET (f->fd, &sngl_wset);
119                 if (f->events & POLLPRI)
120                     FD_SET (f->fd, &sngl_xset);
121                 if (f->events & (POLLIN|POLLOUT|POLLPRI)) {
122                     struct timeval singl_tv;
123
124                     singl_tv.tv_sec = 0;
125                     singl_tv.tv_usec = 0;
126
127                     if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset,
128                                SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
129                                SELECT_TYPE_ARG5 &singl_tv) != -1) {
130                         if (f->events & POLLIN)
131                             FD_SET (f->fd, &rset);
132                         if (f->events & POLLOUT)
133                             FD_SET (f->fd, &wset);
134                         if (f->events & POLLPRI)
135                             FD_SET (f->fd, &xset);
136                         if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
137                             maxfd = f->fd;
138                         ++ready;
139                     } else if (errno == EBADF)
140                         f->revents |= POLLNVAL;
141                 }
142             }
143         }
144
145         if (ready) {
146         /* Linux alters the tv struct... but it shouldn't matter here ...
147          * as we're going to be a little bit out anyway as we've just eaten
148          * more than a couple of cpu cycles above */
149             ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
150                             SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
151                             SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
152         }
153     }
154
155 #ifdef OS_IS_WIN32
156     errno = WSAGetLastError();
157 #endif
158
159     if (ready > 0) {
160         ready = 0;
161         for (f = fds; f < &fds[nfds]; ++f) {
162             f->revents = 0;
163             if (f->fd != -1) {
164                 if (FD_ISSET (f->fd, &rset)) {
165                     /* support for POLLHUP.  An hung up descriptor does not
166                        increase the return value! */
167                     if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
168                         if (errno == ESHUTDOWN || errno == ECONNRESET ||
169                             errno == ECONNABORTED || errno == ENETRESET) {
170                             fprintf(stderr, "Hangup\n");
171                             f->revents |= POLLHUP;
172                         }
173                     }
174
175                     if (f->revents == 0)
176                         f->revents |= POLLIN;
177                 }
178                 if (FD_ISSET (f->fd, &wset))
179                     f->revents |= POLLOUT;
180                 if (FD_ISSET (f->fd, &xset))
181                     f->revents |= POLLPRI;
182             }
183             if (f->revents)
184                 ready++;
185         }
186     }
187
188     return ready;
189 }
190
191 #endif /* HAVE_SYS_POLL_H */