// new poll using nanoseconds resolution and // not waiting forever. int netjack_poll_deadline (int sockfd, jack_time_t deadline) { struct pollfd fds; int poll_err = 0; #if HAVE_PPOLL struct timespec timeout_spec = { 0, 0 }; #else int timeout; #endif jack_time_t now = jack_get_time(); if( now >= deadline ) return 0; if( (deadline - now) >= 1000000 ) { jack_error( "deadline more than 1 second in the future, trimming it." ); deadline = now + 500000; } #if HAVE_PPOLL timeout_spec.tv_nsec = (deadline - now) * 1000; #else timeout = lrintf( (float)(deadline - now) / 1000.0 ); #endif fds.fd = sockfd; fds.events = POLLIN; #if HAVE_PPOLL poll_err = ppoll (&fds, 1, &timeout_spec, NULL); #else poll_err = poll (&fds, 1, timeout); #endif if (poll_err == -1) { switch (errno) { case EBADF: jack_error ("Error %d: An invalid file descriptor was given in one of the sets", errno); break; case EFAULT: jack_error ("Error %d: The array given as argument was not contained in the calling program's address space", errno); break; case EINTR: jack_error ("Error %d: A signal occurred before any requested event", errno); break; case EINVAL: jack_error ("Error %d: The nfds value exceeds the RLIMIT_NOFILE value", errno); break; case ENOMEM: jack_error ("Error %d: There was no space to allocate file descriptor tables", errno); break; } } return poll_err; }
static int wait_for_complete(struct loopback_test *t) { int number_of_events = 0; char dummy; int ret; int i; struct timespec *ts = NULL; struct sigaction sa; sigset_t mask_old, mask; sigemptyset(&mask); sigemptyset(&mask_old); sigaddset(&mask, SIGINT); sigprocmask(SIG_BLOCK, &mask, &mask_old); sa.sa_handler = handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (sigaction(SIGINT, &sa, NULL) == -1) { fprintf(stderr, "sigaction error\n"); return -1; } if (t->poll_timeout.tv_sec != 0) ts = &t->poll_timeout; while (1) { ret = ppoll(t->fds, t->poll_count, ts, &mask_old); if (ret <= 0) { stop_tests(t); fprintf(stderr, "Poll exit with errno %d\n", errno); return -1; } for (i = 0; i < t->poll_count; i++) { if (t->fds[i].revents & POLLPRI) { /* Dummy read to clear the event */ read(t->fds[i].fd, &dummy, 1); number_of_events++; } } if (number_of_events == t->poll_count) break; } if (!is_complete(t)) { fprintf(stderr, "Iteration count did not finish!\n"); return -1; } return 0; }
int pipe_eof(int fd) { struct pollfd pollfd = { .fd = fd, .events = POLLIN|POLLHUP, }; int r; r = poll(&pollfd, 1, 0); if (r < 0) return -errno; if (r == 0) return 0; return pollfd.revents & POLLHUP; } int fd_wait_for_event(int fd, int event, usec_t t) { struct pollfd pollfd = { .fd = fd, .events = event, }; struct timespec ts; int r; r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; if (r == 0) return 0; return pollfd.revents; } static size_t nul_length(const uint8_t *p, size_t sz) { size_t n = 0; while (sz > 0) { if (*p != 0) break; n++; p++; sz--; } return n; }
int main (void) { #if defined(HAVE_SIGNALFD) && defined(HAVE_EVENTFD) \ && defined(HAVE_EVENTFD_READ) && defined(HAVE_PPOLL) { sigset_t mask; int fd, fd2; eventfd_t ev; struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; struct pollfd pfd[2]; sigemptyset (&mask); sigaddset (&mask, SIGUSR1); fd = signalfd (-1, &mask, 0); sigaddset (&mask, SIGUSR2); fd = signalfd (fd, &mask, 0); fd2 = eventfd (5, 0); eventfd_read (fd2, &ev); pfd[0].fd = fd; pfd[0].events = POLLIN|POLLOUT; pfd[1].fd = fd2; pfd[1].events = POLLIN|POLLOUT; ppoll (pfd, 2, &ts, &mask); } #endif #if defined(HAVE_UTIMENSAT) unlink("/tmp/valgrind-utimensat-test"); close (creat ("/tmp/valgrind-utimensat-test", S_IRUSR | S_IWUSR)); { struct timespec ts2[2] = { [0].tv_sec = 10000000, [1].tv_sec = 20000000 }; utimensat (AT_FDCWD, "/tmp/valgrind-utimensat-test", ts2, 0); } unlink("/tmp/valgrind-utimensat-test"); #endif #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_EPOLL_PWAIT) { int fd3; struct epoll_event evs[10]; sigset_t mask; sigemptyset (&mask); sigaddset (&mask, SIGUSR1); sigaddset (&mask, SIGUSR2); fd3 = epoll_create (10); epoll_pwait (fd3, evs, 10, 0, &mask); } #endif return 0; }
/* * Acts as a wrapper around read(2) with a timeout. Updates *timeout with * remaining time on successful return (>= 0). Returns # of bytes read (0 = * EOF, -1 = error, -2 = timeout, -3 = thread exit signal received). */ ssize_t fcd_lib_read(int fd, void *buf, size_t count, struct timespec *timeout) { struct timespec deadline; struct pollfd pfd; ssize_t ret; if (fcd_lib_deadline(&deadline, timeout) == -1) return -1; pfd.fd = fd; pfd.events = POLLIN; while (!fcd_thread_exit_flag) { if (fcd_lib_remaining(timeout, &deadline) == -1) return -1; ret = ppoll(&pfd, 1, timeout, &fcd_mon_ppoll_sigmask); if (ret == -1) { if (errno == EINTR) continue; FCD_PERROR("ppoll"); return -1; } if (ret == 0) return -2; /* * Different file descriptors (regular files, pipes, sysfs/proc * files, etc.) behave so differently that it's impossible to * check revents in a meaningful way. */ ret = read(fd, buf, count); if (ret == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; FCD_PERROR("read"); return -1; } else { if (fcd_lib_remaining(timeout, &deadline) == -1) return -1; return ret; } } return -3; }
/* * Sleeps for the specified number of seconds, unless interrupted by a signal * (SIGUSR1). Returns the thread-local value of fcd_thread_exit_flag (or -1 on * error). * * NOTE: Does not check fcd_thread_exit_flag before sleeping (assumes that * SIGUSR1 has been blocked). */ int fcd_lib_monitor_sleep(time_t seconds) { struct timespec ts; ts.tv_sec = seconds; ts.tv_nsec = 0; if (ppoll(NULL, 0, &ts, &fcd_mon_ppoll_sigmask) == -1 && errno != EINTR) { FCD_PERROR("ppoll"); return -1; } return fcd_thread_exit_flag; }
/* qemu is angry when it sees GLib trying to poll(NULL, 0, ...). */ int poll(struct pollfd *pfd, nfds_t npfd, int timeout) { if (!pfd && !npfd) { /* Empty set, emulate with select(2). */ if (timeout >= 0) { struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; return select(0, NULL, NULL, NULL, &tv); } else return select(0, NULL, NULL, NULL, NULL); } else { /* Emulate with ppoll(2). */ if (timeout >= 0) { struct timespec ts; ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; return ppoll(pfd, npfd, &ts, NULL); } else return ppoll(pfd, npfd, NULL, NULL); } }
int gfs_poll(uint64_t ns, uint8_t *r) { struct timespec t= {.tv_sec=0,.tv_nsec=ns}; int ret=ppoll(&ep0,1,&t,0); if(ret<0) { perror("gfs ppoll"); } if(ret) { struct usb_gadgetfs_event e; int ret=read(ep0.fd,&e,sizeof e); if(ret<=0) return 0; if(e.type==GADGETFS_SETUP) { memcpy(r,&e.u.setup,sizeof(e.u.setup)); return 1; } } return 0; }
static void * mythr(void *ignore) { pthread_mutex_lock(&mutex); ready = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); sigset_t ss; sigfillset(&ss); while (1) { struct timespec ts = {10000, 0}; ppoll(NULL, 0, &ts, &ss); } return NULL; }
int fd_wait_for_event(int fd, int event, usec_t t) { struct pollfd pollfd = { .fd = fd, .events = event, }; struct timespec ts; int r; r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; if (r == 0) return 0; return pollfd.revents; }
/* * Loop until the auditpipe returns something, check if it is what * we want, else repeat the procedure until ppoll(2) times out. */ static void check_auditpipe(struct pollfd fd[], const char *auditregex, FILE *pipestream) { struct timespec currtime, endtime, timeout; /* Set the expire time for poll(2) while waiting for syscall audit */ ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC, &endtime)); endtime.tv_sec += 10; timeout.tv_nsec = endtime.tv_nsec; for (;;) { /* Update the time left for auditpipe to return any event */ ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC, &currtime)); timeout.tv_sec = endtime.tv_sec - currtime.tv_sec; switch (ppoll(fd, 1, &timeout, NULL)) { /* ppoll(2) returns, check if it's what we want */ case 1: if (fd[0].revents & POLLIN) { if (get_records(auditregex, pipestream)) return; } else { atf_tc_fail("Auditpipe returned an " "unknown event %#x", fd[0].revents); } break; /* poll(2) timed out */ case 0: atf_tc_fail("%s not found in auditpipe within the " "time limit", auditregex); break; /* poll(2) standard error */ case -1: atf_tc_fail("Poll: %s", strerror(errno)); break; default: atf_tc_fail("Poll returned too many file descriptors"); } } }
/* Thread to handle SIGHUP, SIGTERM, and new connections on listen ports. */ static void * _service_loop (void *arg) { sigset_t sigs; int i; sigfillset (&sigs); sigdelset (&sigs, SIGHUP); sigdelset (&sigs, SIGTERM); sigdelset (&sigs, SIGUSR1); switch (ss.mode) { case SRV_FILEDES: diod_sock_startfd (ss.srv, ss.rfdno, ss.wfdno, "stdin"); break; case SRV_NORMAL: case SRV_SOCKTEST: break; } while (!ss.shutdown) { if (ss.reload) { diod_conf_init_config_file (NULL); np_usercache_flush (ss.srv); ss.reload = 0; } for (i = 0; i < ss.nfds; i++) { ss.fds[i].events = POLLIN; ss.fds[i].revents = 0; } if (ppoll (ss.fds, ss.nfds, NULL, &sigs) < 0) { if (errno == EINTR) continue; err_exit ("ppoll"); } for (i = 0; i < ss.nfds; i++) { if ((ss.fds[i].revents & POLLIN)) { diod_sock_accept_one (ss.srv, ss.fds[i].fd); } } } return NULL; }
bool Watchdog::WatchdogTask::Execute() { // All watchdog threads share the need to sleep for m_interval usec, with // the ability for this to be interrupted early to speed up program exit. // // Use ppoll() rather than SystemTimeSource::SleepUsecRelative(m_interval) // so the stop message pipe can be monitored, permitting the interruption // of long timing intervals to facilitate program shutdown. struct pollfd fds; struct timespec ts; fds.fd = stop_msg_pipe[0]; fds.events = POLLIN; ts.tv_sec = (m_interval / 1000000); ts.tv_nsec = (m_interval % 1000000) * 1000; if (ppoll(&fds, 1, &ts, NULL)==1 && fds.revents!=0) { debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) watchdog %p received request to stop\n", this, &m_parent); return false; } return true; }
bool LinuxIPCHost::EventLoop() { while (true) { int status = TEMP_FAILURE_RETRY(ppoll(pfds_.data(), pfds_.size(), nullptr, nullptr)); if (status < 1) { LOG_ERROR(LOG_TAG, "ppoll error"); return false; } if (pfds_[kFdIpc].revents && !OnMessage()) { return false; } if (pfds_.size() == kPossibleFds && pfds_[kFdGatt].revents && !OnGattWrite()) { return false; } } return true; }
static void pollctl(void) { int r; struct pollfd pfd; struct timespec pts; struct timespec* ppts; pfd.fd = initctlfd; pfd.events = POLLIN; if(timetowait >= 0) { pts.tv_sec = timetowait; pts.tv_nsec = 0; ppts = &pts; } else { ppts = NULL; } r = ppoll(&pfd, 1, ppts, &defsigset); if(r < 0 && errno != EINTR) { /* Failed ppoll means the main loop becomes unconstrained, making init uncontrollable and wasting cpu cycles. To avoid that, let's try to slow things down a bit. */ warn("poll failed: %m"); sigset_t cursigset; pts.tv_sec = timetowait >= 0 ? timetowait : 1; pts.tv_nsec = 0; /* ppoll also handles sigmask-lifting, try to work around that */ sigprocmask(SIG_SETMASK, &defsigset, &cursigset); nanosleep(&pts, NULL); sigprocmask(SIG_SETMASK, &cursigset, NULL); /* EINTR, on the other hand, is totally ok (SIGCHLD etc) */ } else if(r > 0) { /* only one fd in pfd, so not that much choice here */ state |= S_INITCTL; } }
void event_sdl_watch_thread (GPtrArray *watch_list) { struct pollfd *pfds = g_new0 (struct pollfd, watch_list->len); struct event_watch *ew; int ret; int idx; for (idx = 0; idx < watch_list->len; idx++ ) { ew = g_ptr_array_index (watch_list, idx); g_memmove (&pfds[idx], ew->pfd, sizeof(struct pollfd)); } while ((ret = ppoll(pfds, watch_list->len, NULL, NULL)) > 0) { for (idx = 0; idx < watch_list->len; idx++ ) { if (pfds[idx].revents == pfds[idx].events) { /* The requested event happened, notify mainloop! */ ew = g_ptr_array_index (watch_list, idx); dbg(lvl_debug,"watch(%p) event(%d) encountered\n", ew, pfds[idx].revents); SDL_Event event; SDL_UserEvent userevent; userevent.type = SDL_USEREVENT; userevent.code = SDL_USEREVENT_CODE_WATCH; userevent.data1 = ew->cb; userevent.data2 = NULL; event.type = SDL_USEREVENT; event.user = userevent; SDL_PushEvent (&event); } } } g_free(pfds); pthread_exit(0); }
void process_dns_results(void) { send_unsent_ADNS_queries(); while(adns_any_in_flight()) { struct pollfd one; struct timespec waiting; int n; one.fd = adns_afd; one.events = POLLIN; waiting.tv_sec = 30; waiting.tv_nsec= 0; n = ppoll(&one, 1, &waiting, NULL); if(n==1 && one.revents & POLLIN) { handle_adns_answer(); } else { DBG_log("poll failed with: %d", n); exit(5); } send_unsent_ADNS_queries(); } }
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 int main_loop(int listenfd) { int to, cnt, i, dto; struct fdlist pollfds; struct timespec tspec; sigset_t empty_sigset; sigemptyset(&empty_sigset); // unmask all signals fdlist_create(&pollfds); while(!should_exit) { usbmuxd_log(LL_FLOOD, "main_loop iteration"); to = usb_get_timeout(); usbmuxd_log(LL_FLOOD, "USB timeout is %d ms", to); dto = device_get_timeout(); usbmuxd_log(LL_FLOOD, "Device timeout is %d ms", dto); if(dto < to) to = dto; fdlist_reset(&pollfds); fdlist_add(&pollfds, FD_LISTEN, listenfd, POLLIN); usb_get_fds(&pollfds); client_get_fds(&pollfds); usbmuxd_log(LL_FLOOD, "fd count is %d", pollfds.count); tspec.tv_sec = to / 1000; tspec.tv_nsec = (to % 1000) * 1000000; cnt = ppoll(pollfds.fds, pollfds.count, &tspec, &empty_sigset); usbmuxd_log(LL_FLOOD, "poll() returned %d", cnt); if(cnt == -1) { if(errno == EINTR) { if(should_exit) { usbmuxd_log(LL_INFO, "Event processing interrupted"); break; } if(should_discover) { should_discover = 0; usbmuxd_log(LL_INFO, "Device discovery triggered"); usb_discover(); } } } else if(cnt == 0) { if(usb_process() < 0) { usbmuxd_log(LL_FATAL, "usb_process() failed"); fdlist_free(&pollfds); return -1; } device_check_timeouts(); } else { int done_usb = 0; for(i=0; i<pollfds.count; i++) { if(pollfds.fds[i].revents) { if(!done_usb && pollfds.owners[i] == FD_USB) { if(usb_process() < 0) { usbmuxd_log(LL_FATAL, "usb_process() failed"); fdlist_free(&pollfds); return -1; } done_usb = 1; } if(pollfds.owners[i] == FD_LISTEN) { if(client_accept(listenfd) < 0) { usbmuxd_log(LL_FATAL, "client_accept() failed"); fdlist_free(&pollfds); return -1; } } if(pollfds.owners[i] == FD_CLIENT) { client_process(pollfds.fds[i].fd, pollfds.fds[i].revents); } } } } } fdlist_free(&pollfds); return 0; }
ts = NULL; else { usec_t nw; nw = now(CLOCK_MONOTONIC); if (t > nw) t -= nw; else t = 0; ts = timespec_store(&_ts, t); } { struct pollfd p[3] = { {.fd = fd, .events = events_a, }, {.fd = STDIN_FILENO, .events = events_b & POLLIN, }, {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }}; r = ppoll(p, ELEMENTSOF(p), ts, NULL); } if (r < 0) { log_error("ppoll() failed: %m"); goto finish; } } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int run_tunnel(struct args *args, sigset_t *orig_mask) { char device[IFNAMSIZ]; int fd = create_tap(args->iface, device, args->mtu); if (fd < 0) { fprintf(stderr, "unable to create tap device\n"); return 1; } printf("tap device is: %s\n", device); if (args->up_script) { int ret = run_updown(args->up_script, device); if (ret != 0) { fprintf(stderr, "up script exited with status: %d\n", ret); return 1; } } // TODO: make the port and bind address configurable int sockfd = setup_socket(inet_addr("0.0.0.0"), 1234); if (sockfd < 0) { fprintf(stderr, "unable to create socket\n"); return 1; } if (drop_privileges(args->uid, args->gid) != 0) { fprintf(stderr, "couldn't drop privileges\n"); return 1; } // circular queues struct frame recv_queue[RECV_QUEUE] = {0}; size_t recv_idx = 0; size_t recv_len = 0; struct frame send_queue[SEND_QUEUE] = {0}; size_t send_idx = 0; size_t send_len = 0; struct timespec tm; memset(&tm, 0, sizeof tm); tm.tv_nsec = 10000000; // 0.01 seconds struct pollfd fds[2]; memset(&fds, 0, sizeof fds); fds[0].fd = fd; fds[1].fd = sockfd; struct sockaddr_in remote; memset(&remote, 0, sizeof remote); char has_remote = 0; if (args->remote) { remote.sin_family = AF_INET; remote.sin_port = htons(1234); has_remote = 1; remote.sin_addr.s_addr = inet_addr(args->remote); if (remote.sin_addr.s_addr == INADDR_NONE) { fprintf(stderr, "failed to parse remote: %s\n", args->remote); return 2; } fprintf(stderr, "running in client mode with remote: %s\n", args->remote); } fprintf(stderr, "tunnel is up\n"); for (;;) { fds[0].events = POLLIN; if (recv_len > 0) { fds[0].events |= POLLOUT; } fds[1].events = POLLIN; if (send_len > 0 && has_remote) { fds[1].events |= POLLOUT; } int result = ppoll(fds, 2, &tm, orig_mask); if (result < 0) { if (errno != EINTR) { perror("ppoll"); return 3; } } if (exit_wanted) { fprintf(stderr, "\nreceived signal %d, stopping tunnel\n", received_signal); break; } // tap can handle a write if (fds[0].revents & POLLOUT) { struct frame *f = &recv_queue[recv_idx]; assert(f->len <= args->mtu + ETHERNET_HEADER); recv_idx = (recv_idx + 1) % RECV_QUEUE; recv_len -= 1; ssize_t n = write(fd, f->data, f->len); if (n < 0) { if (errno == EINVAL) { fprintf(stderr, "received garbage frame\n"); } else { perror("write"); return 4; } } else if (n < f->len) { printf("[error] only wrote %zd bytes to tap (out of %zd bytes)\n", n, f->len); } } // udp socket can handle a write if (fds[1].revents & POLLOUT) { struct frame *f = &send_queue[send_idx]; assert(f->len <= args->mtu + ETHERNET_HEADER); send_idx = (send_idx + 1) % SEND_QUEUE; send_len -= 1; ssize_t n = sendto(sockfd, f->data, f->len, 0, (struct sockaddr *) &remote, sizeof remote); if (n < 0) { perror("sendto"); return 4; } else if (n < f->len) { printf("[error] only sent %zd bytes to peer (out of %zd bytes)\n", n, f->len); } } // tap has data for us to read if (fds[0].revents & POLLIN) { size_t idx = (send_idx + send_len) % SEND_QUEUE; if (send_len < SEND_QUEUE) { send_len += 1; } else { assert(send_len == SEND_QUEUE); printf("dropping frame from send queue\n"); // put this packet at the end of the queue; // drop the first frame in the queue send_idx += 1; } struct frame *f = &send_queue[idx]; memset(f, 0, sizeof(struct frame)); ssize_t n = read(fd, &f->data, args->mtu + ETHERNET_HEADER); f->len = n; } // udp socket has data for us to read if (fds[1].revents & POLLIN) { size_t idx = (recv_idx + recv_len) % RECV_QUEUE; if (recv_len < RECV_QUEUE) { recv_len += 1; } else { assert(recv_len == RECV_QUEUE); printf("dropping frame from recv queue\n"); // put this packet at the end of the queue; // drop the first frame in the queue recv_idx += 1; } struct frame *f = &recv_queue[idx]; memset(f, 0, sizeof(struct frame)); // TODO: handle case where remote changes, in both server+client mode socklen_t l = sizeof(remote); has_remote = 1; ssize_t n = recvfrom( sockfd, &f->data, args->mtu + ETHERNET_HEADER, 0, (struct sockaddr *) &remote, &l ); f->len = n; } } if (args->down_script) { int ret = run_updown(args->down_script, device); if (ret != 0) { fprintf(stderr, "down script exited with status: %d\n", ret); return 1; } } return 0; }
static void* reader_thread(void* dontcare) { char token = '!'; int sock = sockfds[1]; struct timeval ts; char c = '\0'; int i; gettimeofday(&ts, NULL); atomic_puts("r: acquiring mutex ..."); pthread_mutex_lock(&lock); atomic_puts("r: ... releasing mutex"); pthread_mutex_unlock(&lock); for (i = 0; i < 2; ++i) { atomic_puts("r: reading socket ..."); gettimeofday(&ts, NULL); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } /* TODO: readv() support */ atomic_puts("r: recv'ing socket ..."); gettimeofday(&ts, NULL); test_assert(1 == recv(sock, &c, sizeof(c), 0)); atomic_printf("r: ... recv'd '%c'\n", c); test_assert(c == token); ++token; atomic_puts("r: recvfrom'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, NULL, NULL)); atomic_printf("r: ... recvfrom'd '%c'\n", c); test_assert(c == token); ++token; { struct sockaddr_un addr; socklen_t addrlen = sizeof(addr); atomic_puts("r: recvfrom(&sock)'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, &addr, &addrlen)); atomic_printf("r: ... recvfrom'd '%c' from sock len:%d\n", c, addrlen); test_assert(c == token); /* socketpair() AF_LOCAL sockets don't identify * themselves. */ test_assert(addrlen == 0); ++token; } { struct mmsghdr mmsg = { { 0 } }; struct iovec data = { 0 }; int magic = ~msg_magic; int err, ret; data.iov_base = &magic; data.iov_len = sizeof(magic); mmsg.msg_hdr.msg_iov = &data; mmsg.msg_hdr.msg_iovlen = 1; struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CTRLMSG_LEN); mmsg.msg_hdr.msg_control = cmptr; mmsg.msg_hdr.msg_controllen = CTRLMSG_LEN; atomic_puts("r: recvmsg with DONTWAIT ..."); ret = recvmsg(sock, &mmsg.msg_hdr, MSG_DONTWAIT); err = errno; atomic_printf("r: ... returned %d (%s/%d)\n", ret, strerror(err), err); test_assert(-1 == ret); test_assert(EWOULDBLOCK == err); test_assert(mmsg.msg_hdr.msg_iov == &data); atomic_puts("r: recmsg'ing socket ..."); test_assert(0 < recvmsg(sock, &mmsg.msg_hdr, 0)); atomic_printf("r: ... recvmsg'd 0x%x\n", magic); test_assert(msg_magic == magic); test_assert(mmsg.msg_hdr.msg_iov == &data); int fd = *(int*)CMSG_DATA(cmptr); struct stat fs_new, fs_old; fstat(fd, &fs_new); fstat(STDERR_FILENO, &fs_old); // check if control msg was send successfully test_assert( fs_old.st_dev == fs_new.st_dev && fs_old.st_ino == fs_new.st_ino && fs_old.st_uid == fs_new.st_uid && fs_old.st_gid == fs_new.st_gid && fs_old.st_rdev == fs_new.st_rdev && fs_old.st_size == fs_new.st_size); magic = ~msg_magic; atomic_puts("r: recmmsg'ing socket ..."); breakpoint(); test_assert(1 == recvmmsg(sock, &mmsg, 1, 0, NULL)); atomic_printf("r: ... recvmmsg'd 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); test_assert(mmsg.msg_hdr.msg_iov == &data); magic = ~msg_magic; #if defined(SYS_socketcall) struct recvmmsg_arg arg = { 0 }; arg.sockfd = sock; arg.msgvec = &mmsg; arg.vlen = 1; test_assert(1 == syscall(SYS_socketcall, SYS_RECVMMSG, (void*)&arg)); #elif defined(SYS_recvmmsg) test_assert(1 == syscall(SYS_recvmmsg, sock, &mmsg, 1, 0, NULL)); #else #error unable to call recvmmsg #endif atomic_printf("r: ... recvmmsg'd(by socketcall) 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); free(cmptr); } { struct msghdr msg = { 0 }; struct iovec iovs[2]; char c1 = '\0', c2 = '\0'; iovs[0].iov_base = &c1; iovs[0].iov_len = sizeof(c1); iovs[1].iov_base = &c2; iovs[1].iov_len = sizeof(c2); msg.msg_iov = iovs; msg.msg_iovlen = sizeof(iovs) / sizeof(iovs[0]); atomic_puts("r: recmsg'ing socket with two iovs ..."); test_assert(2 == recvmsg(sock, &msg, 0)); atomic_printf("r: ... recvmsg'd '%c' and '%c'\n", c1, c2); test_assert(c1 == token); token++; test_assert(c2 == token); token++; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); poll(&pfd, 1, -1); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); ppoll(&pfd, 1, NULL, NULL); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); #if defined(__i386__) struct select_arg arg = { 0 }; arg.n_fds = sock + 1; arg.read = &fds; arg.write = NULL; arg.except = NULL; arg.timeout = &tv; ret = syscall(SYS_select, &arg); #else ret = syscall(SYS_select, sock + 1, &fds, NULL, NULL, &tv); #endif atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); ret = select(sock + 1, &fds, NULL, NULL, &tv); atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { int epfd; struct epoll_event ev; atomic_puts("r: epolling socket ..."); test_assert(0 <= (epfd = epoll_create(1 /*num events*/))); ev.events = EPOLLIN; ev.data.fd = sock; gettimeofday(&ts, NULL); test_assert(0 == epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev)); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(sock == ev.data.fd); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; close(epfd); } { char* buf = (char*)malloc(num_sockbuf_bytes); ssize_t nwritten = 0; struct iovec iov; ++token; memset(buf, token, num_sockbuf_bytes); atomic_printf("r: writing outbuf of size %zd ...\n", num_sockbuf_bytes); while (nwritten < num_sockbuf_bytes) { ssize_t this_write = write(sock, buf, num_sockbuf_bytes - nwritten); atomic_printf("r: wrote %zd bytes this time\n", this_write); nwritten += this_write; } ++token; memset(buf, token, num_sockbuf_bytes); iov.iov_base = buf; iov.iov_len = num_sockbuf_bytes; atomic_printf("r: writev()ing outbuf of size %zd ...\n", num_sockbuf_bytes); while (iov.iov_len > 0) { ssize_t this_write = writev(sock, &iov, 1); atomic_printf("r: wrote %zd bytes this time\n", this_write); iov.iov_len -= this_write; } free(buf); } atomic_puts("r: reading socket with masked signals ..."); { sigset_t old_mask, mask; sigfillset(&mask); test_assert(0 == pthread_sigmask(SIG_BLOCK, &mask, &old_mask)); test_assert(1 == read(sock, &c, sizeof(c))); test_assert(0 == pthread_sigmask(SIG_SETMASK, &old_mask, NULL)); } ++token; atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); /* Make the main thread wait on our join() */ atomic_puts("r: sleeping ..."); usleep(500000); return NULL; }
void outputfd(object obj) { fds[ix].fd = $(obj, $i_Producer_fd); fds[ix].events = POLLOUT; } each_o($$lo_producers, outputfd); sigset_t allow_all; sigemptyset(&allow_all); #ifdef HAVE_PPOLL struct timespec timeout = { .tv_sec = $i_kernel_poll_duration_ms / 1000, .tv_nsec = ($i_kernel_poll_duration_ms % 1000) * 1000000L, }; int ret = ppoll(fds, fdcount, $y_kernel_poll_infinite? NULL : &timeout, &allow_all); #else // Race condition, but at worst will stall things until the next keystroke sigset_t oldsigset; sigprocmask(SIG_SETMASK, &allow_all, &oldsigset); int ret = poll(fds, fdcount, $y_kernel_poll_infinite? -1 : $i_kernel_poll_duration_ms); sigprocmask(SIG_SETMASK, &oldsigset, NULL); #endif if (ret == -1) { //Error if (errno != EINTR) perror("poll"); } else if (ret) {
/** * ソケット送受信 * * @param[in] sock ソケット * @return なし */ st_client client_loop(int sock) { int ready = 0; /* select戻り値 */ struct timespec timeout; /* タイムアウト値 */ sigset_t sigmask; /* シグナルマスク */ st_client status = EX_SUCCESS; /* ステータス */ #ifdef _USE_SELECT fd_set fds, rfds; /* selectマスク */ #else struct pollfd targets[MAX_POLL]; /* poll */ #endif /* _USE_SELECT */ dbglog("start: sock=%d", sock); if (atexit(exit_memfree)) { outlog("atexit"); return EX_FAILURE; } #ifdef _USE_SELECT /* マスクの設定 */ FD_ZERO(&fds); /* 初期化 */ FD_SET(sock, &fds); /* ソケットをマスク */ FD_SET(STDIN_FILENO, &fds); /* 標準入力をマスク */ #endif /* _USE_SELECT */ /* シグナルマスクの取得 */ sigmask = get_sigmask(); /* タイムアウト値初期化 */ (void)memset(&timeout, 0, sizeof(struct timespec)); timeout.tv_sec = 1; /* 1秒 */ timeout.tv_nsec = 0; do { #ifdef _USE_SELECT (void)memcpy(&rfds, &fds, sizeof(fd_set)); /* マスクコピー */ ready = pselect(sock + 1, &rfds, NULL, NULL, &timeout, &sigmask); #else targets[STDIN_POLL].fd = STDIN_FILENO; targets[STDIN_POLL].events = POLLIN; targets[SOCK_POLL].fd = sock; targets[SOCK_POLL].events = POLLIN; ready = ppoll(targets, MAX_POLL, &timeout, &sigmask); #endif /* _USE_SELECT */ if (ready < 0) { if (errno == EINTR) /* 割り込み */ break; /* selectエラー */ outlog("select=%d", ready); return EX_FAILURE; } else if (ready) { #ifdef _USE_SELECT if (FD_ISSET(STDIN_FILENO, &fds)) { /* 標準入力レディ */ status = send_sock(sock); if (status == EX_EMPTY) continue; if (status) return status; } if (FD_ISSET(sock, &fds)) { /* ソケットレディ */ status = read_sock(sock); if (status) return status; } #else if (targets[STDIN_POLL].revents & POLLIN) { /* 標準入力レディ */ status = send_sock(sock); if (status == EX_EMPTY) continue; if (status) return status; } if (targets[SOCK_POLL].revents & POLLIN) { /* ソケットレディ */ status = read_sock(sock); if (status) return status; } #endif /* _USE_SELECT */ } else { /* タイムアウト */ continue; } } while (!g_sig_handled); return EX_SIGNAL; }
static void* reader_thread(void* dontcare) { char token = '!'; int sock = sockfds[1]; struct timeval ts; char c = '\0'; int i; gettimeofday(&ts, NULL); atomic_puts("r: acquiring mutex ..."); pthread_mutex_lock(&lock); atomic_puts("r: ... releasing mutex"); pthread_mutex_unlock(&lock); for (i = 0; i < 2; ++i) { atomic_puts("r: reading socket ..."); gettimeofday(&ts, NULL); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } /* TODO: readv() support */ atomic_puts("r: recv'ing socket ..."); gettimeofday(&ts, NULL); test_assert(1 == recv(sock, &c, sizeof(c), 0)); atomic_printf("r: ... recv'd '%c'\n", c); test_assert(c == token); ++token; atomic_puts("r: recvfrom'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, NULL, NULL)); atomic_printf("r: ... recvfrom'd '%c'\n", c); test_assert(c == token); ++token; { struct sockaddr_un addr; socklen_t addrlen = sizeof(addr); atomic_puts("r: recvfrom(&sock)'ing socket ..."); test_assert(1 == recvfrom(sock, &c, sizeof(c), 0, &addr, &addrlen)); atomic_printf("r: ... recvfrom'd '%c' from sock len:%d\n", c, addrlen); test_assert(c == token); /* socketpair() AF_LOCAL sockets don't identify * themselves. */ test_assert(addrlen == 0); ++token; } { struct mmsghdr mmsg = {{ 0 }}; struct iovec data = { 0 }; int magic = ~msg_magic; int err, ret; data.iov_base = &magic; data.iov_len = sizeof(magic); mmsg.msg_hdr.msg_iov = &data; mmsg.msg_hdr.msg_iovlen = 1; atomic_puts("r: recvmsg with DONTWAIT ..."); ret = recvmsg(sock, &mmsg.msg_hdr, MSG_DONTWAIT); err = errno; atomic_printf("r: ... returned %d (%s/%d)\n", ret, strerror(err), err); test_assert(-1 == ret && EWOULDBLOCK == err); atomic_puts("r: recmsg'ing socket ..."); test_assert(0 < recvmsg(sock, &mmsg.msg_hdr, 0)); atomic_printf("r: ... recvmsg'd 0x%x\n", magic); test_assert(msg_magic == magic); magic = ~msg_magic; atomic_puts("r: recmmsg'ing socket ..."); pthread_barrier_wait(&cheater_barrier); breakpoint(); test_assert(1 == recvmmsg(sock, &mmsg, 1, 0, NULL)); atomic_printf("r: ... recvmmsg'd 0x%x (%u bytes)\n", magic, mmsg.msg_len); test_assert(msg_magic == magic); } { struct msghdr msg = { 0 }; struct iovec iovs[2]; char c1 = '\0', c2 = '\0'; iovs[0].iov_base = &c1; iovs[0].iov_len = sizeof(c1); iovs[1].iov_base = &c2; iovs[1].iov_len = sizeof(c2); msg.msg_iov = iovs; msg.msg_iovlen = sizeof(iovs) / sizeof(iovs[0]); atomic_puts("r: recmsg'ing socket with two iovs ..."); test_assert(2 == recvmsg(sock, &msg, 0)); atomic_printf("r: ... recvmsg'd '%c' and '%c'\n", c1, c2); test_assert(c1 == token); token++; test_assert(c2 == token); token++; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); poll(&pfd, 1, -1); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { struct pollfd pfd; atomic_puts("r: polling socket ..."); pfd.fd = sock; pfd.events = POLLIN; gettimeofday(&ts, NULL); ppoll(&pfd, 1, NULL, NULL); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { fd_set fds; const struct timeval infinity = { 1 << 30, 0 }; struct timeval tv = infinity; int ret; atomic_puts("r: select()ing socket ..."); FD_ZERO(&fds); FD_SET(sock, &fds); ret = select(sock + 1, &fds, NULL, NULL, &tv); atomic_printf("r: ... returned %d; tv { %ld, %ld }\n", ret, tv.tv_sec, tv.tv_usec); test_assert(1 == ret); test_assert(FD_ISSET(sock, &fds)); test_assert(0 < tv.tv_sec && tv.tv_sec < infinity.tv_sec); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; } { int epfd; struct epoll_event ev; atomic_puts("r: epolling socket ..."); test_assert(0 <= (epfd = epoll_create(1/*num events*/))); ev.events = EPOLLIN; ev.data.fd = sock; gettimeofday(&ts, NULL); test_assert(0 == epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev)); test_assert(1 == epoll_wait(epfd, &ev, 1, -1)); atomic_puts("r: ... done, doing nonblocking read ..."); test_assert(sock == ev.data.fd); test_assert(1 == read(sock, &c, sizeof(c))); atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); ++token; close(epfd); } { char* buf = (char*)malloc(num_sockbuf_bytes); ssize_t nwritten = 0; struct iovec iov; ++token; memset(buf, token, num_sockbuf_bytes); atomic_printf("r: writing outbuf of size %d ...\n", num_sockbuf_bytes); while (nwritten < num_sockbuf_bytes) { ssize_t this_write = write(sock, buf, num_sockbuf_bytes - nwritten); atomic_printf("r: wrote %d bytes this time\n", this_write); nwritten += this_write; } ++token; memset(buf, token, num_sockbuf_bytes); iov.iov_base = buf; iov.iov_len = num_sockbuf_bytes; atomic_printf("r: writev()ing outbuf of size %d ...\n", num_sockbuf_bytes); while (iov.iov_len > 0) { ssize_t this_write = writev(sock, &iov, 1); atomic_printf("r: wrote %d bytes this time\n", this_write); iov.iov_len -= this_write; } free(buf); } atomic_puts("r: reading socket with masked signals ..."); { sigset_t old_mask, mask; sigfillset(&mask); test_assert(0 == pthread_sigmask(SIG_BLOCK, &mask, &old_mask)); test_assert(1 == read(sock, &c, sizeof(c))); test_assert(0 == pthread_sigmask(SIG_SETMASK, &old_mask, NULL)); } ++token; atomic_printf("r: ... read '%c'\n", c); test_assert(c == token); /* Make the main thread wait on our join() */ atomic_puts("r: sleeping ..."); usleep(500000); return NULL; }
int main(int argc, char **argv) { int n; /* Poll array: * 0 - server_fd * 1 - pipein_fd * 2 - client_fd (if any) */ struct pollfd fds[3]; int nfds = 3; sigset_t sigmask; sigset_t sigmask_orig; struct sigaction act; int c; while ((c = getopt(argc, argv, "v:")) != -1) { switch (c) { case 'v': verbose = atoi(optarg); break; default: fprintf(stderr, "%s [-v 0-3]\n", argv[0]); return 1; } } /* Termination signal handler. */ memset(&act, 0, sizeof(act)); act.sa_handler = signal_handler; if (sigaction(SIGHUP, &act, 0) < 0 || sigaction(SIGINT, &act, 0) < 0 || sigaction(SIGTERM, &act, 0) < 0) { syserror("sigaction error."); return 2; } /* Ignore SIGPIPE in all cases: it may happen, since we write to pipes, but * it is not fatal. */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGPIPE); if (sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0) { syserror("sigprocmask error."); return 2; } /* Ignore terminating signals, except when ppoll is running. Save current * mask in sigmask_orig. */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGHUP); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); if (sigprocmask(SIG_BLOCK, &sigmask, &sigmask_orig) < 0) { syserror("sigprocmask error."); return 2; } /* Prepare pollfd structure. */ memset(fds, 0, sizeof(fds)); fds[0].events = POLLIN; fds[1].events = POLLIN; fds[2].events = POLLIN; /* Initialise pipe and WebSocket server */ socket_server_init(PORT); pipe_init(); while (!terminate) { /* Make sure fds is up to date. */ fds[0].fd = server_fd; fds[1].fd = pipein_fd; fds[2].fd = client_fd; /* Only handle signals in ppoll: this makes sure we complete processing * the current request before bailing out. */ n = ppoll(fds, nfds, NULL, &sigmask_orig); log(3, "poll ret=%d (%d, %d, %d)\n", n, fds[0].revents, fds[1].revents, fds[2].revents); if (n < 0) { /* Do not print error when ppoll is interupted by a signal. */ if (errno != EINTR || verbose >= 1) syserror("ppoll error."); break; } if (fds[0].revents & POLLIN) { log(1, "WebSocket accept."); socket_server_accept(VERSION); n--; } if (fds[1].revents & POLLIN) { log(2, "Pipe fd ready."); pipein_read(); n--; } if (fds[2].revents & POLLIN) { log(2, "Client fd ready."); socket_client_read(); n--; } if (n > 0) { /* Some events were not handled, this is a problem */ error("Some poll events could not be handled: " "ret=%d (%d, %d, %d).", n, fds[0].revents, fds[1].revents, fds[2].revents); break; } } log(1, "Terminating..."); if (client_fd) socket_client_close(1); return 0; }
int main(int argc, char *argv[]) { struct pollfd p[3]; struct timespec timeout; struct device_settings settings; struct sigaction sa; sigset_t sigs; short events; if (argc < 3) { std::cout << "Running " << argv[0] << " requires 'sixad'. Please run sixad instead" << std::endl; return 1; } const char *mac = argv[1]; debug = atoi(argv[2]); open_log("sixad-remote"); settings = init_values(mac); settings.joystick.axis = false; settings.joystick.sbuttons = false; settings.joystick.accel = false; settings.joystick.speed = false; settings.joystick.pos = false;; settings.led.enabled = false; settings.rumble.enabled = false; ufd = uinput_open(DEV_TYPE_REMOTE, mac, settings); if (ufd->js < 0 || ufd->mk < 0) { return 1; } else if (ufd->js == 0 && ufd->mk == 0) { syslog(LOG_ERR, "remote config has no joystick or input mode selected - please choose one!"); return 1; } int modes = 0; if (settings.remote.numeric) modes |= REMOTE_KEYMODE_NUMBERIC; if (settings.remote.dvd) modes |= REMOTE_KEYMODE_DVD; if (settings.remote.directional) modes |= REMOTE_KEYMODE_DIRECTIONAL; if (settings.remote.multimedia) modes |= REMOTE_KEYMODE_MULTIMEDIA; sigfillset(&sigs); // sigdelset(&sigs, SIGCHLD); // sigdelset(&sigs, SIGPIPE); // sigdelset(&sigs, SIGTERM); // sigdelset(&sigs, SIGINT); // sigdelset(&sigs, SIGHUP); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); if (debug) syslog(LOG_INFO, "Press any to activate"); p[0].fd = 0; p[0].events = POLLIN | POLLERR | POLLHUP; p[1].fd = 1; p[1].events = POLLIN | POLLERR | POLLHUP; p[2].fd = ufd->mk ? ufd->mk : ufd->js; p[2].events = POLLIN | POLLERR | POLLHUP; while (!io_canceled()) { int i, idx = 3; for (i = 0; i < idx; i++) p[i].revents = 0; timeout.tv_sec = 1; timeout.tv_nsec = 0; if (ppoll(p, idx, &timeout, &sigs) < 1) continue; if (p[1].revents & POLLIN) { process_remote(settings, mac, modes); } events = p[0].revents | p[1].revents | p[2].revents; if (events & (POLLERR | POLLHUP)) { break; } } if (debug) syslog(LOG_INFO, "Closing uinput..."); if (settings.joystick.enabled) { uinput_close(ufd->js, debug); } if (settings.remote.enabled || settings.input.enabled) { uinput_close(ufd->mk, debug); } delete ufd; shutdown(isk, SHUT_RDWR); shutdown(csk, SHUT_RDWR); if (debug) syslog(LOG_INFO, "Done"); return 0; }
int main(int argc, char **argv) { struct tcmulib_context *tcmulib_ctx; struct pollfd pollfds[16]; int i; int ret; if (tcmu_setup_log()) { fprintf(stderr, "Could not setup tcmu logger.\n"); exit(1); } /* If any TCMU devices that exist that match subtype, handler->added() will now be called from within tcmulib_initialize(). */ tcmulib_ctx = tcmulib_initialize(&foo_handler, 1); if (tcmulib_ctx <= 0) { tcmu_err("tcmulib_initialize failed with %p\n", tcmulib_ctx); exit(1); } while (1) { pollfds[0].fd = tcmulib_get_master_fd(tcmulib_ctx); pollfds[0].events = POLLIN; pollfds[0].revents = 0; for (i = 0; i < dev_array_len; i++) { pollfds[i+1].fd = tcmu_get_dev_fd(tcmu_dev_array[i]); pollfds[i+1].events = POLLIN; pollfds[i+1].revents = 0; } /* Use ppoll instead poll to avoid poll call reschedules during signal * handling. If we were removing a device, then the uio device's memory * could be freed, but the poll would be rescheduled and end up accessing * the released device. */ ret = ppoll(pollfds, dev_array_len+1, NULL, NULL); if (ret == -1) { tcmu_err("ppoll() returned %d, exiting\n", ret); exit(EXIT_FAILURE); } if (pollfds[0].revents) { /* If any tcmu devices have been added or removed, the added() and removed() handler callbacks will be called from within this. */ tcmulib_master_fd_ready(tcmulib_ctx); /* Since devices (may) have changed, re-poll() instead of processing per-device fds. */ continue; } for (i = 0; i < dev_array_len; i++) { if (pollfds[i+1].revents) { struct tcmulib_cmd *cmd; struct tcmu_device *dev = tcmu_dev_array[i]; tcmulib_processing_start(dev); while ((cmd = tcmulib_get_next_command(dev)) != NULL) { ret = foo_handle_cmd(dev, cmd->cdb, cmd->iovec, cmd->iov_cnt, cmd->sense_buf); tcmulib_command_complete(dev, cmd, ret); } tcmulib_processing_complete(dev); } } } return 0; }
void *tx_data_handler(void *arg) { int sock_client = sock_thread[3]; struct pollfd pfd = {sock_client, POLLIN, 0}; struct timespec timeout; useconds_t delay; int result, position, limit, offset; ssize_t size, rest; char buffer[5003]; memset(tx_data, 0, 8192); limit = 1024; rest = 0; while(1) { delay = *tx_rate * 2; timeout.tv_sec = 0; timeout.tv_nsec = delay * 1000; result = ppoll(&pfd, 1, &timeout, NULL); if(result < 0) break; /* read ram reader position */ position = *tx_cntr; /* receive 4096 bytes if ready, otherwise sleep */ if((limit > 0 && position > limit) || (limit == 0 && position < 1024)) { offset = limit > 0 ? 0 : 4096; limit = limit > 0 ? 0 : 1024; if(result == 0) { memset(tx_data + offset, 0, 4096); continue; } if((size = recv(sock_client, buffer, 4096 + rest, 0)) <= 0) break; if(size == 4096 + rest) { memcpy(tx_data + offset, buffer + rest, 4096); rest = 0; } else { memset(tx_data + offset, 0, 4096); rest = abs(rest - size) & 7; } } else { usleep(delay); } } memset(tx_data, 0, 8192); close(sock_client); sock_thread[3] = -1; return NULL; }
// Get a RX frame U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_RX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Getting RX frame; invalid arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if (rawsock->buffersOut >= rawsock->frameCount) { AVB_LOG_ERROR("Too many RX buffers in use"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Get pointer to active buffer in ring volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize; AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p", rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut, pBuffer, pHdr); // Check if buffer ready for user // In receive mode, we want TP_STATUS_USER flag set if ((pHdr->tp_status & TP_STATUS_USER) == 0) { struct timespec ts, *pts = NULL; struct pollfd pfd; // Use poll to wait for "ready to read" condition // Poll even if our timeout is 0 - to catch the case where // kernel is writing to the wrong slot (see below.) if (timeout != OPENAVB_RAWSOCK_BLOCK) { ts.tv_sec = timeout / MICROSECONDS_PER_SECOND; ts.tv_nsec = (timeout % MICROSECONDS_PER_SECOND) * NANOSECONDS_PER_USEC; pts = &ts; } pfd.fd = rawsock->sock; pfd.events = POLLIN; pfd.revents = 0; int ret = ppoll(&pfd, 1, pts, NULL); if (ret < 0) { if (errno != EINTR) { AVB_LOGF_ERROR("Getting RX frame; poll failed: %s", strerror(errno)); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pfd.revents & POLLIN) == 0) { // timeout AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pHdr->tp_status & TP_STATUS_USER) == 0) { // Hmmm, this is unexpected. poll indicated that the // socket was ready to read, but the slot in the TX ring // that we're looking for the kernel to fill isn't filled. // If there aren't any RX buffers held by the application, // we can try to fix this sticky situation... if (rawsock->buffersOut == 0) { // Scan forward through the RX ring, and look for a // buffer that's ready for us to read. The kernel has // a bad habit of not starting at the beginning of the // ring when the listener process is restarted. int nSkipped = 0; while((pHdr->tp_status & TP_STATUS_USER) == 0) { // Move to next slot in ring. // (Increment buffer/block indexes) if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Adjust pHdr, pBuffer to point to the new slot pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); pBuffer = (U8*)pHdr + rawsock->bufHdrSize; // If we've scanned all the way around the ring, bail out. if (++nSkipped > rawsock->frameCount) { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } // We found a slot that's ready. Hopefully, we're good now. AVB_LOGF_WARNING("Getting RX frame; skipped %d empty slots (rawsock=%p)", nSkipped, rawsock); } else { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } } AVB_LOGF_VERBOSE("Buffer status=0x%4.4lx", (unsigned long)pHdr->tp_status); if (pHdr->tp_status & TP_STATUS_COPY) { AVB_LOG_WARNING("Frame too big for receive buffer"); } // Check the "losing" flag. That indicates that the ring is full, // and the kernel had to toss some frames. There is no "winning" flag. if ((pHdr->tp_status & TP_STATUS_LOSING)) { if (!rawsock->bLosing) { AVB_LOG_WARNING("Getting RX frame; mmap buffers full"); rawsock->bLosing = TRUE; } } else { rawsock->bLosing = FALSE; } // increment indexes for next time if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Remember that the client has another buffer rawsock->buffersOut += 1; if (pHdr->tp_snaplen < pHdr->tp_len) { #if (AVB_LOG_LEVEL >= AVB_LOG_LEVEL_VERBOSE) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_LOG_BUFFER(AVB_LOG_LEVEL_VERBOSE, (const U8 *) pBuffer + (pHdr->tp_mac - rawsock->bufHdrSize), pHdr->tp_len, 16); #else IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); #endif ringRawsockRelRxFrame(rawsock, (U8*)pBuffer); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Return pointer to the buffer and length *offset = pHdr->tp_mac - rawsock->bufHdrSize; *len = pHdr->tp_snaplen; AVB_LOGF_VERBOSE("Good RX frame (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return (U8*)pBuffer; }