poll.c 5.93 KB
Newer Older
1 2 3 4 5 6 7
/* This file is part of the Sofia-SIP package.

   Copyright (C) 2005 Nokia Corporation.

   Contact: Pekka Pessi <pekka.pessi@nokia.com>

   This file is originally from GNU C library.
8

9 10 11 12
   Copyright (C) 1994,1996,1997,1998,1999,2001,2002
   Free Software Foundation, Inc.
   
   This library is free software; you can redistribute it and/or
13 14 15 16
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

17
   This library is distributed in the hope that it will be useful,
18 19 20 21 22 23 24 25 26 27 28
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include "config.h"

29
#if HAVE_SELECT
30 31 32 33 34 35 36 37

#include "sofia-sip/su.h"

#include <alloca.h>
#include <string.h>

#include "sofia-sip/su_wait.h"

38 39 40 41
#undef NBBY
#undef NFDBITS
#undef FDSETSIZE
#undef roundup
42

43 44
#define	NBBY  8					/* bits in a byte */
#define NFDBITS	(sizeof(long) * NBBY)		/* bits per mask */
45

46 47
#define FDSETSIZE(n) (((n) + NFDBITS - 1) / NFDBITS * (NFDBITS / NBBY))
#define roundup(n, x) (((n) + (x) - 1) / (x) * (x))
48

49
/* Emulated poll() using select(). 
50

51
This is used by su_wait().
52

53 54 55 56 57
Poll the file descriptors described by the NFDS structures starting at
FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors.  */
58 59 60

int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
61 62 63 64
  struct timeval tv;
  struct pollfd *f;
  int ready;
  int maxfd = 0;
65 66

#if HAVE_ALLOCA_H
67 68 69
  static int max_fd_size;
  int bytes;
  fd_set *rset, *wset, *xset;
70

71 72
  if (!max_fd_size)
    max_fd_size = getdtablesize ();
73

74
  bytes = FDSETSIZE (max_fd_size);
75

76 77 78 79 80 81 82 83 84
  rset = alloca (bytes);
  wset = alloca (bytes);
  xset = alloca (bytes);

  /* We can't call FD_ZERO, since FD_ZERO only works with sets
     of exactly __FD_SETSIZE size.  */
  memset (rset, 0, bytes);
  memset (wset, 0, bytes);
  memset (xset, 0, bytes);
85
#else
86
  fd_set rset[1], wset[1], xset[1];
87

88 89 90 91
  FD_ZERO(rset);
  FD_ZERO(wset);
  FD_ZERO(xset);
#endif
92

93
  for (f = fds; f < &fds[nfds]; ++f)
94
    {
95 96
      f->revents = 0;
      if (f->fd >= 0)
97 98
	{
#if HAVE_ALLOCA_H
99
	  if (f->fd >= max_fd_size)
100
	    {
101 102 103 104 105
	      /* The user provides a file descriptor number which is higher
		 than the maximum we got from the `getdtablesize' call.
		 Maybe this is ok so enlarge the arrays.  */
	      fd_set *nrset, *nwset, *nxset;
	      int nbytes;
106

107 108
	      max_fd_size = roundup (f->fd, NFDBITS);
	      nbytes = FDSETSIZE (max_fd_size);
109

110 111 112
	      nrset = alloca (nbytes);
	      nwset = alloca (nbytes);
	      nxset = alloca (nbytes);
113

114 115 116
	      memset ((char *) nrset + bytes, 0, nbytes - bytes);
	      memset ((char *) nwset + bytes, 0, nbytes - bytes);
	      memset ((char *) nxset + bytes, 0, nbytes - bytes);
117

118 119 120
	      rset = memcpy (nrset, rset, bytes);
	      wset = memcpy (nwset, wset, bytes);
	      xset = memcpy (nxset, xset, bytes);
121

122
	      bytes = nbytes;
123 124
	    }
#else
125 126 127 128
	  if (f->fd >= FD_SETSIZE) {
	    errno = EBADF;
	    return -1;
	  }
129 130
#endif /* HAVE_ALLOCA_H */

131 132 133 134 135 136 137 138
	  if (f->events & POLLIN)
	    FD_SET (f->fd, rset);
	  if (f->events & POLLOUT)
	    FD_SET (f->fd, wset);
	  if (f->events & POLLPRI)
	    FD_SET (f->fd, xset);
	  if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
	    maxfd = f->fd;
139 140 141
	}
    }

142 143
  tv.tv_sec = timeout / 1000;
  tv.tv_usec = (timeout % 1000) * 1000;
144

145
  while (1)
146
    {
147 148
      ready = select (maxfd + 1, rset, wset, xset,
		      timeout == -1 ? NULL : &tv);
149

150 151 152
      /* It might be that one or more of the file descriptors is invalid.
	 We now try to find and mark them and then try again.  */
      if (ready == -1 && errno == EBADF)
153
	{
154
	  struct timeval sngl_tv;
155
#if HAVE_ALLOCA_H
156 157 158 159 160 161 162 163
	  fd_set *sngl_rset = alloca (bytes);
	  fd_set *sngl_wset = alloca (bytes);
	  fd_set *sngl_xset = alloca (bytes);

	  /* Clear the original set.  */
	  memset (rset, 0, bytes);
	  memset (wset, 0, bytes);
	  memset (xset, 0, bytes);
164
#else
165 166 167
	  fd_set sngl_rset[1];
	  fd_set sngl_wset[1];
	  fd_set sngl_xset[1];
168

169 170 171
	  FD_ZERO(rset);
	  FD_ZERO(wset);
	  FD_ZERO(xset);
172 173
#endif

174 175 176
	  /* This means we don't wait for input.  */
	  sngl_tv.tv_sec = 0;
	  sngl_tv.tv_usec = 0;
177

178
	  maxfd = -1;
179

180 181
	  /* Reset the return value.  */
	  ready = 0;
182

183 184 185 186 187
	  for (f = fds; f < &fds[nfds]; ++f)
	    if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
		&& (f->revents & POLLNVAL) == 0)
	      {
		int n;
188 189

#if HAVE_ALLOCA_H
190 191 192
		memset (sngl_rset, 0, bytes);
		memset (sngl_wset, 0, bytes);
		memset (sngl_xset, 0, bytes);
193
#else
194 195 196
		FD_ZERO(rset);
		FD_ZERO(wset);
		FD_ZERO(xset);
197 198
#endif

199 200 201 202 203 204 205 206 207 208 209 210
		if (f->events & POLLIN)
		  FD_SET (f->fd, sngl_rset);
		if (f->events & POLLOUT)
		  FD_SET (f->fd, sngl_wset);
		if (f->events & POLLPRI)
		  FD_SET (f->fd, sngl_xset);

		n = select (f->fd + 1, sngl_rset, sngl_wset, sngl_xset,
			    &sngl_tv);
		if (n != -1)
		  {
		    /* This descriptor is ok.  */
211
		    if (f->events & POLLIN)
212
		      FD_SET (f->fd, rset);
213
		    if (f->events & POLLOUT)
214
		      FD_SET (f->fd, wset);
215
		    if (f->events & POLLPRI)
216 217 218 219 220 221 222 223 224 225 226 227
		      FD_SET (f->fd, xset);
		    if (f->fd > maxfd)
		      maxfd = f->fd;
		    if (n > 0)
		      /* Count it as being available.  */
		      ++ready;
		  }
		else if (errno == EBADF)
		  f->revents |= POLLNVAL;
	      }
	  /* Try again.  */
	  continue;
228 229
	}

230
      break;
231 232
    }

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  if (ready > 0) 
    for (f = fds; f < &fds[nfds]; ++f)
      {
	if (f->fd >= 0)
	  {
	    if (FD_ISSET (f->fd, rset))
	      f->revents |= POLLIN;
	    if (FD_ISSET (f->fd, wset))
	      f->revents |= POLLOUT;
	    if (FD_ISSET (f->fd, xset))
	      f->revents |= POLLPRI;
	  }
      }

  return ready;
248 249 250
}

#endif