RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/service/epoller.cc
00001 /* epoller.cc
00002    Jeremy Barnes, 26 September 2012
00003    Copyright (c) 2012 Datacratic.  All rights reserved.
00004 
00005 */
00006 
00007 #include "soa/service/epoller.h"
00008 
00009 #include <sys/epoll.h>
00010 #include <poll.h>
00011 #include "jml/arch/exception.h"
00012 #include "jml/arch/backtrace.h"
00013 #include <string.h>
00014 #include <iostream>
00015 
00016 
00017 using namespace std;
00018 using namespace ML;
00019 
00020 namespace Datacratic {
00021 
00022 
00023 /*****************************************************************************/
00024 /* EPOLLER                                                                   */
00025 /*****************************************************************************/
00026 
00027 Epoller::
00028 Epoller()
00029     : epoll_fd(-1)
00030 {
00031 }
00032 
00033 Epoller::
00034 ~Epoller()
00035 {
00036     close();
00037 }
00038 
00039 void
00040 Epoller::
00041 init(int maxFds)
00042 {
00043     //cerr << "initializing epoller at " << this << endl;
00044     //backtrace();
00045 
00046     epoll_fd = epoll_create(maxFds);
00047     if (epoll_fd == -1)
00048         throw ML::Exception(errno, "EndpointBase epoll_create()");
00049 }
00050 
00051 void
00052 Epoller::
00053 close()
00054 {
00055     if (epoll_fd < 0)
00056         return;
00057     //cerr << "closing epoller at " << this << endl;
00058     //backtrace();
00059     ::close(epoll_fd);
00060     epoll_fd = -2;
00061 }
00062 
00063 void
00064 Epoller::
00065 addFd(int fd, void * data)
00066 {
00067     struct epoll_event event;
00068     event.events = EPOLLIN;
00069     event.data.ptr = data;
00070     
00071     int res = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
00072     
00073     if (res == -1)
00074         throw ML::Exception(errno, "epoll_ctl ADD");
00075 }
00076     
00077 void
00078 Epoller::
00079 addFdOneShot(int fd, void * data)
00080 {
00081     struct epoll_event event;
00082     event.events = EPOLLIN | EPOLLONESHOT;
00083     event.data.ptr = data;
00084     
00085     int res = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
00086         
00087     if (res == -1)
00088         throw ML::Exception("epoll_ctl ADD: %s (fd = %d, epollfd = %d)",
00089                             strerror(errno), fd, epoll_fd);
00090 }
00091 
00092 void
00093 Epoller::
00094 restartFdOneShot(int fd, void * data)
00095 {
00096     struct epoll_event event;
00097     event.events = EPOLLIN | EPOLLONESHOT;
00098     event.data.ptr = data;
00099     
00100     int res = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event);
00101     
00102     if (res == -1)
00103         throw ML::Exception(errno, "epoll_ctl MOD");
00104 }
00105 
00106 void
00107 Epoller::
00108 removeFd(int fd)
00109 {
00110     int res = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, 0);
00111     
00112     if (res == -1)
00113         throw ML::Exception("epoll_ctl DEL fd %d: %s", fd,
00114                             strerror(errno));
00115 }
00116 
00117 int
00118 Epoller::
00119 handleEvents(int usToWait, int nEvents,
00120              const HandleEvent & handleEvent_,
00121              const OnEvent & beforeSleep_,
00122              const OnEvent & afterSleep_)
00123 {
00124     const HandleEvent & handleEvent
00125         = handleEvent_ ? handleEvent_ : this->handleEvent;
00126     const OnEvent & beforeSleep
00127         = beforeSleep_ ? beforeSleep_ : this->beforeSleep;
00128     const OnEvent & afterSleep
00129         = afterSleep_ ? afterSleep_ : this->afterSleep;
00130 
00131     for (;;) {
00132         epoll_event events[nEvents];
00133                 
00134         if (beforeSleep)
00135             beforeSleep();
00136 
00137         // Do the sleep with nanosecond resolution
00138         // Let's hope it doesn't busy-wait
00139         if (usToWait != 0) {
00140             pollfd fd[1] = { { epoll_fd, POLLIN, 0 } };
00141             timespec timeout = { 0, usToWait * 1000 };
00142             int res = ppoll(fd, 1, &timeout, 0);
00143             if (res == -1 && errno == EBADF)
00144                 return -1;
00145             if (res == -1 && errno == EINTR)
00146                 continue;
00147             //if (debug) cerr << "handleEvents: res = " << res << endl;
00148             if (res == 0) return 0;
00149         }
00150                 
00151         int res = epoll_wait(epoll_fd, events, nEvents, 0);
00152 
00153         if (afterSleep)
00154             afterSleep();
00155 
00156         // sys call interrupt
00157         if (res == -1 && errno == EINTR) continue;
00158         if (res == -1 && errno == EBADF) {
00159             cerr << "got bad FD" << endl;
00160             return -1;
00161         }
00162         if (res == 0) return 0;
00163 
00164         if (res == -1)
00165             throw Exception(errno, "epoll_wait");
00166         nEvents = res;
00167 
00168         for (unsigned i = 0;  i < nEvents;  ++i) {
00169             if (handleEvent(events[i])) return -1;
00170         }
00171                 
00172         return nEvents;
00173     }
00174 }
00175 
00176 bool
00177 Epoller::
00178 poll() const
00179 {
00180     for (;;) {
00181         pollfd fds[1] = { { epoll_fd, POLLIN, 0 } };
00182         int res = ::poll(fds, 1, 0);
00183         if (res == -1 && errno == EBADF)
00184             return false;
00185         if (res == -1 && errno == EINTR)
00186             continue;
00187         if (res == -1)
00188             throw ML::Exception("ppoll in Epoller::poll");
00189         return res > 0;
00190     }
00191 }
00192 
00193 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator