RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
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