int main() { fd_set rdset, wrset; int max; sigset_t chld_set; init(); signal(SIGCHLD, sigchld_handler); signal(SIGPIPE, SIG_IGN); sigemptyset(&chld_set); sigaddset(&chld_set, SIGCHLD); for (;;) { sigprocmask(SIG_BLOCK, &chld_set, NULL); if (child_exited) reap_children(); max = fill_fds_for_select(&rdset, &wrset); if (libvchan_buffer_space(ctrl_vchan) <= (int)sizeof(struct msg_header)) FD_ZERO(&rdset); wait_for_vchan_or_argfd(ctrl_vchan, max, &rdset, &wrset); sigprocmask(SIG_UNBLOCK, &chld_set, NULL); while (libvchan_data_ready(ctrl_vchan)) handle_server_cmd(); if (FD_ISSET(trigger_fd, &rdset)) handle_trigger_io(); handle_terminated_fork_client(&rdset); } }
int main(int argc, char **argv) { fd_set read_fdset, write_fdset; int i, opt; int max; sigset_t chld_set; while ((opt=getopt(argc, argv, "q")) != -1) { switch (opt) { case 'q': opt_quiet = 1; break; default: /* '?' */ fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); exit(1); } } if (argc - optind < 2 || argc - optind > 3) { fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); exit(1); } remote_domain_id = atoi(argv[optind]); remote_domain_name = argv[optind+1]; if (argc - optind >= 3) default_user = argv[optind+2]; init(remote_domain_id); sigemptyset(&chld_set); sigaddset(&chld_set, SIGCHLD); signal(SIGCHLD, sigchld_handler); /* * The main event loop. Waits for one of the following events: * - message from client * - message from agent * - new client * - child exited */ for (;;) { max = fill_fdsets_for_select(&read_fdset, &write_fdset); if (libvchan_buffer_space(vchan) <= (int)sizeof(struct msg_header)) FD_ZERO(&read_fdset); // vchan full - don't read from clients sigprocmask(SIG_BLOCK, &chld_set, NULL); if (child_exited) reap_children(); wait_for_vchan_or_argfd(vchan, max, &read_fdset, &write_fdset); sigprocmask(SIG_UNBLOCK, &chld_set, NULL); if (FD_ISSET(qrexec_daemon_unix_socket_fd, &read_fdset)) handle_new_client(); while (libvchan_data_ready(vchan)) handle_message_from_agent(); for (i = 0; i <= max_client_fd; i++) if (clients[i].state != CLIENT_INVALID && FD_ISSET(i, &read_fdset)) handle_message_from_client(i); } }
int libvchan_read(struct libvchan *ctrl, void *data, size_t size) { while (1) { int avail = libvchan_data_ready(ctrl); if (avail && size > avail) size = avail; if (avail) return do_recv(ctrl, data, size); if (!libvchan_is_open(ctrl)) return -1; if (!ctrl->blocking) return 0; if (libvchan_wait(ctrl)) return -1; } }
/** may sleep (only if no data is available for reading); may return less data than requested; returns the amount of data processed, -1 on error or peer close */ int libvchan_read(struct libvchan *ctrl, char *data, int size) { int avail, avail_contig; int real_idx; while ((avail = libvchan_data_ready(ctrl)) == 0) if (libvchan_wait(ctrl) < 0) return -1; if (avail > size) avail = size; real_idx = (*ctrl->rd_cons) & (ctrl->rd_ring_size - 1); avail_contig = ctrl->rd_ring_size - real_idx; if (avail_contig < avail) avail = avail_contig; memcpy(data, ctrl->rd_ring + real_idx, avail); *ctrl->rd_cons += avail; if (do_notify(ctrl) < 0) return -1; return avail; }
static void thread_func(void *userdata) { struct userdata *u = userdata; char buf[2048]; // max ring buffer size pa_assert(u); pa_log_debug("Thread starting up"); pa_thread_mq_install(&u->thread_mq); for (;;) { struct pollfd *play_pollfd; struct pollfd *rec_pollfd; int ret; play_pollfd = pa_rtpoll_item_get_pollfd(u->play_rtpoll_item, NULL); rec_pollfd = pa_rtpoll_item_get_pollfd(u->rec_rtpoll_item, NULL); if (play_pollfd->revents & POLLIN) { if (libvchan_wait(u->play_ctrl) < 0) goto fail; play_pollfd->revents = 0; } if (rec_pollfd->revents & POLLIN) { if (libvchan_wait(u->rec_ctrl) < 0) goto fail; rec_pollfd->revents = 0; } /* Render some data and write it to the fifo */ if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { if (u->sink->thread_info.rewind_requested) pa_sink_process_rewind(u->sink, 0); if (libvchan_buffer_space(u->play_ctrl)) { if (process_sink_render(u) < 0) goto fail; } } if (u->source->thread_info.state == PA_SOURCE_RUNNING) { while (libvchan_data_ready(u->rec_ctrl)) { if (process_source_data(u) < 0) goto fail; } } else { /* discard the data */ if (libvchan_data_ready(u->rec_ctrl)) if (libvchan_read(u->rec_ctrl, buf, sizeof(buf)) < 0) goto fail; } /* Hmm, nothing to do. Let's sleep */ play_pollfd->events = POLLIN; rec_pollfd->events = POLLIN; #if PA_CHECK_VERSION(6,0,0) if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) #else if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0) #endif goto fail; if (ret == 0) goto finish; } fail: /* If this was no regular exit from the loop we have to continue * processing messages until we received PA_MESSAGE_SHUTDOWN */ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); finish: pa_log_debug("Thread shutting down"); }
static void select_loop(libvchan_t *vchan) { fd_set select_set; fd_set wr_set; int max_fd; int ret; int vchan_fd; sigset_t selectmask; struct timespec zero_timeout = { 0, 0 }; struct timespec select_timeout = { 10, 0 }; struct buffer stdin_buf; sigemptyset(&selectmask); sigaddset(&selectmask, SIGCHLD); sigprocmask(SIG_BLOCK, &selectmask, NULL); sigemptyset(&selectmask); buffer_init(&stdin_buf); /* remember to set back to blocking mode before closing the FD - this may * be not the only copy and some processes may misbehave when get * nonblocking FD for input/output */ set_nonblock(local_stdin_fd); for (;;) { vchan_fd = libvchan_fd_for_select(vchan); FD_ZERO(&select_set); FD_ZERO(&wr_set); FD_SET(vchan_fd, &select_set); max_fd = vchan_fd; if (local_stdout_fd != -1 && (size_t)libvchan_buffer_space(vchan) > sizeof(struct msg_header)) { FD_SET(local_stdout_fd, &select_set); if (local_stdout_fd > max_fd) max_fd = local_stdout_fd; } if (child_exited && local_stdout_fd == -1) check_child_status(vchan); if (local_stdin_fd != -1 && buffer_len(&stdin_buf)) { FD_SET(local_stdin_fd, &wr_set); if (local_stdin_fd > max_fd) max_fd = local_stdin_fd; } if ((local_stdin_fd == -1 || buffer_len(&stdin_buf) == 0) && libvchan_data_ready(vchan) > 0) { /* check for other FDs, but exit immediately */ ret = pselect(max_fd + 1, &select_set, &wr_set, NULL, &zero_timeout, &selectmask); } else ret = pselect(max_fd + 1, &select_set, &wr_set, NULL, &select_timeout, &selectmask); if (ret < 0) { if (errno == EINTR && local_pid > 0) { continue; } else { perror("select"); do_exit(1); } } if (ret == 0) { if (!libvchan_is_open(vchan)) { /* remote disconnected witout a proper signaling */ do_exit(1); } } if (FD_ISSET(vchan_fd, &select_set)) libvchan_wait(vchan); if (buffer_len(&stdin_buf) && local_stdin_fd != -1 && FD_ISSET(local_stdin_fd, &wr_set)) { if (flush_client_data(local_stdin_fd, &stdin_buf) == WRITE_STDIN_ERROR) { perror("write stdin"); close(local_stdin_fd); local_stdin_fd = -1; } } while (libvchan_data_ready(vchan)) if (handle_vchan_data(vchan, &stdin_buf) != WRITE_STDIN_OK) break; if (local_stdout_fd != -1 && FD_ISSET(local_stdout_fd, &select_set)) handle_input(vchan); } }