static struct ast_frame *misdn_read(struct ast_channel *ast)
{
struct chan_list *tmp;
- fd_set rrfs;
- struct timeval tv = { 0, 20000 };
int len, t;
+ struct pollfd pfd = { .fd = -1, .events = POLLIN };
if (!ast) {
chan_misdn_log(1, 0, "misdn_read called without ast\n");
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");
return NULL;
}
return NULL;
}
- FD_ZERO(&rrfs);
- FD_SET(tmp->pipe[0], &rrfs);
-
- if (!(t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv))) {
- chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
- len = 160;
- }
+ pfd.fd = tmp->pipe[0];
+ t = ast_poll(&pfd, 1, 20);
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;
}
- 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));
if (len <= 0) {
if (ch->ast)
ast_queue_frame(ch->ast, &frame);
} else {
- fd_set wrfs;
- struct timeval tv = { 0, 0 };
+ struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
int t;
- FD_ZERO(&wrfs);
- FD_SET(ch->pipe[1], &wrfs);
+ t = ast_poll(&pfd, 1, 0);
- t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
-
- if (!t) {
- chan_misdn_log(9, bc->port, "Select Timed out\n");
+ if (t < 0) {
+ chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
break;
}
-
- if (t < 0) {
- chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
+
+ if (!t) {
+ chan_misdn_log(9, bc->port, "poll() timed out\n");
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);
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));
static void *do_monitor(void *data)
{
- fd_set rfds, efds;
- int n, res;
+ struct pollfd *fds = NULL;
+ int nfds = 0, inuse_fds = 0, res;
struct phone_pvt *i;
int tonepos = 0;
/* The tone we're playing this round */
- struct timeval wait = {0,0};
+ struct timeval tv = { 0, 0 };
int dotone;
/* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */
}
/* 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 */
- n = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
i = iflist;
dotone = 0;
- while (i) {
- if (FD_ISSET(i->fd, &rfds))
- ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
+ inuse_fds = 0;
+ for (i = iflist; i; i = i->next) {
if (!i->owner) {
/* This needs to be watched, as it lacks an owner */
- FD_SET(i->fd, &rfds);
- FD_SET(i->fd, &efds);
- if (i->fd > n)
- n = i->fd;
+ if (inuse_fds == nfds) {
+ void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
+ if (!tmp) {
+ /* 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) {
/* Remember we're going to have to come back and play
more dialtones */
- if (ast_tvzero(wait)) {
+ if (ast_tvzero(tv)) {
/* 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");
+ }
}
dotone++;
}
}
-
- i = i->next;
}
/* Okay, now that we know what to do, release the interface lock */
ast_mutex_unlock(&iflock);
if (dotone && i && i->mode != MODE_SIGMA) {
/* If we're ready to recycle the time, set it to 30 ms */
tonepos += 240;
- if (tonepos >= sizeof(DialTone))
- tonepos = 0;
- if (ast_tvzero(wait)) {
- wait = ast_tv(30000, 0);
+ if (tonepos >= sizeof(DialTone)) {
+ tonepos = 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 {
- res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
- wait = ast_tv(0,0);
+ res = ast_poll(fds, inuse_fds, -1);
+ tv = ast_tv(0, 0);
tonepos = 0;
}
/* Okay, select has finished. Let's see what happened. */
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;
}
/* If there are no fd's changed, just continue, it's probably time
to play some more dialtones */
- if (!res)
+ if (!res) {
continue;
+ }
/* Alright, lock the interface list again, and let's look and see what has
happened */
if (ast_mutex_lock(&iflock)) {
continue;
}
- i = iflist;
- for(; i; i=i->next) {
- if (FD_ISSET(i->fd, &rfds)) {
+ for (i = iflist; i; i = i->next) {
+ int j;
+ /* 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) {
continue;
}
phone_mini_packet(i);
}
- if (FD_ISSET(i->fd, &efds)) {
+ if (fds[j].revents & POLLERR) {
if (i->owner) {
continue;
}
ast_mutex_unlock(&iflock);
}
return NULL;
-
}
static int restart_monitor()
struct usb_device *usb_dev;
struct usb_dev_handle *usb_handle;
struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
- struct timeval to;
- fd_set rfds;
+ struct pollfd pfd = { .events = POLLIN };
usb_dev = hid_device_init(o->devstr);
if (usb_dev == NULL) {
traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
lastrx = 0;
// popen
- while(!o->stophid)
- {
- to.tv_sec = 0;
- to.tv_usec = 50000; // maw sph
+ while (!o->stophid) {
+ pfd.fd = o->pttkick;
+ pfd.revents = 0;
- FD_ZERO(&rfds);
- 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);
+ res = ast_poll2(&pfd, 1, 50);
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);
continue;
}
- if (FD_ISSET(o->pttkick[0],&rfds))
- {
+ if (pfd.revents & POLLIN) { {
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));
}
}
- if(o->wanteeprom)
- {
+ if (o->wanteeprom) {
ast_mutex_lock(&o->eepromlock);
- if (o->eepromctl == 1) /* to read */
- {
+ if (o->eepromctl == 1) { /* to read */
/* if CS okay */
- if (!get_eeprom(usb_handle,o->eeprom))
- {
- if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC)
- {
- ast_log(LOG_NOTICE,"UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n",o->name);
- }
- else
- {
+ if (!get_eeprom(usb_handle, o->eeprom)) {
+ if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
+ ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
+ } else {
o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
- o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
+ o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
- memcpy(&o->rxvoiceadj,&o->eeprom[EEPROM_RXVOICEADJ],sizeof(float));
- memcpy(&o->rxctcssadj,&o->eeprom[EEPROM_RXCTCSSADJ],sizeof(float));
+ memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
+ memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
}
- }
- else
- {
- ast_log(LOG_NOTICE,"USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n",o->name);
+ } else {
+ 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);
- }
- if (o->eepromctl == 2) /* to write */
- {
+ }
+ if (o->eepromctl == 2) { /* to write */
put_eeprom(usb_handle,o->eeprom);
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;
ast_mutex_unlock(&o->eepromlock);
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
hid_get_inputs(usb_handle,buf);
keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
- if (keyed != o->rxhidsq)
- {
- if(o->debuglevel)printf("chan_usbradio() hidthread: update rxhidsq = %d\n",keyed);
+ if (keyed != o->rxhidsq) {
+ if (o->debuglevel) {
+ printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
+ }
o->rxhidsq=keyed;
}
/* if change in tx state as controlled by xpmr */
- txtmp=o->pmrChan->txPttOut;
-
- if (o->lasttx != txtmp)
- {
- o->pmrChan->txPttHid=o->lasttx = txtmp;
- if(o->debuglevel)printf("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;
+ txtmp = o->pmrChan->txPttOut;
+
+ if (o->lasttx != txtmp) {
+ o->pmrChan->txPttHid = o->lasttx = txtmp;
+ if (o->debuglevel) {
+ ast_debug(0, "hidthread: tx set to %d\n", txtmp);
}
- else
- {
- if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
+ buf[o->hid_gpio_loc] = 0;
+ if (!o->invertptt) {
+ 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;
- memcpy(bufsave,buf,sizeof(buf));
- hid_set_outputs(usb_handle,buf);
+ memcpy(bufsave, buf, sizeof(buf));
+ hid_set_outputs(usb_handle, buf);
}
time(&o->lasthidtime);
}
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;
- hid_set_outputs(usb_handle,buf);
+ hid_set_outputs(usb_handle, buf);
pthread_exit(0);
}
*/
read(o->sounddev, ign, sizeof(ign));
for (;;) {
- fd_set rfds, wfds;
- int maxfd, res;
-
- FD_ZERO(&rfds);
- 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)
+ struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
+ int res;
+
+ if (o->cursound > -1 && o->sounddev < 0) {
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 */
}
if (o->sounddev > -1) {
if (!o->owner) { /* no one owns the audio, so we must drain it */
- FD_SET(o->sounddev, &rfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events = POLLIN;
}
if (o->cursound > -1) {
- FD_SET(o->sounddev, &wfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events |= POLLOUT;
}
}
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
+ res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -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);
continue;
}
- if (FD_ISSET(o->sndcmd[0], &rfds)) {
+ if (pfd[0].revents & POLLIN) {
/* read which sound to play from the pipe */
int i, what = -1;
break;
}
}
- if (sounds[i].ind == -1)
+ if (sounds[i].ind == -1) {
ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
+ }
}
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));
- if (FD_ISSET(o->sounddev, &wfds))
+ }
+ if (pfd[1].revents & POLLOUT) {
send_sound(o);
+ }
}
}
return NULL; /* Never reached */
* and contain all configurtion info.
*/
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 */
- pthread_t vthread; /* video thread */
- ast_mutex_t dec_lock; /* sync decoder and video thread */
- int shutdown; /* set to shutdown vthread */
- struct ast_channel *owner; /* owner channel */
+ int stayopen; /* set if gui starts manually */
+ pthread_t vthread; /* video thread */
+ ast_mutex_t dec_lock; /* sync decoder and video thread */
+ int shutdown; /* set to shutdown vthread */
+ 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_font[256]; /* font for the keypad */
+ char keypad_file[256]; /* image 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 loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
+ 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]) */
/* 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 */
- struct gui_info *gui;
- struct video_dec_desc *in; /* remote video descriptor */
- struct video_out_desc out; /* local video descriptor */
+ struct gui_info *gui;
+ struct video_dec_desc *in; /* remote video descriptor */
+ struct video_out_desc out; /* local video descriptor */
};
static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
*/
static void grabber_move(struct video_device *dev, int dx, int dy)
{
- if (dev->grabber && dev->grabber->move)
- dev->grabber->move(dev->grabber_data, dx, dy);
+ if (dev->grabber && dev->grabber->move) {
+ dev->grabber->move(dev->grabber_data, dx, dy);
+ }
}
/*
/* now setup the parameters for the encoder.
* XXX should be codec-specific
*/
- {
- AVCodecContext *enc_ctx = avcodec_alloc_context();
- v->enc_ctx = enc_ctx;
- enc_ctx->pix_fmt = enc_in->pix_fmt;
- enc_ctx->width = enc_in->w;
- enc_ctx->height = enc_in->h;
- /* XXX rtp_callback ?
- * rtp_mode so ffmpeg inserts as many start codes as possible.
- */
- enc_ctx->rtp_mode = 1;
- enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
- enc_ctx->bit_rate = v->bitrate;
- enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
- enc_ctx->qmin = v->qmin; /* should be configured */
- enc_ctx->time_base = (AVRational){1, v->fps};
- enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
-
- v->enc->enc_init(v->enc_ctx);
-
- if (avcodec_open(enc_ctx, v->codec) < 0) {
- ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
- codec);
- av_free(enc_ctx);
- v->enc_ctx = NULL;
- return video_out_uninit(env);
+ {
+ AVCodecContext *enc_ctx = avcodec_alloc_context();
+ v->enc_ctx = enc_ctx;
+ enc_ctx->pix_fmt = enc_in->pix_fmt;
+ enc_ctx->width = enc_in->w;
+ enc_ctx->height = enc_in->h;
+ /* XXX rtp_callback ?
+ * rtp_mode so ffmpeg inserts as many start codes as possible.
+ */
+ enc_ctx->rtp_mode = 1;
+ enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
+ enc_ctx->bit_rate = v->bitrate;
+ enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
+ enc_ctx->qmin = v->qmin; /* should be configured */
+ enc_ctx->time_base = (AVRational){1, v->fps};
+ enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
+
+ v->enc->enc_init(v->enc_ctx);
+
+ if (avcodec_open(enc_ctx, v->codec) < 0) {
+ ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", codec);
+ av_free(enc_ctx);
+ v->enc_ctx = NULL;
+ return video_out_uninit(env);
+ }
}
- }
/*
* Allocate enough for the encoded bitstream. As we are compressing,
* we hope that the output is never larger than the input size.
p_in = fill_pict(in, &my_p_in);
if (p_out == NULL)
p_out = fill_pict(out, &my_p_out);
-
- /*if win_w is different from zero then we must change
- the size of the scaled buffer (the position is already
+
+ /*if win_w is different from zero then we must change
+ the size of the scaled buffer (the position is already
encoded into the out parameter)*/
if (out->win_w) { /* picture in picture enabled */
eff_w=out->win_w;
img_convert(p_out, out->pix_fmt,
p_in, in->pix_fmt, in->w, in->h);
#else /* XXX replacement */
- {
- 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;
+ {
+ 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);
}
- 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 */
}
}
}
sdl_setup(env);
- if (!ast_strlen_zero(save_display))
+ if (!ast_strlen_zero(save_display)) {
setenv("DISPLAY", save_display, 1);
+ }
ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */
if (grabber_open(&env->out)) {
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;
-
+ }
+
/* even if no device is connected, we must call video_out_init,
* as some of the data structures it initializes are
* used in get_video_frames()
/* Writes intial status of the sources. */
if (env->gui) {
- for (i = 0; i < env->out.device_num; i++) {
- print_message(env->gui->thumb_bd_array[i].board,
- src_msgs[env->out.devices[i].status_index]);
- }
+ for (i = 0; i < env->out.device_num; i++) {
+ print_message(env->gui->thumb_bd_array[i].board,
+ src_msgs[env->out.devices[i].status_index]);
+ }
}
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_channel *chan;
int fd;
/* determine if video format changed */
if (count++ % 10 == 0) {
- if (env->out.sendvideo && env->out.devices)
- sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
+ if (env->out.sendvideo && env->out.devices) {
+ snprintf(buf, sizeof(buf), "%s %s %dx%d @@ %dfps %dkbps",
env->out.devices[env->out.device_primary].name, env->codec_name,
env->enc_in.w, env->enc_in.h,
- env->out.fps, env->out.bitrate/1000);
- else
- sprintf(buf, "hold");
+ env->out.fps, env->out.bitrate / 1000);
+ } else {
+ sprintf(buf, "hold");
+ }
caption = buf;
}
* otherwise the drag will not work */
if (env->gui)
eventhandler(env, caption);
-
+
/* sleep for a while */
- ast_select(0, NULL, NULL, NULL, &t);
+ nanosleep(&t, NULL);
if (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)
- show_frame(env, WIN_REMOTE);
- tmp->used = 0; /* mark buffer as free */
- 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);
+ 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)
+ show_frame(env, WIN_REMOTE);
+ tmp->used = 0; /* mark buffer as free */
+ 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)
break;
for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
if (write(fd, &blah, l) != l)
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);
if (env == NULL)
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);
- } else if (!strcasecmp(var, "videocodec")) {
+ } else if (!strcasecmp(var, "videocodec")) {
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");
- } else if (!strcasecmp(var, "video_size")) {
+ } else if (!strcasecmp(var, "video_size")) {
int in_w = 0, in_h = 0;
if (env->in) {
in_w = env->in->dec_out.w;
env->loc_dpy.w, env->loc_dpy.h,
env->rem_dpy.w, env->rem_dpy.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);
- } else if (!strcasecmp(var, "qmin")) {
+ } else if (!strcasecmp(var, "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);
- } else if (!strcasecmp(var, "startgui")) {
+ } else if (!strcasecmp(var, "startgui")) {
env->stayopen = 1;
console_video_start(env, NULL);
- } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
+ } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
env->stayopen = 0;
if (env->gui && env->owner)
ast_cli_command(-1, "console hangup");
else /* not in a call */
console_video_uninit(env);
- } else {
+ } else {
return 1; /* unrecognised */
}
return 0; /* recognised */
;;
darwin*)
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_FUNC_STRTOD
AC_FUNC_UTIME_NULL
AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap 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 ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap 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])
# BSD might not have exp2, and/or log2
AC_CHECK_LIB([m], [sqrt])
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(malloc)
AST_GCC_ATTRIBUTE(const)
}
#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
- * 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 */
static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
{
#ifndef __AST_POLL_COMPAT_H
#define __AST_POLL_COMPAT_H
+#include "asterisk/select.h"
+
#ifndef AST_POLL_COMPAT
#include <sys/poll.h>
#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);
+
#endif /* __AST_POLL_COMPAT_H */
--- /dev/null
+/*
+ * 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 */
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2008, Digium, Inc.
+ * Copyright (C) 1999 - 2010, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
+extern unsigned int ast_FD_SETSIZE;
+
static char *_argv[256];
static int shuttingdown;
static int restartnow;
char *buf;
const char *runuser = NULL, *rungroup = NULL;
char *remotesock = NULL;
+ struct rlimit l;
/* Remember original args for restart */
if (argc > ARRAY_LEN(_argv) - 1) {
}
if (ast_opt_dump_core) {
- struct rlimit l;
memset(&l, 0, sizeof(l));
l.rlim_cur = RLIM_INFINITY;
l.rlim_max = RLIM_INFINITY;
}
}
+ 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))
rungroup = ast_config_AST_RUN_GROUP;
if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
static void parkinglot_unref(struct ast_parkinglot *parkinglot);
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);
}
/*! \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;
int res = 0;
char parkingslot[AST_MAX_EXTENSION];
/* Get chan, exten from derived kludge */
if (pu->peername[0]) {
char *peername = ast_strdupa(pu->peername);
- char *cp = strrchr(peername, '-');
+ char *dash = strrchr(peername, '-');
char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
int i;
- if (cp)
- *cp = 0;
- ast_copy_string(peername_flat,peername,sizeof(peername_flat));
- for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
- if (peername_flat[i] == '/')
- peername_flat[i]= '0';
+ if (dash) {
+ *dash = '\0';
+ }
+ ast_copy_string(peername_flat, peername, sizeof(peername_flat));
+ for (i = 0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
+ if (peername_flat[i] == '/') {
+ peername_flat[i] = '0';
+ }
}
con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
if (!con) {
} else { /* still within parking time, process descriptors */
for (x = 0; x < AST_MAX_FDS; x++) {
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;
-
- 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);
- else
+ } else {
ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+ }
chan->fdno = x;
/* See if they need servicing */
}
} /* End for */
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) {
- FD_SET(chan->fds[x], nrfds);
- FD_SET(chan->fds[x], nefds);
- if (chan->fds[x] > *max)
- *max = chan->fds[x];
+ void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
+ if (!tmp) {
+ continue;
+ }
+ 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 */
- if (tms < *ms || *ms < 0)
+ if (tms < *ms || *ms < 0) {
*ms = tms;
+ }
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&curlot->parkings);
+
+ ast_free(*pfds);
+ *pfds = new_fds;
+ *nfds = new_nfds;
return res;
}
*/
static void *do_parking_thread(void *ignore)
{
- fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
- fd_set nrfds, nefds; /* args for the next select */
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
+ struct pollfd *pfds = NULL;
+ int nfds = 0;
for (;;) {
- int res = 0;
- int ms = -1; /* select timeout, uninitialized */
- int max = -1; /* max fd, none there yet */
struct ao2_iterator iter;
struct ast_parkinglot *curlot;
- FD_ZERO(&nrfds);
- FD_ZERO(&nefds);
+ int ms = -1; /* poll2 timeout, uninitialized */
iter = ao2_iterator_init(parkinglots, 0);
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_iterator_destroy(&iter);
- rfds = nrfds;
- efds = nefds;
- {
- struct timeval wait = ast_samp2tv(ms, 1000);
- /* Wait for something to happen */
- ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
- }
+ /* Wait for something to happen */
+ ast_poll(pfds, nfds, ms);
pthread_testcancel();
}
+ /* If this WERE reached, we'd need to free(pfds) */
return NULL; /* Never reached */
}
struct pollfd
{
- int fd;
- short events;
- short revents;
+ int fd;
+ short events;
+ short revents;
}
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
#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 <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 */
-#ifdef AST_POLL_COMPAT
+unsigned int ast_FD_SETSIZE = FD_SETSIZE;
/*---------------------------------------------------------------------------*\
- Private Functions
+ Private Functions
\*---------------------------------------------------------------------------*/
-static int map_poll_spec
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+#if defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL)
+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 */
+ register unsigned long i; /* loop control */
+ register struct pollfd *pCur; /* current array element */
+ register int max_fd = -1; /* return value */
- /*!\note
+ /*
* Map the poll() structures into the file descriptor sets required
* by select().
*/
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
/* Skip any bad FDs in the array. */
- if (pCur->fd < 0)
+ if (pCur->fd < 0) {
continue;
+ }
if (pCur->events & POLLIN) {
/* "Input Ready" notification desired. */
return max_fd;
}
-\f
-static struct timeval *map_timeout
-#if __STDC__ > 0
- (int poll_timeout, struct timeval *pSelTimeout)
-#else
- (poll_timeout, pSelTimeout)
- int poll_timeout;
- struct timeval *pSelTimeout;
-#endif
+
+#ifdef AST_POLL_COMPAT
+static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
{
struct timeval *pResult;
- /*!\note
- * Map the poll() timeout value into a select() timeout. The possible
- * values of the poll() timeout value, and their meanings, are:
- *
- * VALUE MEANING
- *
- * -1 wait indefinitely (until signal occurs)
- * 0 return immediately, don't block
- * >0 wait specified number of milliseconds
- *
- * select() uses a "struct timeval", which specifies the timeout in
- * seconds and microseconds, so the milliseconds value has to be mapped
- * accordingly.
- */
+ /*
+ Map the poll() timeout value into a select() timeout. The possible
+ values of the poll() timeout value, and their meanings, are:
+
+ VALUE MEANING
- assert(pSelTimeout != (struct timeval *) NULL);
+ -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:
return pResult;
}
+#endif /* AST_POLL_COMPAT */
-static void map_select_results
-#if __STDC__ > 0
- (struct pollfd *pArray,
- unsigned long n_fds,
- fd_set *pReadSet,
- fd_set *pWriteSet,
- fd_set *pExceptSet)
-#else
- (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
- struct pollfd *pArray;
- unsigned long n_fds;
- fd_set *pReadSet;
- fd_set *pWriteSet;
- fd_set *pExceptSet;
-#endif
+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 */
+ 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. */
}
/* Exception events take priority over input events. */
-
pCur->revents = 0;
- if (FD_ISSET (pCur->fd, pExceptSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
pCur->revents |= POLLPRI;
- } else if (FD_ISSET (pCur->fd, pReadSet)) {
+ } else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
pCur->revents |= POLLIN;
}
- if (FD_ISSET (pCur->fd, pWriteSet)) {
+ if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
pCur->revents |= POLLOUT;
}
}
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)
{
- fd_set read_descs; /* input file descs */
- fd_set write_descs; /* output file descs */
- fd_set except_descs; /* exception descs */
+ 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 */
+ 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);
+ 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,
+ 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);
+
+ pTimeout = map_timeout (timeout, &stime);
/* 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);
+ 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) {
map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
}
return ready_descriptors;
+#endif
}
-#endif /* AST_POLL_COMPAT */
+
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
/* send request, possibly wait for reply */
unsigned char reply_buf[1024];
- fd_set rfds;
- struct timeval to = { 3, 0 }; /* timeout, make it configurable */
+ struct pollfd pfds = { .fd = s, .events = POLLIN, };
struct sockaddr_in src;
socklen_t srclen;
}
if (answer == NULL)
break;
- FD_ZERO(&rfds);
- FD_SET(s, &rfds);
- res = ast_select(s + 1, &rfds, NULL, NULL, &to);
+ res = ast_poll(&pfds, 1, 3000);
if (res <= 0) /* timeout or error */
continue;
memset(&src, '\0', sizeof(src));
static void *dispatch_thread_handler(void *data)
{
- SaSelectionObjectT clm_fd, evt_fd, max_fd;
+ SaSelectionObjectT clm_fd, evt_fd;
int res;
- fd_set read_fds;
+ struct pollfd pfd[2] = { { .events = POLLIN, }, { .events = POLLIN, } };
SaAisErrorT ais_res;
ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
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) {
- FD_ZERO(&read_fds);
- FD_SET(clm_fd, &read_fds);
- FD_SET(evt_fd, &read_fds);
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
- res = ast_select(max_fd + 1, &read_fds, NULL, NULL, NULL);
+ res = ast_poll(pfd, 2, -1);
if (res == -1 && errno != EINTR && errno != EAGAIN) {
ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
"and the module will no longer operate.\n", strerror(errno));
break;
}
- if (FD_ISSET(clm_fd, &read_fds))
+ if (pfd[0].revents & POLLIN) {
saClmDispatch(clm_handle, SA_DISPATCH_ALL);
- if (FD_ISSET(evt_fd, &read_fds))
+ }
+ if (pfd[1].revents & POLLIN) {
saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
+ }
}
return NULL;
*/
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
{
- int sock;
- fd_set fds;
- struct timeval tv, *tvptr = NULL;
+ struct pollfd pfd = { .events = POLLIN };
int len, res;
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
- sock = SSL_get_fd(client->ssl_session);
- if (sock < 0)
- return -1;
+ pfd.fd = SSL_get_fd(client->ssl_session);
+ if (pfd.fd < 0) {
+ return -1;
+ }
} else
#endif /* HAVE_OPENSSL */
- sock = iks_fd(client->p);
-
- memset(&tv, 0, sizeof(struct timeval));
- 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;
+ pfd.fd = iks_fd(client->p);
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
+ res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
if (res > 0) {
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
len = SSL_read(client->ssl_session, buffer, buf_len);
} else
#endif /* HAVE_OPENSSL */
- len = recv(sock, buffer, buf_len, 0);
+ len = recv(pfd.fd, buffer, buf_len, 0);
if (len > 0) {
return len;
--- /dev/null
+/*
+ * 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");