int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout) { ast_fdset read_descs; /* input file descs */ ast_fdset write_descs; /* output file descs */ ast_fdset except_descs; /* exception descs */ struct timeval stime; /* select() timeout value */ int ready_descriptors; /* function result */ int max_fd = 0; /* maximum fd value */ struct timeval *pTimeout; /* actually passed */ int save_errno; FD_ZERO(&read_descs); FD_ZERO(&write_descs); FD_ZERO(&except_descs); /* Map the poll() file descriptor list in the select() data structures. */ if (pArray) { max_fd = map_poll_spec (pArray, n_fds, &read_descs, &write_descs, &except_descs); } /* Map the poll() timeout value in the select() timeout structure. */ pTimeout = map_timeout (timeout, &stime); /* Make the select() call. */ ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, pTimeout); save_errno = errno; if (ready_descriptors >= 0) { map_select_results (pArray, n_fds, &read_descs, &write_descs, &except_descs); } errno = save_errno; return ready_descriptors; }
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv) { #if !defined(AST_POLL_COMPAT) struct timeval start = ast_tvnow(); #if defined(HAVE_PPOLL) struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 }; int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL); #else int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1); #endif struct timeval after = ast_tvnow(); if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) { *tv = ast_tvsub(*tv, ast_tvsub(after, start)); } else if (res > 0 && tv) { *tv = ast_tv(0, 0); } return res; #else ast_fdset read_descs, write_descs, except_descs; int ready_descriptors, max_fd = 0; FD_ZERO(&read_descs); FD_ZERO(&write_descs); FD_ZERO(&except_descs); if (pArray) { max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs); } ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv); if (ready_descriptors >= 0) { map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs); } return ready_descriptors; #endif }
static void *do_monitor(void *data) { fd_set rfds, efds; int n, res; struct phone_pvt *i; int tonepos = 0; /* The tone we're playing this round */ 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 */ /* From here on out, we die whenever asked */ if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) { ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n"); return NULL; } for(;;) { /* Don't let anybody kill us right away. Nobody should lock the interface list and wait for the monitor list, but the other way around is okay. */ if (ast_mutex_lock(&monlock)) { ast_log(LOG_ERROR, "Unable to grab monitor lock\n"); return NULL; } /* Lock the interface list */ if (ast_mutex_lock(&iflock)) { ast_log(LOG_ERROR, "Unable to grab interface lock\n"); ast_mutex_unlock(&monlock); return NULL; } /* 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); 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 (i->dialtone) { /* Remember we're going to have to come back and play more dialtones */ if (!tv.tv_usec && !tv.tv_sec) { /* If we're due for a dialtone, play one */ 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); /* And from now on, we're okay to be killed, so release the monitor lock as well */ ast_mutex_unlock(&monlock); /* Wait indefinitely for something to happen */ if (dotone) { /* If we're ready to recycle the time, set it to 30 ms */ tonepos += 240; if (tonepos >= sizeof(DialTone)) tonepos = 0; if (!tv.tv_usec && !tv.tv_sec) { tv.tv_usec = 30000; tv.tv_sec = 0; } res = ast_select(n + 1, &rfds, NULL, &efds, &tv); } else { res = ast_select(n + 1, &rfds, NULL, &efds, NULL); tv.tv_usec = 0; tv.tv_sec = 0; tonepos = 0; } /* Okay, select has finished. Let's see what happened. */ if (res < 0) { ast_log(LOG_WARNING, "select return %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) continue; /* Alright, lock the interface list again, and let's look and see what has happened */ if (ast_mutex_lock(&iflock)) { ast_log(LOG_WARNING, "Unable to lock the interface list\n"); continue; } i = iflist; while(i) { if (FD_ISSET(i->fd, &rfds)) { if (i->owner) { ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d, %s)...\n", i->fd, i->dev); continue; } phone_mini_packet(i); } if (FD_ISSET(i->fd, &efds)) { if (i->owner) { ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d, %s)...\n", i->fd, i->dev); continue; } phone_check_exception(i); } i=i->next; } ast_mutex_unlock(&iflock); } /* Never reached */ return NULL; }
/* * Helper thread to periodically poll the video source and enqueue the * generated frames to the channel's queue. * Using a separate thread also helps because the encoding can be * computationally expensive so we don't want to starve the main thread. */ static void *video_thread(void *arg) { struct video_desc *env = arg; int count = 0; char save_display[128] = ""; /* if sdl_videodriver is set, override the environment. Also, * if it contains 'console' override DISPLAY around the call to SDL_Init * so we use the console as opposed to the x11 version of aalib */ if (!ast_strlen_zero(env->sdl_videodriver)) { /* override */ const char *s = getenv("DISPLAY"); setenv("SDL_VIDEODRIVER", env->sdl_videodriver, 1); if (s && !strcasecmp(env->sdl_videodriver, "aalib-console")) { ast_copy_string(save_display, s, sizeof(save_display)); unsetenv("DISPLAY"); } } sdl_setup(env); if (!ast_strlen_zero(save_display)) setenv("DISPLAY", save_display, 1); /* initialize grab coordinates */ env->out.loc_src_geometry.x = 0; env->out.loc_src_geometry.y = 0; 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"); } else { #if 0 /* In principle, try to register the fd. * In practice, many webcam drivers do not support select/poll, * so don't bother and instead read periodically from the * video thread. */ if (env->out.fd >= 0) ast_channel_set_fd(env->owner, 1, env->out.fd); #endif video_out_init(env); } for (;;) { struct timeval t = { 0, 50000 }; /* XXX 20 times/sec */ struct ast_frame *p, *f; struct ast_channel *chan; int fd; char *caption = NULL, buf[160]; /* determine if video format changed */ if (count++ % 10 == 0) { if (env->out.sendvideo) sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps", env->out.videodevice, env->codec_name, env->enc_in.w, env->enc_in.h, env->out.fps, env->out.bitrate/1000); else sprintf(buf, "hold"); caption = buf; } /* manage keypad events */ /* XXX here we should always check for events, * otherwise the drag will not work */ if (env->gui) eventhandler(env, caption); /* sleep for a while */ ast_select(0, NULL, NULL, NULL, &t); 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 */ if (v->d_callbacks->dec_run(v, tmp)) 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; f = get_video_frames(env, &p); /* read and display */ if (!f) continue; chan = env->owner; if (chan == NULL) continue; fd = chan->alertpipe[1]; ast_channel_lock(chan); /* AST_LIST_INSERT_TAIL is only good for one frame, cannot use here */ if (chan->readq.first == NULL) { chan->readq.first = f; } else { chan->readq.last->frame_list.next = f; } chan->readq.last = p; /* * more or less same as ast_queue_frame, but extra * write on the alertpipe to signal frames. */ if (fd > -1) { int blah = 1, l = sizeof(blah); 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)); } } ast_channel_unlock(chan); } /* thread terminating, here could call the uninit */ /* uninitialize the local and remote video environments */ env->in = dec_uninit(env->in); video_out_uninit(env); if (env->gui) env->gui = cleanup_sdl(env->gui); ast_mutex_destroy(&env->dec_lock); env->shutdown = 0; return NULL; }