dect
/
asterisk
Archived
13
0
Fork 0

Merged revisions 284597 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r284597 | tilghman | 2010-09-02 00:00:34 -0500 (Thu, 02 Sep 2010) | 29 lines
  
  Merged revisions 284593,284595 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2
  
  ................
    r284593 | tilghman | 2010-09-01 17:59:50 -0500 (Wed, 01 Sep 2010) | 18 lines
    
    Merged revisions 284478 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r284478 | tilghman | 2010-09-01 13:49:11 -0500 (Wed, 01 Sep 2010) | 11 lines
      
      Ensure that all areas that previously used select(2) now use poll(2), with implementations that need poll(2) implemented with select(2) safe against 1024-bit overflows.
      
      This is a followup to the fix for the pthread timer in 1.6.2 and beyond, fixing
      a potential crash bug in all supported releases.
      
      (closes issue #17678)
       Reported by: russell
      Branch: https://origsvn.digium.com/svn/asterisk/team/tilghman/ast_select 
      
      Review: https://reviewboard.asterisk.org/r/824/
    ........
  ................
    r284595 | tilghman | 2010-09-01 22:57:43 -0500 (Wed, 01 Sep 2010) | 2 lines
    
    Failed to rerun bootstrap.sh after last commit
  ................
................


git-svn-id: http://svn.digium.com/svn/asterisk/trunk@284598 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
tilghman 2010-09-02 05:02:54 +00:00
parent 37f68a5475
commit c32f63c825
20 changed files with 32277 additions and 7995 deletions

View File

@ -23,6 +23,7 @@
#define _OOSOCKET_H_ #define _OOSOCKET_H_
#include "asterisk/poll-compat.h" #include "asterisk/poll-compat.h"
#include "asterisk/compiler.h"
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
#include <winsock.h> #include <winsock.h>
@ -329,9 +330,9 @@ EXTERN int ooSocketSendTo(OOSOCKET socket, const ASN1OCTET* pdata,
* returns. * returns.
* @return Completion status of operation: 0 (ASN_OK) = success, * @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error. * negative return value is error.
*/ */
EXTERN int ooSocketSelect(int nfds, fd_set *readfds, fd_set *writefds, EXTERN int ooSocketSelect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval * timeout); fd_set *exceptfds, struct timeval * timeout) __attribute_deprecated__;
EXTERN int ooSocketPoll(struct pollfd *pfds, int nfds, int timeout); EXTERN int ooSocketPoll(struct pollfd *pfds, int nfds, int timeout);

View File

@ -15,6 +15,7 @@
*****************************************************************************/ *****************************************************************************/
#include "asterisk.h" #include "asterisk.h"
#include "asterisk/lock.h" #include "asterisk/lock.h"
#include "asterisk/poll-compat.h"
#include "ooports.h" #include "ooports.h"
#include "oochannels.h" #include "oochannels.h"
@ -1980,22 +1981,12 @@ int ooStopMonitorCalls()
OOBOOL ooChannelsIsConnectionOK(OOH323CallData *call, OOSOCKET sock) OOBOOL ooChannelsIsConnectionOK(OOH323CallData *call, OOSOCKET sock)
{ {
struct timeval to; struct timeval to = { .tv_usec = 500 };
fd_set readfds; struct pollfd pfds = { .fd = sock, .events = POLLIN };
int ret = 0, nfds=0; int ret = 0;
to.tv_sec = 0; ret = ast_poll2(&pfds, 1, &to);
to.tv_usec = 500;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
if(nfds < (int)sock)
nfds = (int)sock;
nfds++;
ret = ooSocketSelect(nfds, &readfds, NULL, NULL, &to);
if(ret == -1) if(ret == -1)
{ {
OOTRACEERR3("Error in select ...broken pipe check(%s, %s)\n", OOTRACEERR3("Error in select ...broken pipe check(%s, %s)\n",

View File

@ -7160,15 +7160,14 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
static struct ast_frame *misdn_read(struct ast_channel *ast) static struct ast_frame *misdn_read(struct ast_channel *ast)
{ {
struct chan_list *tmp; struct chan_list *tmp;
fd_set rrfs;
struct timeval tv = { 0, 20000 };
int len, t; int len, t;
struct pollfd pfd = { .fd = -1, .events = POLLIN };
if (!ast) { if (!ast) {
chan_misdn_log(1, 0, "misdn_read called without ast\n"); chan_misdn_log(1, 0, "misdn_read called without ast\n");
return NULL; return NULL;
} }
if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) { if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n"); chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
return NULL; return NULL;
} }
@ -7178,21 +7177,18 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
return NULL; return NULL;
} }
FD_ZERO(&rrfs); pfd.fd = tmp->pipe[0];
FD_SET(tmp->pipe[0], &rrfs); t = ast_poll(&pfd, 1, 20);
t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv);
if (!t) {
chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
len = 160;
}
if (t < 0) { if (t < 0) {
chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n", strerror(errno)); chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
return NULL; return NULL;
} }
if (FD_ISSET(tmp->pipe[0], &rrfs)) { if (!t) {
chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
len = 160;
} else if (pfd.revents & POLLIN) {
len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf)); len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
if (len <= 0) { if (len <= 0) {
@ -10456,25 +10452,21 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
ast_queue_frame(ch->ast, &frame); ast_queue_frame(ch->ast, &frame);
} }
} else { } else {
fd_set wrfs; struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
struct timeval tv = { 0, 0 };
int t; int t;
FD_ZERO(&wrfs); t = ast_poll(&pfd, 1, 0);
FD_SET(ch->pipe[1], &wrfs);
t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
if (!t) {
chan_misdn_log(9, bc->port, "Select Timed out\n");
break;
}
if (t < 0) { if (t < 0) {
chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno)); chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
break;
}
if (!t) {
chan_misdn_log(9, bc->port, "poll() timed out\n");
break; break;
} }
if (FD_ISSET(ch->pipe[1], &wrfs)) { if (pfd.revents & POLLOUT) {
chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len); chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) { if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno)); chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));

View File

@ -1017,12 +1017,12 @@ static void phone_check_exception(struct phone_pvt *i)
static void *do_monitor(void *data) static void *do_monitor(void *data)
{ {
fd_set rfds, efds; struct pollfd *fds = NULL;
int n, res; int nfds = 0, inuse_fds = 0, res;
struct phone_pvt *i; struct phone_pvt *i;
int tonepos = 0; int tonepos = 0;
/* The tone we're playing this round */ /* The tone we're playing this round */
struct timeval wait = {0,0}; struct timeval tv = { 0, 0 };
int dotone; int dotone;
/* This thread monitors all the frame relay interfaces which are not yet in use /* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */ (and thus do not have a separate thread) indefinitely */
@ -1036,33 +1036,38 @@ static void *do_monitor(void *data)
} }
/* Build the stuff we're going to select on, that is the socket of every /* Build the stuff we're going to select on, that is the socket of every
phone_pvt that does not have an associated owner channel */ phone_pvt that does not have an associated owner channel */
n = -1;
FD_ZERO(&rfds);
FD_ZERO(&efds);
i = iflist; i = iflist;
dotone = 0; dotone = 0;
while (i) { inuse_fds = 0;
if (FD_ISSET(i->fd, &rfds)) for (i = iflist; i; i = i->next) {
ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
if (!i->owner) { if (!i->owner) {
/* This needs to be watched, as it lacks an owner */ /* This needs to be watched, as it lacks an owner */
FD_SET(i->fd, &rfds); if (inuse_fds == nfds) {
FD_SET(i->fd, &efds); void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
if (i->fd > n) if (!tmp) {
n = i->fd; /* Avoid leaking */
continue;
}
fds = tmp;
nfds++;
}
fds[inuse_fds].fd = i->fd;
fds[inuse_fds].events = POLLIN | POLLERR;
fds[inuse_fds].revents = 0;
inuse_fds++;
if (i->dialtone && i->mode != MODE_SIGMA) { if (i->dialtone && i->mode != MODE_SIGMA) {
/* Remember we're going to have to come back and play /* Remember we're going to have to come back and play
more dialtones */ more dialtones */
if (ast_tvzero(wait)) { if (ast_tvzero(tv)) {
/* If we're due for a dialtone, play one */ /* If we're due for a dialtone, play one */
if (write(i->fd, DialTone + tonepos, 240) != 240) if (write(i->fd, DialTone + tonepos, 240) != 240) {
ast_log(LOG_WARNING, "Dial tone write error\n"); ast_log(LOG_WARNING, "Dial tone write error\n");
}
} }
dotone++; dotone++;
} }
} }
i = i->next;
} }
/* Okay, now that we know what to do, release the interface lock */ /* Okay, now that we know what to do, release the interface lock */
ast_mutex_unlock(&iflock); ast_mutex_unlock(&iflock);
@ -1071,26 +1076,28 @@ static void *do_monitor(void *data)
if (dotone && i && i->mode != MODE_SIGMA) { if (dotone && i && i->mode != MODE_SIGMA) {
/* If we're ready to recycle the time, set it to 30 ms */ /* If we're ready to recycle the time, set it to 30 ms */
tonepos += 240; tonepos += 240;
if (tonepos >= sizeof(DialTone)) if (tonepos >= sizeof(DialTone)) {
tonepos = 0; tonepos = 0;
if (ast_tvzero(wait)) {
wait = ast_tv(30000, 0);
} }
res = ast_select(n + 1, &rfds, NULL, &efds, &wait); if (ast_tvzero(tv)) {
tv = ast_tv(0, 30000);
}
res = ast_poll2(fds, inuse_fds, &tv);
} else { } else {
res = ast_select(n + 1, &rfds, NULL, &efds, NULL); res = ast_poll(fds, inuse_fds, -1);
wait = ast_tv(0,0); tv = ast_tv(0, 0);
tonepos = 0; tonepos = 0;
} }
/* Okay, select has finished. Let's see what happened. */ /* Okay, select has finished. Let's see what happened. */
if (res < 0) { if (res < 0) {
ast_debug(1, "select return %d: %s\n", res, strerror(errno)); ast_debug(1, "poll returned %d: %s\n", res, strerror(errno));
continue; continue;
} }
/* If there are no fd's changed, just continue, it's probably time /* If there are no fd's changed, just continue, it's probably time
to play some more dialtones */ to play some more dialtones */
if (!res) if (!res) {
continue; continue;
}
/* Alright, lock the interface list again, and let's look and see what has /* Alright, lock the interface list again, and let's look and see what has
happened */ happened */
if (ast_mutex_lock(&iflock)) { if (ast_mutex_lock(&iflock)) {
@ -1098,15 +1105,27 @@ static void *do_monitor(void *data)
continue; continue;
} }
i = iflist; for (i = iflist; i; i = i->next) {
for(; i; i=i->next) { int j;
if (FD_ISSET(i->fd, &rfds)) { /* Find the record */
for (j = 0; j < inuse_fds; j++) {
if (fds[j].fd == i->fd) {
break;
}
}
/* Not found? */
if (j == inuse_fds) {
continue;
}
if (fds[j].revents & POLLIN) {
if (i->owner) { if (i->owner) {
continue; continue;
} }
phone_mini_packet(i); phone_mini_packet(i);
} }
if (FD_ISSET(i->fd, &efds)) { if (fds[j].revents & POLLERR) {
if (i->owner) { if (i->owner) {
continue; continue;
} }
@ -1116,7 +1135,6 @@ static void *do_monitor(void *data)
ast_mutex_unlock(&iflock); ast_mutex_unlock(&iflock);
} }
return NULL; return NULL;
} }
static int restart_monitor() static int restart_monitor()

View File

@ -1119,8 +1119,7 @@ static void *hidthread(void *arg)
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct usb_dev_handle *usb_handle; struct usb_dev_handle *usb_handle;
struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg; struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
struct timeval to; struct pollfd pfd = { .events = POLLIN };
fd_set rfds;
usb_dev = hid_device_init(o->devstr); usb_dev = hid_device_init(o->devstr);
if (usb_dev == NULL) { if (usb_dev == NULL) {
@ -1156,63 +1155,49 @@ static void *hidthread(void *arg)
traceusb1(("hidthread: Starting normally on %s!!\n",o->name)); traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
lastrx = 0; lastrx = 0;
// popen // popen
while(!o->stophid) while (!o->stophid) {
{ pfd.fd = o->pttkick;
to.tv_sec = 0; pfd.revents = 0;
to.tv_usec = 50000; // maw sph
FD_ZERO(&rfds); res = ast_poll2(&pfd, 1, 50);
FD_SET(o->pttkick[0],&rfds);
/* ast_select emulates linux behaviour in terms of timeout handling */
res = ast_select(o->pttkick[0] + 1, &rfds, NULL, NULL, &to);
if (res < 0) { if (res < 0) {
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno)); ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
usleep(10000); usleep(10000);
continue; continue;
} }
if (FD_ISSET(o->pttkick[0],&rfds)) if (pfd.revents & POLLIN) { {
{
char c; char c;
if (read(o->pttkick[0],&c,1) < 0) { if (read(o->pttkick[0], &c, 1) < 0) {
ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno)); ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
} }
} }
if(o->wanteeprom) if (o->wanteeprom) {
{
ast_mutex_lock(&o->eepromlock); ast_mutex_lock(&o->eepromlock);
if (o->eepromctl == 1) /* to read */ if (o->eepromctl == 1) { /* to read */
{
/* if CS okay */ /* if CS okay */
if (!get_eeprom(usb_handle,o->eeprom)) if (!get_eeprom(usb_handle, o->eeprom)) {
{ if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
{ } else {
ast_log(LOG_NOTICE,"UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n",o->name);
}
else
{
o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET]; o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
o->txmixaset = o->eeprom[EEPROM_TXMIXASET]; o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
o->txmixbset = o->eeprom[EEPROM_TXMIXBSET]; o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
memcpy(&o->rxvoiceadj,&o->eeprom[EEPROM_RXVOICEADJ],sizeof(float)); memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
memcpy(&o->rxctcssadj,&o->eeprom[EEPROM_RXCTCSSADJ],sizeof(float)); memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ]; o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ]; o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name); ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
} }
} } else {
else ast_log(LOG_NOTICE, "USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n", o->name);
{
ast_log(LOG_NOTICE,"USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n",o->name);
} }
hid_set_outputs(usb_handle,bufsave); hid_set_outputs(usb_handle,bufsave);
} }
if (o->eepromctl == 2) /* to write */ if (o->eepromctl == 2) { /* to write */
{
put_eeprom(usb_handle,o->eeprom); put_eeprom(usb_handle,o->eeprom);
hid_set_outputs(usb_handle,bufsave); hid_set_outputs(usb_handle,bufsave);
ast_log(LOG_NOTICE,"USB Parameters written to EEPROM on %s\n",o->name); ast_log(LOG_NOTICE, "USB Parameters written to EEPROM on %s\n", o->name);
} }
o->eepromctl = 0; o->eepromctl = 0;
ast_mutex_unlock(&o->eepromlock); ast_mutex_unlock(&o->eepromlock);
@ -1220,38 +1205,43 @@ static void *hidthread(void *arg)
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
hid_get_inputs(usb_handle,buf); hid_get_inputs(usb_handle,buf);
keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor); keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
if (keyed != o->rxhidsq) if (keyed != o->rxhidsq) {
{ if (o->debuglevel) {
if(o->debuglevel)printf("chan_usbradio() hidthread: update rxhidsq = %d\n",keyed); printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
}
o->rxhidsq=keyed; o->rxhidsq=keyed;
} }
/* if change in tx state as controlled by xpmr */ /* if change in tx state as controlled by xpmr */
txtmp=o->pmrChan->txPttOut; txtmp = o->pmrChan->txPttOut;
if (o->lasttx != txtmp) if (o->lasttx != txtmp) {
{ o->pmrChan->txPttHid = o->lasttx = txtmp;
o->pmrChan->txPttHid=o->lasttx = txtmp; if (o->debuglevel) {
if(o->debuglevel)printf("hidthread: tx set to %d\n",txtmp); ast_debug(0, "hidthread: tx set to %d\n", txtmp);
buf[o->hid_gpio_loc] = 0;
if (!o->invertptt)
{
if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
} }
else buf[o->hid_gpio_loc] = 0;
{ if (!o->invertptt) {
if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt; if (txtmp) {
buf[o->hid_gpio_loc] = o->hid_io_ptt;
}
} else {
if (!txtmp) {
buf[o->hid_gpio_loc] = o->hid_io_ptt;
}
} }
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
memcpy(bufsave,buf,sizeof(buf)); memcpy(bufsave, buf, sizeof(buf));
hid_set_outputs(usb_handle,buf); hid_set_outputs(usb_handle, buf);
} }
time(&o->lasthidtime); time(&o->lasthidtime);
} }
buf[o->hid_gpio_loc] = 0; buf[o->hid_gpio_loc] = 0;
if (o->invertptt) buf[o->hid_gpio_loc] = o->hid_io_ptt; if (o->invertptt) {
buf[o->hid_gpio_loc] = o->hid_io_ptt;
}
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl; buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
hid_set_outputs(usb_handle,buf); hid_set_outputs(usb_handle, buf);
pthread_exit(0); pthread_exit(0);
} }
@ -1452,37 +1442,29 @@ static void *sound_thread(void *arg)
*/ */
read(o->sounddev, ign, sizeof(ign)); read(o->sounddev, ign, sizeof(ign));
for (;;) { for (;;) {
fd_set rfds, wfds; struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
int maxfd, res; int res;
FD_ZERO(&rfds); if (o->cursound > -1 && o->sounddev < 0) {
FD_ZERO(&wfds);
FD_SET(o->sndcmd[0], &rfds);
maxfd = o->sndcmd[0]; /* pipe from the main process */
if (o->cursound > -1 && o->sounddev < 0)
setformat(o, O_RDWR); /* need the channel, try to reopen */ setformat(o, O_RDWR); /* need the channel, try to reopen */
else if (o->cursound == -1 && o->owner == NULL) } else if (o->cursound == -1 && o->owner == NULL) {
{
setformat(o, O_CLOSE); /* can close */ setformat(o, O_CLOSE); /* can close */
} }
if (o->sounddev > -1) { if (o->sounddev > -1) {
if (!o->owner) { /* no one owns the audio, so we must drain it */ if (!o->owner) { /* no one owns the audio, so we must drain it */
FD_SET(o->sounddev, &rfds); pfd[1].events = POLLIN;
maxfd = MAX(o->sounddev, maxfd);
} }
if (o->cursound > -1) { if (o->cursound > -1) {
FD_SET(o->sounddev, &wfds); pfd[1].events |= POLLOUT;
maxfd = MAX(o->sounddev, maxfd);
} }
} }
/* ast_select emulates linux behaviour in terms of timeout handling */ res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -1);
res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
if (res < 1) { if (res < 1) {
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno)); ast_log(LOG_WARNING, "poll failed: %s\n", strerror(errno));
sleep(1); sleep(1);
continue; continue;
} }
if (FD_ISSET(o->sndcmd[0], &rfds)) { if (pfd[0].revents & POLLIN) {
/* read which sound to play from the pipe */ /* read which sound to play from the pipe */
int i, what = -1; int i, what = -1;
@ -1495,14 +1477,17 @@ static void *sound_thread(void *arg)
break; break;
} }
} }
if (sounds[i].ind == -1) if (sounds[i].ind == -1) {
ast_log(LOG_WARNING, "invalid sound index: %d\n", what); ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
}
} }
if (o->sounddev > -1) { if (o->sounddev > -1) {
if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */ if (pfd[1].revents & POLLIN) { /* read and ignore errors */
read(o->sounddev, ign, sizeof(ign)); read(o->sounddev, ign, sizeof(ign));
if (FD_ISSET(o->sounddev, &wfds)) }
if (pfd[1].revents & POLLOUT) {
send_sound(o); send_sound(o);
}
} }
} }
return NULL; /* Never reached */ return NULL; /* Never reached */

View File

@ -234,34 +234,34 @@ struct video_out_desc {
* and contain all configurtion info. * and contain all configurtion info.
*/ */
struct video_desc { struct video_desc {
char codec_name[64]; /* the codec we use */ char codec_name[64]; /* the codec we use */
int stayopen; /* set if gui starts manually */ int stayopen; /* set if gui starts manually */
pthread_t vthread; /* video thread */ pthread_t vthread; /* video thread */
ast_mutex_t dec_lock; /* sync decoder and video thread */ ast_mutex_t dec_lock; /* sync decoder and video thread */
int shutdown; /* set to shutdown vthread */ int shutdown; /* set to shutdown vthread */
struct ast_channel *owner; /* owner channel */ struct ast_channel *owner; /* owner channel */
struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */ struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */
char keypad_file[256]; /* image for the keypad */ char keypad_file[256]; /* image for the keypad */
char keypad_font[256]; /* font for the keypad */ char keypad_font[256]; /* font for the keypad */
char sdl_videodriver[256]; char sdl_videodriver[256];
struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */ struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */ struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
/* geometry of the thumbnails for all video sources. */ /* geometry of the thumbnails for all video sources. */
struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */ struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
int frame_freeze; /* flag to freeze the incoming frame */ int frame_freeze; /* flag to freeze the incoming frame */
/* local information for grabbers, codecs, gui */ /* local information for grabbers, codecs, gui */
struct gui_info *gui; struct gui_info *gui;
struct video_dec_desc *in; /* remote video descriptor */ struct video_dec_desc *in; /* remote video descriptor */
struct video_out_desc out; /* local video descriptor */ struct video_out_desc out; /* local video descriptor */
}; };
static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p); static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
@ -387,8 +387,9 @@ static struct fbuf_t *grabber_read(struct video_device *dev, int fps)
*/ */
static void grabber_move(struct video_device *dev, int dx, int dy) static void grabber_move(struct video_device *dev, int dx, int dy)
{ {
if (dev->grabber && dev->grabber->move) if (dev->grabber && dev->grabber->move) {
dev->grabber->move(dev->grabber_data, dx, dy); dev->grabber->move(dev->grabber_data, dx, dy);
}
} }
/* /*
@ -508,33 +509,32 @@ static int video_out_init(struct video_desc *env)
/* now setup the parameters for the encoder. /* now setup the parameters for the encoder.
* XXX should be codec-specific * XXX should be codec-specific
*/ */
{ {
AVCodecContext *enc_ctx = avcodec_alloc_context(); AVCodecContext *enc_ctx = avcodec_alloc_context();
v->enc_ctx = enc_ctx; v->enc_ctx = enc_ctx;
enc_ctx->pix_fmt = enc_in->pix_fmt; enc_ctx->pix_fmt = enc_in->pix_fmt;
enc_ctx->width = enc_in->w; enc_ctx->width = enc_in->w;
enc_ctx->height = enc_in->h; enc_ctx->height = enc_in->h;
/* XXX rtp_callback ? /* XXX rtp_callback ?
* rtp_mode so ffmpeg inserts as many start codes as possible. * rtp_mode so ffmpeg inserts as many start codes as possible.
*/ */
enc_ctx->rtp_mode = 1; enc_ctx->rtp_mode = 1;
enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2 enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
enc_ctx->bit_rate = v->bitrate; enc_ctx->bit_rate = v->bitrate;
enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2; enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
enc_ctx->qmin = v->qmin; /* should be configured */ enc_ctx->qmin = v->qmin; /* should be configured */
enc_ctx->time_base = (AVRational){1, v->fps}; enc_ctx->time_base = (AVRational){1, v->fps};
enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
v->enc->enc_init(v->enc_ctx); v->enc->enc_init(v->enc_ctx);
if (avcodec_open(enc_ctx, v->codec) < 0) { if (avcodec_open(enc_ctx, v->codec) < 0) {
ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", codec);
codec); av_free(enc_ctx);
av_free(enc_ctx); v->enc_ctx = NULL;
v->enc_ctx = NULL; return video_out_uninit(env);
return video_out_uninit(env); }
} }
}
/* /*
* Allocate enough for the encoded bitstream. As we are compressing, * Allocate enough for the encoded bitstream. As we are compressing,
* we hope that the output is never larger than the input size. * we hope that the output is never larger than the input size.
@ -637,9 +637,9 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
p_in = fill_pict(in, &my_p_in); p_in = fill_pict(in, &my_p_in);
if (p_out == NULL) if (p_out == NULL)
p_out = fill_pict(out, &my_p_out); p_out = fill_pict(out, &my_p_out);
/*if win_w is different from zero then we must change /*if win_w is different from zero then we must change
the size of the scaled buffer (the position is already the size of the scaled buffer (the position is already
encoded into the out parameter)*/ encoded into the out parameter)*/
if (out->win_w) { /* picture in picture enabled */ if (out->win_w) { /* picture in picture enabled */
eff_w=out->win_w; eff_w=out->win_w;
@ -650,26 +650,26 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
img_convert(p_out, out->pix_fmt, img_convert(p_out, out->pix_fmt,
p_in, in->pix_fmt, in->w, in->h); p_in, in->pix_fmt, in->w, in->h);
#else /* XXX replacement */ #else /* XXX replacement */
{ {
struct SwsContext *convert_ctx; struct SwsContext *convert_ctx;
convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
eff_w, eff_h, out->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
if (convert_ctx == NULL) {
ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
return;
}
if (0)
ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
sws_scale(convert_ctx,
p_in->data, p_in->linesize,
in->w, in->h, /* src slice */
p_out->data, p_out->linesize);
sws_freeContext(convert_ctx); convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
} eff_w, eff_h, out->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
if (convert_ctx == NULL) {
ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
return;
}
if (0)
ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
sws_scale(convert_ctx,
p_in->data, p_in->linesize,
in->w, in->h, /* src slice */
p_out->data, p_out->linesize);
sws_freeContext(convert_ctx);
}
#endif /* XXX replacement */ #endif /* XXX replacement */
} }
@ -873,18 +873,20 @@ static void *video_thread(void *arg)
} }
} }
sdl_setup(env); sdl_setup(env);
if (!ast_strlen_zero(save_display)) if (!ast_strlen_zero(save_display)) {
setenv("DISPLAY", save_display, 1); setenv("DISPLAY", save_display, 1);
}
ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */ ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */
if (grabber_open(&env->out)) { if (grabber_open(&env->out)) {
ast_log(LOG_WARNING, "cannot open local video source\n"); ast_log(LOG_WARNING, "cannot open local video source\n");
} }
if (env->out.device_num) if (env->out.device_num) {
env->out.devices[env->out.device_primary].status_index |= IS_PRIMARY | IS_SECONDARY; env->out.devices[env->out.device_primary].status_index |= IS_PRIMARY | IS_SECONDARY;
}
/* even if no device is connected, we must call video_out_init, /* even if no device is connected, we must call video_out_init,
* as some of the data structures it initializes are * as some of the data structures it initializes are
* used in get_video_frames() * used in get_video_frames()
@ -893,14 +895,14 @@ static void *video_thread(void *arg)
/* Writes intial status of the sources. */ /* Writes intial status of the sources. */
if (env->gui) { if (env->gui) {
for (i = 0; i < env->out.device_num; i++) { for (i = 0; i < env->out.device_num; i++) {
print_message(env->gui->thumb_bd_array[i].board, print_message(env->gui->thumb_bd_array[i].board,
src_msgs[env->out.devices[i].status_index]); src_msgs[env->out.devices[i].status_index]);
} }
} }
for (;;) { for (;;) {
struct timeval t = { 0, 50000 }; /* XXX 20 times/sec */ struct timespec t = { 0, 50000000 }; /* XXX 20 times/sec */
struct ast_frame *p, *f; struct ast_frame *p, *f;
struct ast_channel *chan; struct ast_channel *chan;
int fd; int fd;
@ -908,13 +910,14 @@ static void *video_thread(void *arg)
/* determine if video format changed */ /* determine if video format changed */
if (count++ % 10 == 0) { if (count++ % 10 == 0) {
if (env->out.sendvideo && env->out.devices) if (env->out.sendvideo && env->out.devices) {
sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps", snprintf(buf, sizeof(buf), "%s %s %dx%d @@ %dfps %dkbps",
env->out.devices[env->out.device_primary].name, env->codec_name, env->out.devices[env->out.device_primary].name, env->codec_name,
env->enc_in.w, env->enc_in.h, env->enc_in.w, env->enc_in.h,
env->out.fps, env->out.bitrate/1000); env->out.fps, env->out.bitrate / 1000);
else } else {
sprintf(buf, "hold"); sprintf(buf, "hold");
}
caption = buf; caption = buf;
} }
@ -923,36 +926,36 @@ static void *video_thread(void *arg)
* otherwise the drag will not work */ * otherwise the drag will not work */
if (env->gui) if (env->gui)
eventhandler(env, caption); eventhandler(env, caption);
/* sleep for a while */ /* sleep for a while */
ast_select(0, NULL, NULL, NULL, &t); nanosleep(&t, NULL);
if (env->in) { if (env->in) {
struct video_dec_desc *v = env->in; struct video_dec_desc *v = env->in;
/*
* While there is something to display, call the decoder and free
* the buffer, possibly enabling the receiver to store new data.
*/
while (v->dec_in_dpy) {
struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
/* decode the frame, but show it only if not frozen */ /*
if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze) * While there is something to display, call the decoder and free
show_frame(env, WIN_REMOTE); * the buffer, possibly enabling the receiver to store new data.
tmp->used = 0; /* mark buffer as free */ */
tmp->ebit = 0; while (v->dec_in_dpy) {
ast_mutex_lock(&env->dec_lock); struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
v->dec_in_dpy = &v->dec_in[0];
if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */ /* decode the frame, but show it only if not frozen */
v->dec_in_cur = tmp; /* using the slot just freed */ if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze)
else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */ show_frame(env, WIN_REMOTE);
v->dec_in_dpy = NULL; /* nothing more to display */ tmp->used = 0; /* mark buffer as free */
ast_mutex_unlock(&env->dec_lock); tmp->ebit = 0;
ast_mutex_lock(&env->dec_lock);
if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
v->dec_in_dpy = &v->dec_in[0];
if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */
v->dec_in_cur = tmp; /* using the slot just freed */
else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
v->dec_in_dpy = NULL; /* nothing more to display */
ast_mutex_unlock(&env->dec_lock);
}
} }
}
if (env->shutdown) if (env->shutdown)
break; break;
@ -988,7 +991,7 @@ static void *video_thread(void *arg)
for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) { for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
if (write(fd, &blah, l) != l) if (write(fd, &blah, l) != l)
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n", ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
chan->name, f->frametype, f->subclass, strerror(errno)); chan->name, f->frametype, f->subclass, strerror(errno));
} }
} }
ast_channel_unlock(chan); ast_channel_unlock(chan);
@ -1194,13 +1197,13 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
if (env == NULL) if (env == NULL)
return 1; /* unrecognised */ return 1; /* unrecognised */
if (!strcasecmp(var, "videodevice")) { if (!strcasecmp(var, "videodevice")) {
ast_cli(fd, "videodevice is [%s]\n", env->out.devices[env->out.device_primary].name); ast_cli(fd, "videodevice is [%s]\n", env->out.devices[env->out.device_primary].name);
} else if (!strcasecmp(var, "videocodec")) { } else if (!strcasecmp(var, "videocodec")) {
ast_cli(fd, "videocodec is [%s]\n", env->codec_name); ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
} else if (!strcasecmp(var, "sendvideo")) { } else if (!strcasecmp(var, "sendvideo")) {
ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off"); ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
} else if (!strcasecmp(var, "video_size")) { } else if (!strcasecmp(var, "video_size")) {
int in_w = 0, in_h = 0; int in_w = 0, in_h = 0;
if (env->in) { if (env->in) {
in_w = env->in->dec_out.w; in_w = env->in->dec_out.w;
@ -1212,22 +1215,22 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
env->loc_dpy.w, env->loc_dpy.h, env->loc_dpy.w, env->loc_dpy.h,
env->rem_dpy.w, env->rem_dpy.h, env->rem_dpy.w, env->rem_dpy.h,
in_w, in_h); in_w, in_h);
} else if (!strcasecmp(var, "bitrate")) { } else if (!strcasecmp(var, "bitrate")) {
ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate); ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
} else if (!strcasecmp(var, "qmin")) { } else if (!strcasecmp(var, "qmin")) {
ast_cli(fd, "qmin is [%d]\n", env->out.qmin); ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
} else if (!strcasecmp(var, "fps")) { } else if (!strcasecmp(var, "fps")) {
ast_cli(fd, "fps is [%d]\n", env->out.fps); ast_cli(fd, "fps is [%d]\n", env->out.fps);
} else if (!strcasecmp(var, "startgui")) { } else if (!strcasecmp(var, "startgui")) {
env->stayopen = 1; env->stayopen = 1;
console_video_start(env, NULL); console_video_start(env, NULL);
} else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) { } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
env->stayopen = 0; env->stayopen = 0;
if (env->gui && env->owner) if (env->gui && env->owner)
ast_cli_command(-1, "console hangup"); ast_cli_command(-1, "console hangup");
else /* not in a call */ else /* not in a call */
console_video_uninit(env); console_video_uninit(env);
} else { } else {
return 1; /* unrecognised */ return 1; /* unrecognised */
} }
return 0; /* recognised */ return 0; /* recognised */

38808
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,7 @@ case "${host_os}" in
;; ;;
darwin*) darwin*)
AC_DEFINE([AST_POLL_COMPAT], 1, [Define to 1 if internal poll should be used.]) AC_DEFINE([AST_POLL_COMPAT], 1, [Define to 1 if internal poll should be used.])
AC_DEFINE([_DARWIN_UNLIMITED_SELECT], 1, [Define to 1 if running on Darwin.])
;; ;;
*) *)
AC_PREFIX_DEFAULT([/usr]) AC_PREFIX_DEFAULT([/usr])
@ -466,7 +467,7 @@ AC_FUNC_STRNLEN
AC_FUNC_STRTOD AC_FUNC_STRTOD
AC_FUNC_UTIME_NULL AC_FUNC_UTIME_NULL
AC_FUNC_VPRINTF AC_FUNC_VPRINTF
AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap ntohll newlocale putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl]) AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii memchr memmove memset mkdir munmap ntohll newlocale ppoll putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl])
# NOTE: we use AC_CHECK_LIB to get -lm into the arguments for later checks, # NOTE: we use AC_CHECK_LIB to get -lm into the arguments for later checks,
# so that AC_CHECK_FUNCS can detect functions in that library. # so that AC_CHECK_FUNCS can detect functions in that library.
@ -741,6 +742,48 @@ AC_RUN_IFELSE(
AC_MSG_RESULT(unknown) AC_MSG_RESULT(unknown)
) )
AC_MSG_CHECKING(if we can increase the maximum select-able file descriptor)
AC_RUN_IFELSE(
AC_LANG_PROGRAM([
#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
], [[
struct rlimit rlim = { FD_SETSIZE * 2, FD_SETSIZE * 2 };
int fd0, fd1;
struct timeval tv = { 0, };
struct ast_fdset { long fds_bits[[1024]]; } fds = { { 0, } };
if (setrlimit(RLIMIT_NOFILE, &rlim)) { exit(1); }
if ((fd0 = open("/dev/null", O_RDONLY)) < 0) { exit(1); }
if (dup2(fd0, (fd1 = FD_SETSIZE + 1)) < 0) { exit(1); }
FD_SET(fd0, (fd_set *) &fds);
FD_SET(fd1, (fd_set *) &fds);
if (select(FD_SETSIZE + 2, (fd_set *) &fds, NULL, NULL, &tv) < 0) { exit(1); }
exit(0)]]),
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_VARIABLE_FDSET], 1, [Define to 1 if your system can support larger than default select bitmasks.]),
AC_MSG_RESULT(no),
AC_MSG_RESULT(cross-compile)
)
if test "${ac_cv_have_variable_fdset}x" = "0x"; then
AC_RUN_IFELSE(
AC_LANG_PROGRAM([
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
], [if (getuid() != 0) { exit(1); }]),
AC_DEFINE([CONFIGURE_RAN_AS_ROOT], 1, [Some configure tests will unexpectedly fail if configure is run by a non-root user. These may be able to be tested at runtime.]))
fi
AST_GCC_ATTRIBUTE(pure) AST_GCC_ATTRIBUTE(pure)
AST_GCC_ATTRIBUTE(malloc) AST_GCC_ATTRIBUTE(malloc)
AST_GCC_ATTRIBUTE(const) AST_GCC_ATTRIBUTE(const)

View File

@ -17,6 +17,10 @@
/* Define to 1 if the `closedir' function returns void instead of `int'. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID #undef CLOSEDIR_VOID
/* Some configure tests will unexpectedly fail if configure is run by a
non-root user. These may be able to be tested at runtime. */
#undef CONFIGURE_RAN_AS_ROOT
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems. systems. This function is required for `alloca.c' support on those systems.
*/ */
@ -381,9 +385,6 @@
/* Define to 1 if your system defines the locale_t type in xlocale.h */ /* Define to 1 if your system defines the locale_t type in xlocale.h */
#undef HAVE_LOCALE_T_IN_XLOCALE_H #undef HAVE_LOCALE_T_IN_XLOCALE_H
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define to 1 if you have the `log' function. */ /* Define to 1 if you have the `log' function. */
#undef HAVE_LOG #undef HAVE_LOG
@ -538,6 +539,9 @@
/* Define to 1 if you have the `powl' function. */ /* Define to 1 if you have the `powl' function. */
#undef HAVE_POWL #undef HAVE_POWL
/* Define to 1 if you have the `ppoll' function. */
#undef HAVE_PPOLL
/* Define to 1 if you have the ISDN PRI library. */ /* Define to 1 if you have the ISDN PRI library. */
#undef HAVE_PRI #undef HAVE_PRI
@ -803,7 +807,7 @@
/* Define to 1 if you have the `strtoq' function. */ /* Define to 1 if you have the `strtoq' function. */
#undef HAVE_STRTOQ #undef HAVE_STRTOQ
/* Define to 1 if `st_blksize' is a member of `struct stat'. */ /* Define to 1 if `st_blksize' is member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE #undef HAVE_STRUCT_STAT_ST_BLKSIZE
/* Define to 1 if you have the mISDN Supplemental Services library. */ /* Define to 1 if you have the mISDN Supplemental Services library. */
@ -956,6 +960,10 @@
/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ /* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
#undef HAVE_UTIME_NULL #undef HAVE_UTIME_NULL
/* Define to 1 if your system can support larger than default select bitmasks.
*/
#undef HAVE_VARIABLE_FDSET
/* Define to 1 if you have the `vasprintf' function. */ /* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF #undef HAVE_VASPRINTF
@ -1074,12 +1082,12 @@
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME #undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */ /* Define to the version of this package. */
#undef PACKAGE_VERSION #undef PACKAGE_VERSION
/* Define to 1 if the C compiler supports function prototypes. */
#undef PROTOTYPES
/* Define to necessary symbol if this constant uses a non-standard name on /* Define to necessary symbol if this constant uses a non-standard name on
your system. */ your system. */
#undef PTHREAD_CREATE_JOINABLE #undef PTHREAD_CREATE_JOINABLE
@ -1099,6 +1107,11 @@
/* Define to the type of arg 5 for `select'. */ /* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5 #undef SELECT_TYPE_ARG5
/* Define to 1 if the `setvbuf' function takes the buffering type as its
second argument and the buffer pointer as the third, as on System V before
release 3. */
#undef SETVBUF_REVERSED
/* The size of `char *', as computed by sizeof. */ /* The size of `char *', as computed by sizeof. */
#undef SIZEOF_CHAR_P #undef SIZEOF_CHAR_P
@ -1128,30 +1141,23 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */ /* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME #undef TM_IN_SYS_TIME
/* Enable extensions on AIX 3, Interix. */ /* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE #ifndef _ALL_SOURCE
# undef _ALL_SOURCE # undef _ALL_SOURCE
#endif #endif
/* Define to 1 if running on Darwin. */
#undef _DARWIN_UNLIMITED_SELECT
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Enable GNU extensions on systems that have them. */ /* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
# undef _GNU_SOURCE # undef _GNU_SOURCE
#endif #endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
#undef _LARGEFILE_SOURCE #undef _LARGEFILE_SOURCE
@ -1169,6 +1175,20 @@
/* Define to 1 if you need to in order for `stat' and other things to work. */ /* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE #undef _POSIX_SOURCE
/* Enable extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Define like PROTOTYPES; this can be used by system headers. */
#undef __PROTOTYPES
/* Define to empty if `const' does not conform to ANSI C. */ /* Define to empty if `const' does not conform to ANSI C. */
#undef const #undef const

View File

@ -2232,44 +2232,6 @@ static inline void timersub(struct timeval *tvend, struct timeval *tvstart, stru
} }
#endif #endif
/*!
* \brief Waits for activity on a group of channels
* \param nfds the maximum number of file descriptors in the sets
* \param rfds file descriptors to check for read availability
* \param wfds file descriptors to check for write availability
* \param efds file descriptors to check for exceptions (OOB data)
* \param tvp timeout while waiting for events
* \details
* This is the same as a standard select(), except it guarantees the
* behaviour where the passed struct timeval is updated with how much
* time was not slept while waiting for the specified events
*/
static inline int ast_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tvp)
{
#ifdef __linux__
return select(nfds, rfds, wfds, efds, tvp);
#else
if (tvp) {
struct timeval tv, tvstart, tvend, tvlen;
int res;
tv = *tvp;
gettimeofday(&tvstart, NULL);
res = select(nfds, rfds, wfds, efds, tvp);
gettimeofday(&tvend, NULL);
timersub(&tvend, &tvstart, &tvlen);
timersub(&tv, &tvlen, tvp);
if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
tvp->tv_sec = 0;
tvp->tv_usec = 0;
}
return res;
}
else
return select(nfds, rfds, wfds, efds, NULL);
#endif
}
/*! \brief Retrieves the current T38 state of a channel */ /*! \brief Retrieves the current T38 state of a channel */
static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan) static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
{ {

View File

@ -79,6 +79,8 @@
#ifndef __AST_POLL_COMPAT_H #ifndef __AST_POLL_COMPAT_H
#define __AST_POLL_COMPAT_H #define __AST_POLL_COMPAT_H
#include "asterisk/select.h"
#ifndef AST_POLL_COMPAT #ifndef AST_POLL_COMPAT
#include <sys/poll.h> #include <sys/poll.h>
@ -114,4 +116,24 @@ int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout);
#endif /* AST_POLL_COMPAT */ #endif /* AST_POLL_COMPAT */
/*!
* \brief Same as poll(2), except the time is specified in microseconds and
* the tv argument is modified to indicate the time remaining.
*/
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv);
/*!
* \brief Shortcut for conversion of FD_ISSET to poll(2)-based
*/
static inline int ast_poll_fd_index(struct pollfd *haystack, int nfds, int needle)
{
int i;
for (i = 0; i < nfds; i++) {
if (haystack[i].fd == needle) {
return i;
}
}
return -1;
}
#endif /* __AST_POLL_COMPAT_H */ #endif /* __AST_POLL_COMPAT_H */

110
include/asterisk/select.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2010, Digium, Inc.
*
* Tilghman Lesher <tlesher AT digium DOT com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!\file
* \brief Bitfield expansions for ast_select
*/
#ifndef __AST_SELECT_H
#define __AST_SELECT_H
#include <sys/select.h>
#include <errno.h>
#include "asterisk/utils.h"
#ifdef __cplusplus
extern "C" {
#endif
extern unsigned int ast_FD_SETSIZE;
#if !defined(HAVE_VARIABLE_FDSET) && defined(CONFIGURE_RAN_AS_ROOT)
#define ast_fdset fd_set
#else
typedef struct {
long fds_bits[4096 / sizeof(long)]; /* 32768 bits */
} ast_fdset;
#undef FD_ZERO
#define FD_ZERO(a) \
do { \
long *bytes = (long *) a; \
int i; \
for (i = 0; i < sizeof(*(a)) / sizeof(long); i++) { \
bytes[i] = 0; \
} \
} while (0)
#undef FD_SET
#define FD_SET(fd, fds) \
do { \
long *bytes = (long *) fds; \
if (fd / sizeof(*bytes) + ((fd + 1) % sizeof(*bytes) ? 1 : 0) < sizeof(*(fds))) { \
bytes[fd / (sizeof(*bytes))] |= 1L << (fd % sizeof(*bytes)); \
} else { \
ast_log(LOG_ERROR, "FD %d exceeds the maximum size of ast_fdset!\n", fd); \
} \
} while (0)
#endif /* HAVE_VARIABLE_FDSET */
/*! \brief Waits for activity on a group of channels
* \param nfds the maximum number of file descriptors in the sets
* \param rfds file descriptors to check for read availability
* \param wfds file descriptors to check for write availability
* \param efds file descriptors to check for exceptions (OOB data)
* \param tvp timeout while waiting for events
* This is the same as a standard select(), except it guarantees the
* behaviour where the passed struct timeval is updated with how much
* time was not slept while waiting for the specified events
*/
static inline int ast_select(int nfds, ast_fdset *rfds, ast_fdset *wfds, ast_fdset *efds, struct timeval *tvp)
{
#ifdef __linux__
ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
#else
int save_errno = 0;
ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
if (tvp) {
struct timeval tv, tvstart, tvend, tvlen;
int res;
tv = *tvp;
gettimeofday(&tvstart, NULL);
res = select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
save_errno = errno;
gettimeofday(&tvend, NULL);
timersub(&tvend, &tvstart, &tvlen);
timersub(&tv, &tvlen, tvp);
if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
tvp->tv_sec = 0;
tvp->tv_usec = 0;
}
errno = save_errno;
return res;
}
else
return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, NULL);
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* __AST_SELECT_H */

View File

@ -1,7 +1,7 @@
/* /*
* Asterisk -- An open source telephony toolkit. * Asterisk -- An open source telephony toolkit.
* *
* Copyright (C) 1999 - 2008, Digium, Inc. * Copyright (C) 1999 - 2010, Digium, Inc.
* *
* Mark Spencer <markster@digium.com> * Mark Spencer <markster@digium.com>
* *
@ -272,6 +272,8 @@ static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0"; static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl"; static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
extern unsigned int ast_FD_SETSIZE;
static char *_argv[256]; static char *_argv[256];
static int shuttingdown; static int shuttingdown;
static int restartnow; static int restartnow;
@ -3167,7 +3169,8 @@ int main(int argc, char *argv[])
char *buf; char *buf;
const char *runuser = NULL, *rungroup = NULL; const char *runuser = NULL, *rungroup = NULL;
char *remotesock = NULL; char *remotesock = NULL;
int moduleresult; /*!< Result from the module load subsystem */ int moduleresult; /*!< Result from the module load subsystem */
struct rlimit l;
/* Remember original args for restart */ /* Remember original args for restart */
if (argc > ARRAY_LEN(_argv) - 1) { if (argc > ARRAY_LEN(_argv) - 1) {
@ -3352,7 +3355,6 @@ int main(int argc, char *argv[])
} }
if (ast_opt_dump_core) { if (ast_opt_dump_core) {
struct rlimit l;
memset(&l, 0, sizeof(l)); memset(&l, 0, sizeof(l));
l.rlim_cur = RLIM_INFINITY; l.rlim_cur = RLIM_INFINITY;
l.rlim_max = RLIM_INFINITY; l.rlim_max = RLIM_INFINITY;
@ -3361,6 +3363,44 @@ int main(int argc, char *argv[])
} }
} }
if (getrlimit(RLIMIT_NOFILE, &l)) {
ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
}
#if !defined(CONFIGURE_RAN_AS_ROOT)
/* Check if select(2) will run with more file descriptors */
do {
int fd, fd2;
ast_fdset readers;
struct timeval tv = { 0, };
if (l.rlim_cur <= FD_SETSIZE) {
/* The limit of select()able FDs is irrelevant, because we'll never
* open one that high. */
break;
}
if (!(fd = open("/dev/null", O_RDONLY))) {
ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
break; /* XXX Should we exit() here? XXX */
}
fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
if (dup2(fd, fd2)) {
ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
break;
}
FD_ZERO(&readers);
FD_SET(fd2, &readers);
if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
}
} while (0);
#elif defined(HAVE_VARIABLE_FDSET)
ast_FD_SETSIZE = l.rlim_cur;
#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP)) if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
rungroup = ast_config_AST_RUN_GROUP; rungroup = ast_config_AST_RUN_GROUP;
if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER)) if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))

View File

@ -438,7 +438,7 @@ static const struct ast_datastore_info dial_features_info = {
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot); static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
static void parkinglot_unref(struct ast_parkinglot *parkinglot); static void parkinglot_unref(struct ast_parkinglot *parkinglot);
static void parkinglot_destroy(void *obj); static void parkinglot_destroy(void *obj);
int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max); int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *fs);
struct ast_parkinglot *find_parkinglot(const char *name); struct ast_parkinglot *find_parkinglot(const char *name);
static struct ast_parkinglot *create_parkinglot(const char *name); static struct ast_parkinglot *create_parkinglot(const char *name);
static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot); static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
@ -3603,9 +3603,10 @@ static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_
} }
/*! \brief Run management on parkinglots, called once per parkinglot */ /*! \brief Run management on parkinglots, called once per parkinglot */
int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max) int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *ms)
{ {
struct pollfd *new_fds = NULL;
int new_nfds = 0;
struct parkeduser *pu; struct parkeduser *pu;
int res = 0; int res = 0;
char parkingslot[AST_MAX_EXTENSION]; char parkingslot[AST_MAX_EXTENSION];
@ -3628,12 +3629,12 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
/* Get chan, exten from derived kludge */ /* Get chan, exten from derived kludge */
if (pu->peername[0]) { if (pu->peername[0]) {
char *peername = ast_strdupa(pu->peername); char *peername = ast_strdupa(pu->peername);
char *cp = strrchr(peername, '-'); char *dash = strrchr(peername, '-');
char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */ char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
int i; int i;
if (cp) { if (dash) {
*cp = 0; *dash = '\0';
} }
peername_flat = ast_strdupa(peername); peername_flat = ast_strdupa(peername);
@ -3712,14 +3713,33 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
} else { /* still within parking time, process descriptors */ } else { /* still within parking time, process descriptors */
for (x = 0; x < AST_MAX_FDS; x++) { for (x = 0; x < AST_MAX_FDS; x++) {
struct ast_frame *f; struct ast_frame *f;
int y;
if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) if (chan->fds[x] == -1) {
continue; /* nothing on this descriptor */
}
for (y = 0; y < *nfds; y++) {
if ((*pfds[y]).fd == chan->fds[x]) {
/* Found poll record! */
break;
}
}
if (y == *nfds) {
/* Not found */
continue; continue;
}
if (FD_ISSET(chan->fds[x], efds))
if (!((*pfds[y]).revents & (POLLIN | POLLERR))) {
/* Next x */
continue;
}
if ((*pfds[y]).revents & POLLERR) {
ast_set_flag(chan, AST_FLAG_EXCEPTION); ast_set_flag(chan, AST_FLAG_EXCEPTION);
else } else {
ast_clear_flag(chan, AST_FLAG_EXCEPTION); ast_clear_flag(chan, AST_FLAG_EXCEPTION);
}
chan->fdno = x; chan->fdno = x;
/* See if they need servicing */ /* See if they need servicing */
@ -3760,22 +3780,32 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
} }
} /* End for */ } /* End for */
if (x >= AST_MAX_FDS) { if (x >= AST_MAX_FDS) {
std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
if (chan->fds[x] > -1) { if (chan->fds[x] > -1) {
FD_SET(chan->fds[x], nrfds); void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
FD_SET(chan->fds[x], nefds); if (!tmp) {
if (chan->fds[x] > *max) continue;
*max = chan->fds[x]; }
new_fds = tmp;
new_fds[new_nfds].fd = chan->fds[x];
new_fds[new_nfds].events = POLLIN | POLLERR;
new_fds[new_nfds].revents = 0;
new_nfds++;
} }
} }
/* Keep track of our shortest wait */ /* Keep track of our shortest wait */
if (tms < *ms || *ms < 0) if (tms < *ms || *ms < 0) {
*ms = tms; *ms = tms;
}
} }
} }
} }
AST_LIST_TRAVERSE_SAFE_END; AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&curlot->parkings); AST_LIST_UNLOCK(&curlot->parkings);
ast_free(*pfds);
*pfds = new_fds;
*nfds = new_nfds;
return res; return res;
} }
@ -3789,35 +3819,26 @@ std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
*/ */
static void *do_parking_thread(void *ignore) static void *do_parking_thread(void *ignore)
{ {
fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ struct pollfd *pfds = NULL;
fd_set nrfds, nefds; /* args for the next select */ int nfds = 0;
FD_ZERO(&rfds);
FD_ZERO(&efds);
for (;;) { for (;;) {
int res = 0;
int ms = -1; /* select timeout, uninitialized */
int max = -1; /* max fd, none there yet */
struct ao2_iterator iter; struct ao2_iterator iter;
struct ast_parkinglot *curlot; struct ast_parkinglot *curlot;
FD_ZERO(&nrfds); int ms = -1; /* poll2 timeout, uninitialized */
FD_ZERO(&nefds);
iter = ao2_iterator_init(parkinglots, 0); iter = ao2_iterator_init(parkinglots, 0);
while ((curlot = ao2_iterator_next(&iter))) { while ((curlot = ao2_iterator_next(&iter))) {
res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max); manage_parkinglot(curlot, &pfds, &nfds, &ms);
ao2_ref(curlot, -1); ao2_ref(curlot, -1);
} }
ao2_iterator_destroy(&iter);
rfds = nrfds; /* Wait for something to happen */
efds = nefds; ast_poll(pfds, nfds, ms);
{
struct timeval wait = ast_samp2tv(ms, 1000);
/* Wait for something to happen */
ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
}
pthread_testcancel(); pthread_testcancel();
} }
/* If this WERE reached, we'd need to free(pfds) */
return NULL; /* Never reached */ return NULL; /* Never reached */
} }

View File

@ -10,9 +10,9 @@
struct pollfd struct pollfd
{ {
int fd; int fd;
short events; short events;
short revents; short revents;
} }
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout) int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
@ -73,54 +73,44 @@
#include "asterisk.h" #include "asterisk.h"
#include <unistd.h> /* standard Unix definitions */ #include <unistd.h> /* standard Unix definitions */
#include <sys/types.h> /* system types */ #include <sys/types.h> /* system types */
#include <sys/time.h> /* time definitions */ #include <sys/time.h> /* time definitions */
#include <assert.h> /* assertion macros */ #include <assert.h> /* assertion macros */
#include <string.h> /* string functions */ #include <string.h> /* string functions */
#include <errno.h>
#include "asterisk/utils.h" /* this package */ #include "asterisk/utils.h" /* this package */
#include "asterisk/poll-compat.h" /* this package */ #include "asterisk/poll-compat.h" /* this package */
#ifdef AST_POLL_COMPAT unsigned int ast_FD_SETSIZE = FD_SETSIZE;
#ifndef MAX #ifndef MAX
#define MAX(a,b) a > b ? a : b #define MAX(a,b) a > b ? a : b
#endif #endif
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Private Functions Private Functions
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
static int map_poll_spec #if defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL)
#if __STDC__ > 0 static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
(struct pollfd *pArray, ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
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
{ {
register unsigned long i; /* loop control */ register unsigned long i; /* loop control */
register struct pollfd *pCur; /* current array element */ register struct pollfd *pCur; /* current array element */
register int max_fd = -1; /* return value */ register int max_fd = -1; /* return value */
/*!\note /*
* Map the poll() structures into the file descriptor sets required * Map the poll() structures into the file descriptor sets required
* by select(). * by select().
*/ */
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */ /* Skip any bad FDs in the array. */
if (pCur->fd < 0) if (pCur->fd < 0) {
continue; continue;
}
if (pCur->events & POLLIN) { if (pCur->events & POLLIN) {
/* "Input Ready" notification desired. */ /* "Input Ready" notification desired. */
@ -145,34 +135,28 @@ static int map_poll_spec
return max_fd; return max_fd;
} }
static struct timeval *map_timeout #ifdef AST_POLL_COMPAT
#if __STDC__ > 0 static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
(int poll_timeout, struct timeval *pSelTimeout)
#else
(poll_timeout, pSelTimeout)
int poll_timeout;
struct timeval *pSelTimeout;
#endif
{ {
struct timeval *pResult; struct timeval *pResult;
/*!\note /*
* Map the poll() timeout value into a select() timeout. The possible Map the poll() timeout value into a select() timeout. The possible
* values of the poll() timeout value, and their meanings, are: 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); 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) { switch (poll_timeout) {
case -1: case -1:
@ -203,25 +187,13 @@ static struct timeval *map_timeout
return pResult; return pResult;
} }
#endif /* AST_POLL_COMPAT */
static void map_select_results static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
#if __STDC__ > 0 ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
(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
{ {
register unsigned long i; /* loop control */ register unsigned long i; /* loop control */
register struct pollfd *pCur; /* current array element */ register struct pollfd *pCur; /* current array element */
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) { for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */ /* Skip any bad FDs in the array. */
@ -231,59 +203,101 @@ static void map_select_results
} }
/* Exception events take priority over input events. */ /* Exception events take priority over input events. */
pCur->revents = 0; pCur->revents = 0;
if (FD_ISSET (pCur->fd, pExceptSet)) { if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
pCur->revents |= POLLPRI; pCur->revents |= POLLPRI;
} else if (FD_ISSET (pCur->fd, pReadSet)) { } else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
pCur->revents |= POLLIN; pCur->revents |= POLLIN;
} }
if (FD_ISSET (pCur->fd, pWriteSet)) { if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
pCur->revents |= POLLOUT; pCur->revents |= POLLOUT;
} }
} }
return; return;
} }
#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Public Functions Public Functions
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifdef AST_POLL_COMPAT
int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout) int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
{ {
fd_set read_descs; /* input file descs */ ast_fdset read_descs; /* input file descs */
fd_set write_descs; /* output file descs */ ast_fdset write_descs; /* output file descs */
fd_set except_descs; /* exception descs */ ast_fdset except_descs; /* exception descs */
struct timeval stime; /* select() timeout value */ struct timeval stime; /* select() timeout value */
int ready_descriptors; /* function result */ int ready_descriptors; /* function result */
int max_fd = 0; /* maximum fd value */ int max_fd = 0; /* maximum fd value */
struct timeval *pTimeout; /* actually passed */ struct timeval *pTimeout; /* actually passed */
int save_errno;
FD_ZERO (&read_descs); FD_ZERO(&read_descs);
FD_ZERO (&write_descs); FD_ZERO(&write_descs);
FD_ZERO (&except_descs); FD_ZERO(&except_descs);
/* Map the poll() file descriptor list in the select() data structures. */ /* Map the poll() file descriptor list in the select() data structures. */
if (pArray) { if (pArray) {
max_fd = map_poll_spec (pArray, n_fds, max_fd = map_poll_spec (pArray, n_fds,
&read_descs, &write_descs, &except_descs); &read_descs, &write_descs, &except_descs);
} }
/* Map the poll() timeout value in the select() timeout structure. */ /* Map the poll() timeout value in the select() timeout structure. */
pTimeout = map_timeout(timeout, &stime);
pTimeout = map_timeout (timeout, &stime);
/* Make the select() call. */ /* Make the select() call. */
ready_descriptors = select(max_fd + 1, &read_descs, &write_descs,
ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
&except_descs, pTimeout); &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)
{
#ifdef HAVE_PPOLL
struct timeval start = ast_tvnow();
struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
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) { if (ready_descriptors >= 0) {
map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs); map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
} }
return ready_descriptors; return ready_descriptors;
#endif
} }
#endif /* AST_POLL_COMPAT */

View File

@ -397,8 +397,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */ for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
/* send request, possibly wait for reply */ /* send request, possibly wait for reply */
unsigned char reply_buf[1024]; unsigned char reply_buf[1024];
fd_set rfds; struct pollfd pfds = { .fd = s, .events = POLLIN };
struct timeval to = { 3, 0 }; /* timeout, make it configurable */
struct sockaddr_in src; struct sockaddr_in src;
socklen_t srclen; socklen_t srclen;
@ -410,9 +409,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
} }
if (answer == NULL) if (answer == NULL)
break; break;
FD_ZERO(&rfds); res = ast_poll(&pfds, 1, 3000);
FD_SET(s, &rfds);
res = ast_select(s + 1, &rfds, NULL, NULL, &to);
if (res <= 0) /* timeout or error */ if (res <= 0) /* timeout or error */
continue; continue;
memset(&src, 0, sizeof(src)); memset(&src, 0, sizeof(src));

View File

@ -113,9 +113,9 @@ const char *ais_err2str(SaAisErrorT error)
static void *dispatch_thread_handler(void *data) static void *dispatch_thread_handler(void *data)
{ {
SaSelectionObjectT clm_fd, evt_fd, max_fd; SaSelectionObjectT clm_fd, evt_fd;
int res; int res;
fd_set read_fds; struct pollfd pfd[2] = { { .events = POLLIN, }, { .events = POLLIN, } };
SaAisErrorT ais_res; SaAisErrorT ais_res;
ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd); ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
@ -132,24 +132,26 @@ static void *dispatch_thread_handler(void *data)
return NULL; return NULL;
} }
max_fd = clm_fd > evt_fd ? clm_fd : evt_fd; pfd[0].fd = clm_fd;
pfd[1].fd = evt_fd;
while (!dispatch_thread.stop) { while (!dispatch_thread.stop) {
FD_ZERO(&read_fds); pfd[0].revents = 0;
FD_SET(clm_fd, &read_fds); pfd[1].revents = 0;
FD_SET(evt_fd, &read_fds);
res = ast_select(max_fd + 1, &read_fds, NULL, NULL, NULL); res = ast_poll(pfd, 2, -1);
if (res == -1 && errno != EINTR && errno != EAGAIN) { if (res == -1 && errno != EINTR && errno != EAGAIN) {
ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, " ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
"and the module will no longer operate.\n", strerror(errno)); "and the module will no longer operate.\n", strerror(errno));
break; break;
} }
if (FD_ISSET(clm_fd, &read_fds)) if (pfd[0].revents & POLLIN) {
saClmDispatch(clm_handle, SA_DISPATCH_ALL); saClmDispatch(clm_handle, SA_DISPATCH_ALL);
if (FD_ISSET(evt_fd, &read_fds)) }
if (pfd[1].revents & POLLIN) {
saEvtDispatch(evt_handle, SA_DISPATCH_ALL); saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
}
} }
return NULL; return NULL;

View File

@ -1283,38 +1283,27 @@ static int aji_tls_handshake(struct aji_client *client)
*/ */
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout) static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
{ {
int sock; struct pollfd pfd = { .events = POLLIN };
fd_set fds;
struct timeval tv, *tvptr = NULL;
int len, res; int len, res;
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
if (aji_is_secure(client)) { if (aji_is_secure(client)) {
sock = SSL_get_fd(client->ssl_session); pfd.fd = SSL_get_fd(client->ssl_session);
if (sock < 0) { if (pfd.fd < 0) {
return -1; return -1;
} }
} else } else
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
sock = iks_fd(client->p); pfd.fd = iks_fd(client->p);
memset(&tv, 0, sizeof(struct timeval)); res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
FD_ZERO(&fds);
FD_SET(sock, &fds);
tv.tv_sec = timeout;
/* NULL value for tvptr makes ast_select wait indefinitely */
tvptr = (timeout != -1) ? &tv : NULL;
/* ast_select emulates linux behaviour in terms of timeout handling */
res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
if (res > 0) { if (res > 0) {
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
if (aji_is_secure(client)) { if (aji_is_secure(client)) {
len = SSL_read(client->ssl_session, buffer, buf_len); len = SSL_read(client->ssl_session, buffer, buf_len);
} else } else
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
len = recv(sock, buffer, buf_len, 0); len = recv(pfd.fd, buffer, buf_len, 0);
if (len > 0) { if (len > 0) {
return len; return len;

View File

@ -703,9 +703,8 @@ static void *do_pktccops(void *data)
int res, nfds, len; int res, nfds, len;
struct copsmsg *recmsg, *sendmsg; struct copsmsg *recmsg, *sendmsg;
struct copsmsg recmsgb, sendmsgb; struct copsmsg recmsgb, sendmsgb;
fd_set rfds; struct pollfd *pfds = NULL, *tmp;
struct timeval tv; struct pktcobj *pobject;
struct pktcobj *pobject;
struct cops_cmts *cmts; struct cops_cmts *cmts;
struct cops_gate *gate; struct cops_gate *gate;
char *sobjp; char *sobjp;
@ -719,9 +718,8 @@ static void *do_pktccops(void *data)
ast_debug(3, "COPS: thread started\n"); ast_debug(3, "COPS: thread started\n");
for (;;) { for (;;) {
tv.tv_sec = 1; ast_free(pfds);
tv.tv_usec = 0; pfds = NULL;
FD_ZERO(&rfds);
nfds = 0; nfds = 0;
AST_LIST_LOCK(&cmts_list); AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) { AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
@ -735,15 +733,27 @@ static void *do_pktccops(void *data)
} }
} }
if (cmts->sfd > 0) { if (cmts->sfd > 0) {
FD_SET(cmts->sfd, &rfds); if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
if (cmts->sfd > nfds) nfds = cmts->sfd; continue;
}
pfds = tmp;
pfds[nfds].fd = cmts->sfd;
pfds[nfds].events = POLLIN;
pfds[nfds].revents = 0;
nfds++;
} else { } else {
cmts->sfd = cops_connect(cmts->host, cmts->port); cmts->sfd = cops_connect(cmts->host, cmts->port);
if (cmts->sfd > 0) { if (cmts->sfd > 0) {
cmts->state = 1; cmts->state = 1;
if (cmts->sfd > 0) { if (cmts->sfd > 0) {
FD_SET(cmts->sfd, &rfds); if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
if (cmts->sfd > nfds) nfds = cmts->sfd; continue;
}
pfds = tmp;
pfds[nfds].fd = cmts->sfd;
pfds[nfds].events = POLLIN;
pfds[nfds].revents = 0;
nfds++;
} }
} }
} }
@ -781,10 +791,11 @@ static void *do_pktccops(void *data)
if (pktcreload == 2) { if (pktcreload == 2) {
pktcreload = 0; pktcreload = 0;
} }
if ((res = select(nfds + 1, &rfds, NULL, NULL, &tv))) { if ((res = ast_poll(pfds, nfds, 1000))) {
AST_LIST_LOCK(&cmts_list); AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) { AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
if (FD_ISSET(cmts->sfd, &rfds)) { int idx;
if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
len = cops_getmsg(cmts->sfd, recmsg); len = cops_getmsg(cmts->sfd, recmsg);
if (len > 0) { if (len > 0) {
ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n", ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n",

253
tests/test_poll.c Normal file
View File

@ -0,0 +1,253 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2010, Digium, Inc.
*
* Tilghman Lesher <tlesher AT digium DOT com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!
* \file
* \brief Poll Tests
*
* \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
*
* Verify that the various poll implementations work as desired (ast_poll, ast_poll2)
* \ingroup tests
*/
/*** MODULEINFO
<depend>TEST_FRAMEWORK</depend>
***/
#include "asterisk.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
#include "asterisk/poll-compat.h"
#ifndef HAVE_SBIN_LAUNCHD
static void *failsafe_cancel(void *vparent)
{
pthread_t parent = (pthread_t) (long) vparent;
sleep(1);
pthread_testcancel();
pthread_kill(parent, SIGURG);
sleep(1);
pthread_testcancel();
pthread_kill(parent, SIGURG);
sleep(1);
pthread_testcancel();
pthread_kill(parent, SIGURG);
pthread_exit(NULL);
}
#define RESET for (i = 0; i < 4; i++) { pfd[i].revents = 0; }
AST_TEST_DEFINE(poll_test)
{
#define FDNO 3
int fd[2], res = AST_TEST_PASS, i, res2;
int rdblocker[2];
#if FDNO > 3
int wrblocker[2], consec_interrupt = 0;
#endif
struct pollfd pfd[4] = { { .events = POLLOUT, }, { .events = POLLIN, }, { .events = POLLIN }, { .events = POLLOUT } };
pthread_t failsafe_tid;
struct timeval tv = { 0, 0 };
#if FDNO > 3
char garbage[256] =
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/";
#endif
switch (cmd) {
case TEST_INIT:
info->name = "poll_test";
info->category = "main/poll/";
info->summary = "unit test for the ast_poll() API";
info->description =
"Verifies behavior for the ast_poll() API call\n";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
ast_test_status_update(test, "Creating handle that should NEVER block on write\n");
if ((fd[0] = open("/dev/null", O_WRONLY)) < 0) {
ast_test_status_update(test, "Unable to open a writable handle to /dev/null: %s\n", strerror(errno));
return AST_TEST_FAIL;
}
ast_test_status_update(test, "Creating handle that should NEVER block on read\n");
if ((fd[1] = open("/dev/zero", O_RDONLY)) < 0) {
ast_test_status_update(test, "Unable to open a readable handle to /dev/zero: %s\n", strerror(errno));
close(fd[0]);
return AST_TEST_FAIL;
}
ast_test_status_update(test, "Creating handle that should block on read\n");
if (pipe(rdblocker) < 0) {
ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
close(fd[0]);
close(fd[1]);
return AST_TEST_FAIL;
}
#if FDNO > 3
ast_test_status_update(test, "Creating handle that should block on write\n");
if (pipe(wrblocker) < 0) {
ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
close(fd[0]);
close(fd[1]);
close(rdblocker[0]);
close(rdblocker[1]);
return AST_TEST_FAIL;
}
ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
ast_test_status_update(test, "Unable to start failsafe thread\n");
close(fd[0]);
close(fd[1]);
close(fd[2]);
close(rdblocker[0]);
close(rdblocker[1]);
close(wrblocker[0]);
close(wrblocker[1]);
return AST_TEST_FAIL;
}
/* Fill the pipe full of data */
ast_test_status_update(test, "Making pipe block on write\n");
for (i = 0; i < 4096; i++) { /* 1MB of data should be more than enough for any pipe */
errno = 0;
if (write(wrblocker[1], garbage, sizeof(garbage)) < sizeof(garbage)) {
ast_test_status_update(test, "Got %d\n", errno);
if (errno == EINTR && ++consec_interrupt > 1) {
break;
}
} else {
consec_interrupt = 0;
}
}
ast_test_status_update(test, "Cancelling failsafe thread.\n");
pthread_cancel(failsafe_tid);
pthread_kill(failsafe_tid, SIGURG);
pthread_join(failsafe_tid, NULL);
#endif
pfd[0].fd = fd[0];
pfd[1].fd = fd[1];
pfd[2].fd = rdblocker[0];
#if FDNO > 3
pfd[3].fd = wrblocker[1];
#endif
/* Need to ensure the infinite timeout doesn't stall the process */
ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
ast_test_status_update(test, "Unable to start failsafe thread\n");
close(fd[0]);
close(fd[1]);
close(rdblocker[0]);
close(rdblocker[1]);
#if FDNO > 3
close(wrblocker[0]);
close(wrblocker[1]);
#endif
return AST_TEST_FAIL;
}
RESET;
if ((res2 = ast_poll(pfd, FDNO, -1)) != 2) {
ast_test_status_update(test, "ast_poll does not return that only two handles are available (inf timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
RESET;
if ((res2 = ast_poll2(pfd, FDNO, NULL)) != 2) {
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (inf timeout): %d %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
ast_test_status_update(test, "Cancelling failsafe thread.\n");
pthread_cancel(failsafe_tid);
pthread_kill(failsafe_tid, SIGURG);
pthread_join(failsafe_tid, NULL);
RESET;
if (ast_poll(pfd, FDNO, 0) != 2) {
ast_test_status_update(test, "ast_poll does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
RESET;
if (ast_poll2(pfd, FDNO, &tv) != 2) {
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
RESET;
if (ast_poll(pfd, FDNO, 1) != 2) {
ast_test_status_update(test, "ast_poll does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
tv.tv_usec = 1000;
if (ast_poll2(pfd, FDNO, &tv) != 2) {
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
res = AST_TEST_FAIL;
}
close(fd[0]);
close(fd[1]);
close(rdblocker[0]);
close(rdblocker[1]);
#if FDNO > 3
close(wrblocker[0]);
close(wrblocker[1]);
#endif
return res;
}
#endif
static int unload_module(void)
{
#ifndef HAVE_SBIN_LAUNCHD
AST_TEST_UNREGISTER(poll_test);
#endif
return 0;
}
static int load_module(void)
{
#ifndef HAVE_SBIN_LAUNCHD
AST_TEST_REGISTER(poll_test);
#endif
return AST_MODULE_LOAD_SUCCESS;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Poll test");