mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-11-03 04:16:43 +00:00 
			
		
		
		
	https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r285268 | tilghman | 2010-09-07 14:08:09 -0500 (Tue, 07 Sep 2010) | 18 lines Merged revisions 285267 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r285267 | tilghman | 2010-09-07 14:07:17 -0500 (Tue, 07 Sep 2010) | 11 lines Merged revisions 285266 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r285266 | tilghman | 2010-09-07 14:04:50 -0500 (Tue, 07 Sep 2010) | 4 lines Use poll, if indicated to do so, in the ast_poll2 implementation. This fixes the unit tests on FreeBSD 8.0. ........ ................ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@285269 65c4cc65-6c06-0410-ace0-fbb531ad65f3
		
			
				
	
	
		
			308 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*---------------------------------------------------------------------------*\
 | 
						|
  $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 "asterisk.h"
 | 
						|
 | 
						|
#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 */
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include "asterisk/utils.h"                            /* this package */
 | 
						|
#include "asterisk/poll-compat.h"                            /* this package */
 | 
						|
 | 
						|
unsigned int ast_FD_SETSIZE = FD_SETSIZE;
 | 
						|
 | 
						|
#ifndef MAX
 | 
						|
#define MAX(a,b)	a > b ? a : b
 | 
						|
#endif
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------*\
 | 
						|
				 Private Functions
 | 
						|
\*---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#if defined(AST_POLL_COMPAT)
 | 
						|
static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
 | 
						|
		ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
 | 
						|
{
 | 
						|
	register unsigned long  i;     /* loop control */
 | 
						|
	register struct pollfd *pCur;  /* current array element */
 | 
						|
	register int max_fd = -1;      /* return value */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * 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);
 | 
						|
	}
 | 
						|
 | 
						|
	return max_fd;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef AST_POLL_COMPAT
 | 
						|
static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
 | 
						|
{
 | 
						|
	struct timeval *pResult;
 | 
						|
 | 
						|
	/*
 | 
						|
	   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 != NULL);
 | 
						|
 | 
						|
	switch (poll_timeout) {
 | 
						|
	case -1:
 | 
						|
		/*
 | 
						|
		 * A NULL timeout structure tells select() to wait indefinitely.
 | 
						|
		 */
 | 
						|
		pResult = (struct timeval *) NULL;
 | 
						|
		break;
 | 
						|
 | 
						|
	case 0:
 | 
						|
		/*
 | 
						|
		 * "Return immediately" (test) is specified by all zeros in
 | 
						|
		 * a timeval structure.
 | 
						|
		 */
 | 
						|
		pSelTimeout->tv_sec  = 0;
 | 
						|
		pSelTimeout->tv_usec = 0;
 | 
						|
		pResult = pSelTimeout;
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		/* 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;
 | 
						|
	}
 | 
						|
 | 
						|
	return pResult;
 | 
						|
}
 | 
						|
#endif /* AST_POLL_COMPAT */
 | 
						|
 | 
						|
static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
 | 
						|
			  ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
 | 
						|
{
 | 
						|
	register unsigned long  i;    /* loop control */
 | 
						|
	register struct pollfd *pCur; /* current array element */
 | 
						|
 | 
						|
	for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
 | 
						|
		/* Skip any bad FDs in the array. */
 | 
						|
 | 
						|
		if (pCur->fd < 0) {
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Exception events take priority over input events. */
 | 
						|
		pCur->revents = 0;
 | 
						|
		if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
 | 
						|
			pCur->revents |= POLLPRI;
 | 
						|
		} else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
 | 
						|
			pCur->revents |= POLLIN;
 | 
						|
		}
 | 
						|
 | 
						|
		if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
 | 
						|
			pCur->revents |= POLLOUT;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------*\
 | 
						|
				 Public Functions
 | 
						|
\*---------------------------------------------------------------------------*/
 | 
						|
#ifdef AST_POLL_COMPAT
 | 
						|
int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
 | 
						|
{
 | 
						|
	ast_fdset  read_descs;                       /* input file descs */
 | 
						|
	ast_fdset  write_descs;                      /* output file descs */
 | 
						|
	ast_fdset  except_descs;                     /* exception descs */
 | 
						|
	struct  timeval stime;                       /* select() timeout value */
 | 
						|
	int     ready_descriptors;                   /* function result */
 | 
						|
	int     max_fd = 0;                          /* maximum fd value */
 | 
						|
	struct  timeval *pTimeout;                   /* actually passed */
 | 
						|
	int save_errno;
 | 
						|
 | 
						|
	FD_ZERO(&read_descs);
 | 
						|
	FD_ZERO(&write_descs);
 | 
						|
	FD_ZERO(&except_descs);
 | 
						|
 | 
						|
	/* Map the poll() file descriptor list in the select() data structures. */
 | 
						|
 | 
						|
	if (pArray) {
 | 
						|
		max_fd = map_poll_spec (pArray, n_fds,
 | 
						|
				&read_descs, &write_descs, &except_descs);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Map the poll() timeout value in the select() timeout structure. */
 | 
						|
 | 
						|
	pTimeout = map_timeout (timeout, &stime);
 | 
						|
 | 
						|
	/* Make the select() call. */
 | 
						|
 | 
						|
	ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
 | 
						|
				&except_descs, pTimeout);
 | 
						|
	save_errno = errno;
 | 
						|
 | 
						|
	if (ready_descriptors >= 0) {
 | 
						|
		map_select_results (pArray, n_fds,
 | 
						|
				&read_descs, &write_descs, &except_descs);
 | 
						|
	}
 | 
						|
 | 
						|
	errno = save_errno;
 | 
						|
	return ready_descriptors;
 | 
						|
}
 | 
						|
#endif /* AST_POLL_COMPAT */
 | 
						|
 | 
						|
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
 | 
						|
{
 | 
						|
#if !defined(AST_POLL_COMPAT)
 | 
						|
	struct timeval start = ast_tvnow();
 | 
						|
#if defined(HAVE_PPOLL)
 | 
						|
	struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
 | 
						|
	int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
 | 
						|
#else
 | 
						|
	int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1);
 | 
						|
#endif
 | 
						|
	struct timeval after = ast_tvnow();
 | 
						|
	if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) {
 | 
						|
		*tv = ast_tvsub(*tv, ast_tvsub(after, start));
 | 
						|
	} else if (res > 0 && tv) {
 | 
						|
		*tv = ast_tv(0, 0);
 | 
						|
	}
 | 
						|
	return res;
 | 
						|
#else
 | 
						|
	ast_fdset read_descs, write_descs, except_descs;
 | 
						|
	int ready_descriptors, max_fd = 0;
 | 
						|
 | 
						|
	FD_ZERO(&read_descs);
 | 
						|
	FD_ZERO(&write_descs);
 | 
						|
	FD_ZERO(&except_descs);
 | 
						|
 | 
						|
	if (pArray) {
 | 
						|
		max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs);
 | 
						|
	}
 | 
						|
 | 
						|
	ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv);
 | 
						|
 | 
						|
	if (ready_descriptors >= 0) {
 | 
						|
		map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
 | 
						|
	}
 | 
						|
 | 
						|
	return ready_descriptors;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 |