X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fpoll.c;h=575bb10745ef34c26bdd5c732bebb5c1a017da8e;hb=4ba419b6cbd377c668d6a221154df358b610ebcc;hp=6c9aec3d6319eeb69f74b2df57030d7dc6db1564;hpb=1a582db112f0d898f93bdcc618e06d75ff8f2410;p=vlc diff --git a/src/network/poll.c b/src/network/poll.c index 6c9aec3d63..575bb10745 100644 --- a/src/network/poll.c +++ b/src/network/poll.c @@ -1,7 +1,7 @@ /***************************************************************************** * poll.c: I/O event multiplexing ***************************************************************************** - * Copyright © 2007-2008 Rémi Denis-Courmont + * Copyright © 2007 Rémi Denis-Courmont * $Id$ * * Author: Rémi Denis-Courmont @@ -26,9 +26,43 @@ #endif #include +#include #include -#ifndef WIN32 + +#ifdef HAVE_MAEMO +# include +# include +# include + +int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) +{ + struct timespec tsbuf, *ts; + sigset_t set; + int canc, ret; + + if (timeout != -1) + { + div_t d = div (timeout, 1000); + tsbuf.tv_sec = d.quot; + tsbuf.tv_nsec = d.rem * 1000000; + ts = &tsbuf; + } + else + ts = NULL; + + pthread_sigmask (SIG_BLOCK, NULL, &set); + sigdelset (&set, SIGRTMIN); + + canc = vlc_savecancel (); + ret = ppoll (fds, nfds, ts, &set); + vlc_restorecancel (canc); + + vlc_testcancel (); + return ret; +} + +#elif defined (HAVE_POLL) struct pollfd; int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) @@ -36,80 +70,96 @@ int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) (void)fds; (void)nfds; (void)timeout; abort (); } -#else +#else /* !HAVE_POLL */ + #include -#include -#include int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) { - WSAEVENT phEvents[nfds]; - DWORD val; + fd_set rdset, wrset, exset; + struct timeval tv = { 0, 0 }; + int val; +resume: + val = -1; vlc_testcancel (); + FD_ZERO (&rdset); + FD_ZERO (&wrset); + FD_ZERO (&exset); for (unsigned i = 0; i < nfds; i++) { - long events = FD_CLOSE; + int fd = fds[i].fd; + if (val < fd) + val = fd; + /* With POSIX, FD_SET & FD_ISSET are not defined if fd is negative or + * bigger or equal than FD_SETSIZE. That is one of the reasons why VLC + * uses poll() rather than select(). Most POSIX systems implement + * fd_set has a bit field with no sanity checks. This is especially bad + * on systems (such as BSD) that have no process open files limit by + * default, such that it is quite feasible to get fd >= FD_SETSIZE. + * The next instructions will result in a buffer overflow if run on + * a POSIX system, and the later FD_ISSET will do undefined memory + * access. + * + * With Winsock, fd_set is a table of integers. This is awfully slow. + * However, FD_SET and FD_ISSET silently and safely discard + * overflows. If it happens we will loose socket events. Note that + * most (if not all) Winsock SOCKET handles are actually bigger than + * FD_SETSIZE in terms of absolute value - they are not POSIX file + * descriptors. From Vista, there is a much nicer WSAPoll(), but Mingw + * is yet to support it. + * + * With BeOS, the situation is unknown (FIXME: document). + */ if (fds[i].events & POLLIN) - events |= FD_READ | FD_ACCEPT; + FD_SET (fd, &rdset); if (fds[i].events & POLLOUT) - events |= FD_WRITE; + FD_SET (fd, &wrset); if (fds[i].events & POLLPRI) - events |= FD_OOB; - fds[i].revents = 0; + FD_SET (fd, &exset); + } - phEvents[i] = WSACreateEvent (); - WSAEventSelect (fds[i].fd, phEvents[i], events); +#ifndef HAVE_ALERTABLE_SELECT +# warning FIXME! Fix cancellation and remove this crap. + if ((timeout < 0) || (timeout > 50)) + { + tv.tv_sec = 0; + tv.tv_usec = 50000; + } + else +#endif + if (timeout >= 0) + { + div_t d = div (timeout, 1000); + tv.tv_sec = d.quot; + tv.tv_usec = d.rem * 1000; } - int ret = 0, n = 0; + val = select (val + 1, &rdset, &wrset, &exset, + /*(timeout >= 0) ?*/ &tv /*: NULL*/); - switch (WaitForMultipleObjectsEx (nfds, phEvents, FALSE, timeout, TRUE)) +#ifndef HAVE_ALERTABLE_SELECT + if (val == 0) { - case WAIT_IO_COMPLETION: - WSASetLastError (WSAEINTR); - ret = -1; - break; - case WAIT_TIMEOUT: - ret = 0; - break; - default: - for (unsigned i = 0; i < nfds; i++) - { - WSANETWORKEVENTS events; - if (WSAEnumNetworkEvents (fds[i].fd, phEvents[i], &events)) - { - fds[i].revents |= POLLNVAL; - ret = -1; - continue; - } - if (events.lNetworkEvents & FD_CLOSE) - fds[i].revents |= POLLHUP | (fds[i].events & POLLIN); - if (events.lNetworkEvents & FD_ACCEPT) - fds[i].revents |= POLLIN; - if (events.lNetworkEvents & FD_OOB) - fds[i].revents |= POLLPRI; - if (events.lNetworkEvents & FD_READ) - fds[i].revents |= POLLIN; - if (events.lNetworkEvents & FD_WRITE) - { - fds[i].revents |= POLLOUT; - if (events.iErrorCode[FD_WRITE_BIT]) - fds[i].revents |= POLLERR; - } - if (fds[i].events) - n++; - } - if (ret == 0) - ret = n; + if (timeout > 0) + timeout -= (timeout > 50) ? 50 : timeout; + if (timeout != 0) + goto resume; } +#endif - for (unsigned i = 0; i < nfds; i++) - WSACloseEvent (phEvents[i]); - vlc_testcancel (); + if (val == -1) + return -1; - return ret; + for (unsigned i = 0; i < nfds; i++) + { + int fd = fds[i].fd; + fds[i].revents = (FD_ISSET (fd, &rdset) ? POLLIN : 0) + | (FD_ISSET (fd, &wrset) ? POLLOUT : 0) + | (FD_ISSET (fd, &exset) ? POLLPRI : 0); + } + return val; } -#endif /* WIN32 */ +#endif /* !HAVE_POLL */