| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | /*---------------------------------------------------------------------------*\
 | 
					
						
							|  |  |  |  |   $Id$ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   NAME | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	poll - select(2)-based poll() emulation function for BSD systems. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   SYNOPSIS | 
					
						
							|  |  |  |  | 	#include "poll.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	struct pollfd | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 	    int     fd; | 
					
						
							|  |  |  |  | 	    short   events; | 
					
						
							|  |  |  |  | 	    short   revents; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	int poll (struct pollfd *pArray, unsigned long n_fds, int timeout) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   DESCRIPTION | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	This file, and the accompanying "poll.h", implement the System V | 
					
						
							|  |  |  |  | 	poll(2) system call for BSD systems (which typically do not provide | 
					
						
							|  |  |  |  | 	poll()).  Poll() provides a method for multiplexing input and output | 
					
						
							|  |  |  |  | 	on multiple open file descriptors; in traditional BSD systems, that | 
					
						
							|  |  |  |  | 	capability is provided by select().  While the semantics of select() | 
					
						
							|  |  |  |  | 	differ from those of poll(), poll() can be readily emulated in terms | 
					
						
							|  |  |  |  | 	of select() -- which is how this function is implemented. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   REFERENCES | 
					
						
							|  |  |  |  | 	Stevens, W. Richard. Unix Network Programming.  Prentice-Hall, 1990. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   NOTES | 
					
						
							|  |  |  |  | 	1. This software requires an ANSI C compiler. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   LICENSE | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	This software is released under the following license: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		Copyright (c) 1995-2002 Brian M. Clapper | 
					
						
							|  |  |  |  | 		All rights reserved. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		Redistribution and use in source and binary forms are | 
					
						
							|  |  |  |  | 		permitted provided that: (1) source distributions retain | 
					
						
							|  |  |  |  | 		this entire copyright notice and comment; (2) modifications | 
					
						
							|  |  |  |  | 		made to the software are prominently mentioned, and a copy | 
					
						
							|  |  |  |  | 		of the original software (or a pointer to its location) are | 
					
						
							|  |  |  |  | 		included; and (3) distributions including binaries display | 
					
						
							|  |  |  |  | 		the following acknowledgement: "This product includes | 
					
						
							|  |  |  |  | 		software developed by Brian M. Clapper <bmc@clapper.org>" | 
					
						
							|  |  |  |  | 		in the documentation or other materials provided with the | 
					
						
							|  |  |  |  | 		distribution. The name of the author may not be used to | 
					
						
							|  |  |  |  | 		endorse or promote products derived from this software | 
					
						
							|  |  |  |  | 		without specific prior written permission. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS | 
					
						
							|  |  |  |  | 		OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE | 
					
						
							|  |  |  |  | 		IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | 
					
						
							|  |  |  |  | 		PARTICULAR PURPOSE. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	Effectively, this means you can do what you want with the software | 
					
						
							|  |  |  |  | 	except remove this notice or take advantage of the author's name. | 
					
						
							|  |  |  |  | 	If you modify the software and redistribute your modified version, | 
					
						
							|  |  |  |  | 	you must indicate that your version is a modification of the | 
					
						
							|  |  |  |  | 	original, and you must provide either a pointer to or a copy of the | 
					
						
							|  |  |  |  | 	original. | 
					
						
							|  |  |  |  | \*---------------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*---------------------------------------------------------------------------*\
 | 
					
						
							|  |  |  |  | 				 Includes | 
					
						
							|  |  |  |  | \*---------------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <unistd.h>			     /* standard Unix definitions */
 | 
					
						
							|  |  |  |  | #include <sys/types.h>                       /* system types */
 | 
					
						
							|  |  |  |  | #include <sys/time.h>                        /* time definitions */
 | 
					
						
							|  |  |  |  | #include <assert.h>                          /* assertion macros */
 | 
					
						
							|  |  |  |  | #include <string.h>                          /* string functions */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  |  | #include "asterisk/poll-compat.h"                            /* this package */
 | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /*---------------------------------------------------------------------------*\
 | 
					
						
							|  |  |  |  | 				  Macros | 
					
						
							|  |  |  |  | \*---------------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #ifndef MAX
 | 
					
						
							|  |  |  |  | #define MAX(a,b)	((a) > (b) ? (a) : (b))
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |  | 
					
						
							|  |  |  |  | /*---------------------------------------------------------------------------*\
 | 
					
						
							|  |  |  |  | 			     Private Functions | 
					
						
							|  |  |  |  | \*---------------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int map_poll_spec | 
					
						
							|  |  |  |  | #if __STDC__ > 0
 | 
					
						
							|  |  |  |  | 			(struct pollfd *pArray, | 
					
						
							|  |  |  |  | 			  unsigned long  n_fds, | 
					
						
							|  |  |  |  | 			  fd_set        *pReadSet, | 
					
						
							|  |  |  |  | 			  fd_set        *pWriteSet, | 
					
						
							|  |  |  |  | 			  fd_set        *pExceptSet) | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | 			 (pArray, n_fds, pReadSet, pWriteSet, pExceptSet) | 
					
						
							|  |  |  |  | 			  struct pollfd *pArray; | 
					
						
							|  |  |  |  | 			  unsigned long  n_fds; | 
					
						
							|  |  |  |  | 			  fd_set        *pReadSet; | 
					
						
							|  |  |  |  | 			  fd_set        *pWriteSet; | 
					
						
							|  |  |  |  | 			  fd_set        *pExceptSet; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	register unsigned long  i;                   /* loop control */ | 
					
						
							|  |  |  |  | 	register struct	    pollfd *pCur;        /* current array element */ | 
					
						
							|  |  |  |  | 	register int	    max_fd = -1;         /* return value */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/*!\note
 | 
					
						
							|  |  |  |  | 	 * Map the poll() structures into the file descriptor sets required | 
					
						
							|  |  |  |  | 	 * by select(). | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { | 
					
						
							|  |  |  |  | 		/* Skip any bad FDs in the array. */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (pCur->fd < 0) | 
					
						
							|  |  |  |  | 			continue; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (pCur->events & POLLIN) { | 
					
						
							|  |  |  |  | 			/* "Input Ready" notification desired. */ | 
					
						
							|  |  |  |  | 			FD_SET(pCur->fd, pReadSet); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (pCur->events & POLLOUT) { | 
					
						
							|  |  |  |  | 			/* "Output Possible" notification desired. */ | 
					
						
							|  |  |  |  | 			FD_SET(pCur->fd, pWriteSet); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (pCur->events & POLLPRI) { | 
					
						
							|  |  |  |  | 			/*!\note
 | 
					
						
							|  |  |  |  | 			 * "Exception Occurred" notification desired.  (Exceptions | 
					
						
							|  |  |  |  | 			 * include out of band data.) | 
					
						
							|  |  |  |  | 			 */ | 
					
						
							|  |  |  |  | 			FD_SET(pCur->fd, pExceptSet); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		max_fd = MAX(max_fd, pCur->fd); | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	return max_fd; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  |  | 
					
						
							|  |  |  |  | static struct timeval *map_timeout | 
					
						
							|  |  |  |  | #if __STDC__ > 0
 | 
					
						
							|  |  |  |  | 			(int poll_timeout, struct timeval *pSelTimeout) | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | 			(poll_timeout, pSelTimeout) | 
					
						
							|  |  |  |  | 			 int             poll_timeout; | 
					
						
							|  |  |  |  | 			 struct timeval *pSelTimeout; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	struct timeval *pResult; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/*!\note
 | 
					
						
							|  |  |  |  | 	 * Map the poll() timeout value into a select() timeout.  The possible | 
					
						
							|  |  |  |  | 	 * values of the poll() timeout value, and their meanings, are: | 
					
						
							|  |  |  |  | 	 * | 
					
						
							|  |  |  |  | 	 * VALUE	MEANING | 
					
						
							|  |  |  |  | 	 * | 
					
						
							|  |  |  |  | 	 * -1	wait indefinitely (until signal occurs) | 
					
						
							|  |  |  |  | 	 *  0	return immediately, don't block | 
					
						
							|  |  |  |  | 	 * >0	wait specified number of milliseconds | 
					
						
							|  |  |  |  | 	 * | 
					
						
							|  |  |  |  | 	 * select() uses a "struct timeval", which specifies the timeout in | 
					
						
							|  |  |  |  | 	 * seconds and microseconds, so the milliseconds value has to be mapped | 
					
						
							|  |  |  |  | 	 * accordingly. | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	assert(pSelTimeout != (struct timeval *) NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch (poll_timeout) { | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 	case -1: | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		/*
 | 
					
						
							|  |  |  |  | 		 * A NULL timeout structure tells select() to wait indefinitely. | 
					
						
							|  |  |  |  | 		 */ | 
					
						
							|  |  |  |  | 		pResult = (struct timeval *) NULL; | 
					
						
							|  |  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	case 0: | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		/*
 | 
					
						
							|  |  |  |  | 		 * "Return immediately" (test) is specified by all zeros in | 
					
						
							|  |  |  |  | 		 * a timeval structure. | 
					
						
							|  |  |  |  | 		 */ | 
					
						
							|  |  |  |  | 		pSelTimeout->tv_sec  = 0; | 
					
						
							|  |  |  |  | 		pSelTimeout->tv_usec = 0; | 
					
						
							|  |  |  |  | 		pResult = pSelTimeout; | 
					
						
							|  |  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		/* Wait the specified number of milliseconds. */ | 
					
						
							|  |  |  |  | 		pSelTimeout->tv_sec  = poll_timeout / 1000; /* get seconds */ | 
					
						
							|  |  |  |  | 		poll_timeout        %= 1000;                /* remove seconds */ | 
					
						
							|  |  |  |  | 		pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */ | 
					
						
							|  |  |  |  | 		pResult = pSelTimeout; | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	return pResult; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  |  | 
					
						
							|  |  |  |  | static void map_select_results | 
					
						
							|  |  |  |  | #if __STDC__ > 0
 | 
					
						
							|  |  |  |  | 			 (struct pollfd *pArray, | 
					
						
							|  |  |  |  | 			  unsigned long  n_fds, | 
					
						
							|  |  |  |  | 			  fd_set        *pReadSet, | 
					
						
							|  |  |  |  | 			  fd_set        *pWriteSet, | 
					
						
							|  |  |  |  | 			  fd_set        *pExceptSet) | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | 			 (pArray, n_fds, pReadSet, pWriteSet, pExceptSet) | 
					
						
							|  |  |  |  | 			  struct pollfd *pArray; | 
					
						
							|  |  |  |  | 			  unsigned long  n_fds; | 
					
						
							|  |  |  |  | 			  fd_set        *pReadSet; | 
					
						
							|  |  |  |  | 			  fd_set        *pWriteSet; | 
					
						
							|  |  |  |  | 			  fd_set        *pExceptSet; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	register unsigned long  i;                   /* loop control */ | 
					
						
							|  |  |  |  | 	register struct	    pollfd *pCur;        /* current array element */ | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { | 
					
						
							|  |  |  |  | 		/* Skip any bad FDs in the array. */ | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		if (pCur->fd < 0) { | 
					
						
							|  |  |  |  | 			continue; | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		/* Exception events take priority over input events. */ | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		pCur->revents = 0; | 
					
						
							|  |  |  |  | 		if (FD_ISSET (pCur->fd, pExceptSet)) { | 
					
						
							|  |  |  |  | 			pCur->revents |= POLLPRI; | 
					
						
							|  |  |  |  | 		} else if (FD_ISSET (pCur->fd, pReadSet)) { | 
					
						
							|  |  |  |  | 			pCur->revents |= POLLIN; | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 		if (FD_ISSET (pCur->fd, pWriteSet)) { | 
					
						
							|  |  |  |  | 			pCur->revents |= POLLOUT; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  |  | 
					
						
							|  |  |  |  | /*---------------------------------------------------------------------------*\
 | 
					
						
							|  |  |  |  | 			     Public Functions | 
					
						
							|  |  |  |  | \*---------------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | int poll | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #if __STDC__ > 0
 | 
					
						
							|  |  |  |  | 	(struct pollfd *pArray, unsigned long n_fds, int timeout) | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | 	(pArray, n_fds, timeout) | 
					
						
							|  |  |  |  | 	 struct	       pollfd *pArray; | 
					
						
							|  |  |  |  | 	 unsigned long n_fds; | 
					
						
							|  |  |  |  | 	 int	       timeout; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	fd_set  read_descs;                          /* input file descs */ | 
					
						
							|  |  |  |  | 	fd_set  write_descs;                         /* output file descs */ | 
					
						
							|  |  |  |  | 	fd_set  except_descs;                        /* exception descs */ | 
					
						
							|  |  |  |  | 	struct  timeval stime;                       /* select() timeout value */ | 
					
						
							|  |  |  |  | 	int	    ready_descriptors;                   /* function result */ | 
					
						
							| 
									
										
										
										
											2008-09-03 13:26:43 +00:00
										 |  |  |  | 	int	    max_fd = 0;                          /* maximum fd value */ | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	struct  timeval *pTimeout;                   /* actually passed */ | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	FD_ZERO (&read_descs); | 
					
						
							|  |  |  |  | 	FD_ZERO (&write_descs); | 
					
						
							|  |  |  |  | 	FD_ZERO (&except_descs); | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	/* Map the poll() file descriptor list in the select() data structures. */ | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-03 13:26:43 +00:00
										 |  |  |  | 	if (pArray) { | 
					
						
							|  |  |  |  |     	max_fd = map_poll_spec (pArray, n_fds, | 
					
						
							|  |  |  |  | 				&read_descs, &write_descs, &except_descs); | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	/* Map the poll() timeout value in the select() timeout structure. */ | 
					
						
							|  |  |  |  | 	pTimeout = map_timeout(timeout, &stime); | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	/* Make the select() call. */ | 
					
						
							|  |  |  |  | 	ready_descriptors = select(max_fd + 1, &read_descs, &write_descs, | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 				&except_descs, pTimeout); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	if (ready_descriptors >= 0) { | 
					
						
							|  |  |  |  | 		map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs); | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  |  | 	return ready_descriptors; | 
					
						
							| 
									
										
										
										
											2003-10-26 19:17:28 +00:00
										 |  |  |  | } |