#include #include #include #include "selectops.h" #include "babd.h" #include "link.h" static int bab_maxfd = -1; static fd_set rfds; static fd_set wfds; int use_epoll = 1; int epoll_fd = -1; inline void SelectEventHandler::touch_fd(int fd) { if (-1 == fd_used) fd_used = fd; else if (fd_used != fd) scan_all = 1; if (fd > bab_maxfd) bab_maxfd = fd; } static int select_poll_core(struct timeval *tv) { int maxfd = 0, i; for (i=0; i<=bab_maxfd; i++) { if (selectObjs[0][i]) FD_SET(i, &rfds); if (selectObjs[1][i]) FD_SET(i, &wfds); } maxfd = i; maxfd = select(maxfd, &rfds, &wfds, NULL, tv); if (maxfd < 0) { if (EINTR == errno) return 1; perror("select"); return 1; } for (i=0; i<=bab_maxfd; i++) { if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) maxfd--; if (FD_ISSET(i, &rfds) && selectObjs[0][i]) selectObjs[0][i]->SelectEvent(i, SEL_READ); if (FD_ISSET(i, &wfds) && selectObjs[1][i]) selectObjs[1][i]->SelectEvent(i, SEL_WRITE); } return 0; } static int epoll_poll_core(struct timeval *tv) { #define MAX_EPOLL_EVENTS 1000 struct epoll_event events[MAX_EPOLL_EVENTS]; int timeout; int nr; if (tv->tv_sec > 65) timeout = 65000; else timeout = tv->tv_sec * 1000 + (tv->tv_usec / 1000); nr = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout); if (nr == -1) { if (errno == EINTR) return 1; perror("epoll_wait"); return 1; } for (int i=0; ievents & (EPOLLIN | EPOLLERR)) && selectObjs[0][ev->data.fd]) selectObjs[0][ev->data.fd]->SelectEvent(ev->data.fd, SEL_READ); if ((ev->events & EPOLLOUT) && selectObjs[1][ev->data.fd]) selectObjs[1][ev->data.fd]->SelectEvent(ev->data.fd, SEL_WRITE); } return 0; } void bab_poll(void) { struct timeval tv; killIfaces(); do_hangups(); killIfaces(); FD_ZERO(&rfds); FD_ZERO(&wfds); again: tv = timer_getdelay(); if (use_epoll) { if (epoll_poll_core(&tv)) goto again; } else { if (select_poll_core(&tv)) goto again; } killIfaces(); do_hangups(); killIfaces(); timer_run(); killIfaces(); do_hangups(); } SelectEventHandler::SelectEventHandler() { scan_all = 0; fd_used = -1; } SelectEventHandler::~SelectEventHandler() { int i; if (scan_all) { for (i=0; i bab_maxfd) touch_fd(fd); if (use_epoll) { int op = had ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; if (-1 == epoll_ctl(epoll_fd, op, fd, &ev)) { perror("Set: epoll_ctl: MOD"); *(char *)0 = 0; } } return; } if (use_epoll && had && (event == SEL_NONE)) { if (-1 == epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev)) { perror("Set(none): epoll_ctl: DEL"); fprintf(stderr, "pid = %d\n", (int)getpid()); *(char *)0 = 0; } } if (fd == bab_maxfd && !selectObjs[0][fd] && !selectObjs[1][fd]) { int i; for (i=bab_maxfd-1; i>-1; i--) if (selectObjs[0][i] || selectObjs[1][i]) break; bab_maxfd = i; } } void SelectEventHandler::SelectRemoveEvent(int fd, SelectEventType event) { int removed_read = 0, removed_write = 0; if (event & SEL_READ) { if (selectObjs[0][fd]) removed_read = 1; selectObjs[0][fd] = 0; } if (event & SEL_WRITE) { if (selectObjs[1][fd]) removed_write = 1; selectObjs[1][fd] = 0; } if (fd == bab_maxfd && !selectObjs[0][fd] && !selectObjs[1][fd]) { int i; for (i=bab_maxfd-1; i>-1; i--) if (selectObjs[0][i] || selectObjs[1][i]) break; bab_maxfd = i; } if (use_epoll) { struct epoll_event ev; memset(&ev, 0, sizeof ev); ev.data.fd = fd; if (selectObjs[0][fd]) ev.events |= EPOLLIN; if (selectObjs[1][fd]) ev.events |= EPOLLOUT; if (!ev.events) { if (removed_read || removed_write) { if (-1 == epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev)) { perror("Remove: epoll_ctl: DEL"); *(char *)0 = 0; } } } else { if (-1 == epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev)) { perror("Remove: epoll_ctl: MOD"); *(char *)0 = 0; } } } } void selectops_epoll_init(void) { epoll_fd = epoll_create(256); if (epoll_fd == -1) { perror("epoll_create"); use_epoll = 0; return; } use_epoll = 1; }