193fc8128e4ae6596383cf5e3ec601d7ba32a8e7
[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 "util.h"
46 #include "poll.h"
47
48 int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
49     struct timeval tv;
50     fd_set rset, wset, xset;
51     struct pollfd *f;
52     int ready;
53     int maxfd = 0;
54     char data[64];
55
56     FD_ZERO (&rset);
57     FD_ZERO (&wset);
58     FD_ZERO (&xset);
59
60     if (nfds == 0) {
61         if (timeout >= 0) {
62             pa_msleep(timeout);
63             return 0;
64         }
65
66 #ifdef OS_IS_WIN32
67         /*
68          * Windows does not support signals properly so waiting for them would
69          * mean a deadlock.
70          */
71         pa_msleep(100);
72         return 0;
73 #else
74         return select(0, NULL, NULL, NULL, NULL);
75 #endif
76     }
77
78     for (f = fds; f < &fds[nfds]; ++f) {
79         if (f->fd != -1) {
80             if (f->events & POLLIN)
81                 FD_SET (f->fd, &rset);
82             if (f->events & POLLOUT)
83                 FD_SET (f->fd, &wset);
84             if (f->events & POLLPRI)
85                 FD_SET (f->fd, &xset);
86             if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
87                 maxfd = f->fd;
88         }
89     }
90
91     tv.tv_sec = timeout / 1000;
92     tv.tv_usec = (timeout % 1000) * 1000;
93
94     ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
95                     SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
96                     SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
97     if ((ready == -1) && (errno == EBADF)) {
98         ready = 0;
99
100         FD_ZERO (&rset);
101         FD_ZERO (&wset);
102         FD_ZERO (&xset);
103
104         maxfd = -1;
105
106         for (f = fds; f < &fds[nfds]; ++f) {
107             if (f->fd != -1) {
108                 fd_set sngl_rset, sngl_wset, sngl_xset;
109
110                 FD_ZERO (&sngl_rset);
111                 FD_ZERO (&sngl_wset);
112                 FD_ZERO (&sngl_xset);
113
114                 if (f->events & POLLIN)
115                     FD_SET (f->fd, &sngl_rset);
116                 if (f->events & POLLOUT)
117                     FD_SET (f->fd, &sngl_wset);
118                 if (f->events & POLLPRI)
119                     FD_SET (f->fd, &sngl_xset);
120                 if (f->events & (POLLIN|POLLOUT|POLLPRI)) {
121                     struct timeval singl_tv;
122
123                     singl_tv.tv_sec = 0;
124                     singl_tv.tv_usec = 0;
125
126                     if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset,
127                                SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
128                                SELECT_TYPE_ARG5 &singl_tv) != -1) {
129                         if (f->events & POLLIN)
130                             FD_SET (f->fd, &rset);
131                         if (f->events & POLLOUT)
132                             FD_SET (f->fd, &wset);
133                         if (f->events & POLLPRI)
134                             FD_SET (f->fd, &xset);
135                         if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
136                             maxfd = f->fd;
137                         ++ready;
138                     } else if (errno == EBADF)
139                         f->revents |= POLLNVAL;
140                 }
141             }
142         }
143
144         if (ready) {
145         /* Linux alters the tv struct... but it shouldn't matter here ...
146          * as we're going to be a little bit out anyway as we've just eaten
147          * more than a couple of cpu cycles above */
148             ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
149                             SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
150                             SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
151         }
152     }
153
154 #ifdef OS_IS_WIN32
155     errno = WSAGetLastError();
156 #endif
157
158     if (ready > 0) {
159         ready = 0;
160         for (f = fds; f < &fds[nfds]; ++f) {
161             f->revents = 0;
162             if (f->fd != -1) {
163                 if (FD_ISSET (f->fd, &rset)) {
164                     /* support for POLLHUP.  An hung up descriptor does not
165                        increase the return value! */
166                     if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
167                         if (errno == ESHUTDOWN || errno == ECONNRESET ||
168                             errno == ECONNABORTED || errno == ENETRESET) {
169                             fprintf(stderr, "Hangup\n");
170                             f->revents |= POLLHUP;
171                         }
172                     }
173
174                     if (f->revents == 0)
175                         f->revents |= POLLIN;
176                 }
177                 if (FD_ISSET (f->fd, &wset))
178                     f->revents |= POLLOUT;
179                 if (FD_ISSET (f->fd, &xset))
180                     f->revents |= POLLPRI;
181             }
182             if (f->revents)
183                 ready++;
184         }
185     }
186
187     return ready;
188 }
189
190 #endif /* HAVE_SYS_POLL_H */