diff --git a/configure.ac b/configure.ac index f987545..100104a 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,9 @@ fi AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ]) AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no]) +if test "x${have_epoll}" = "xyes"; then + AC_DEFINE([HAVE_EPOLL], [1], [Define to 1 if you have the `epoll`.]) +fi AM_CONDITIONAL([HAVE_EPOLL], [ test "x${have_epoll}" = "xyes" ]) # openssl (for examples) diff --git a/examples/EventPoll.h b/examples/EventPoll.h new file mode 100644 index 0000000..8b6930d --- /dev/null +++ b/examples/EventPoll.h @@ -0,0 +1,36 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef EVENT_POLL_H +#define EVENT_POLL_H + +#ifdef HAVE_CONFIG_H +# include +#endif // HAVE_CONFIG_H + +#ifdef HAVE_EPOLL +# include "EventPoll_epoll.h" +#endif // HAVE_EPOLL + +#endif // EVENT_POLL_H diff --git a/examples/EventPollEvent.h b/examples/EventPollEvent.h new file mode 100644 index 0000000..9c2ec4e --- /dev/null +++ b/examples/EventPollEvent.h @@ -0,0 +1,44 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef EVENT_POLL_EVENT_H +#define EVENT_POLL_EVENT_H + +namespace spdylay { + +enum EventPollEvent { + EP_POLLIN = 1, + EP_POLLOUT = 1 << 1, + EP_POLLHUP = 1 << 2, + EP_POLLERR = 1 << 3 +}; + +enum EventPollOp { + EP_ADD, + EP_MOD +}; + +} // namespace spdylay + +#endif // EVENT_POLL_EVENT_H diff --git a/examples/EventPoll_epoll.cc b/examples/EventPoll_epoll.cc new file mode 100644 index 0000000..2b8f55b --- /dev/null +++ b/examples/EventPoll_epoll.cc @@ -0,0 +1,116 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "EventPoll_epoll.h" + +#include + +#include + +namespace spdylay { + +EventPoll::EventPoll(size_t max_events) + : max_events_(max_events), num_events_(0) +{ + epfd_ = epoll_create(1); + assert(epfd_ != -1); + evlist_ = new epoll_event[max_events_]; +} + +EventPoll::~EventPoll() +{ + if(epfd_ != -1) { + close(epfd_); + } + delete [] evlist_; +} + +int EventPoll::poll(int timeout) +{ + num_events_ = 0; + int n = epoll_wait(epfd_, evlist_, max_events_, timeout); + if(n > 0) { + num_events_ = n; + } + return n; +} + +int EventPoll::get_num_events() +{ + return num_events_; +} + +void* EventPoll::get_user_data(size_t p) +{ + return evlist_[p].data.ptr; +} + +int EventPoll::get_events(size_t p) +{ + int events = 0; + int revents = evlist_[p].events; + if(revents & EPOLLIN) { + events |= EP_POLLIN; + } + if(revents & EPOLLOUT) { + events |= EP_POLLOUT; + } + if(revents & EPOLLHUP) { + events |= EP_POLLHUP; + } + if(revents & EPOLLERR) { + events |= EP_POLLERR; + } + return events; +} + +namespace { +int update_event(int epfd, int op, int fd, int events, void *user_data) +{ + epoll_event ev; + ev.events = 0; + if(events & EP_POLLIN) { + ev.events |= EPOLLIN; + } + if(events & EP_POLLOUT) { + ev.events |= EPOLLOUT; + } + ev.data.ptr = user_data; + return epoll_ctl(epfd, op, fd, &ev); +} +} // namespace + +int EventPoll::ctl_event(int op, int fd, int events, void *user_data) +{ + if(op == EP_ADD) { + op = EPOLL_CTL_ADD; + } else if(op == EP_MOD) { + op = EPOLL_CTL_MOD; + } else { + return -1; + } + return update_event(epfd_, op, fd, events, user_data); +} + +} // namespace spdylay diff --git a/examples/EventPoll_epoll.h b/examples/EventPoll_epoll.h new file mode 100644 index 0000000..b17ec90 --- /dev/null +++ b/examples/EventPoll_epoll.h @@ -0,0 +1,60 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef EVENT_POLL_EPOLL_H +#define EVENT_POLL_EPOLL_H + +#include + +#include + +#include "EventPollEvent.h" + +namespace spdylay { + +class EventPoll { +public: + EventPoll(size_t max_events); + ~EventPoll(); + // Returns 0 if this function succeeds, or -1. + // On success + int poll(int timeout); + // Returns number of events detected in previous call of poll(). + int get_num_events(); + // Returns events of p-eth event. + int get_events(size_t p); + // Returns user data of p-th event. + void* get_user_data(size_t p); + // Adds/Modifies event to watch. + int ctl_event(int op, int fd, int events, void *user_data); +private: + int epfd_; + size_t max_events_; + epoll_event *evlist_; + size_t num_events_; +}; + +} // namespace spdylay + +#endif // EVENT_POLL_EPOLL_H diff --git a/examples/Makefile.am b/examples/Makefile.am index a0e8b70..0a46495 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -33,7 +33,11 @@ spdycat_SOURCES = uri.cc spdylay_ssl.cc util.cc spdycat.cc if HAVE_EPOLL -spdyd_SOURCES = uri.cc spdylay_ssl.cc util.cc spdyd.cc +spdyd_SOURCES = uri.cc spdylay_ssl.cc util.cc spdyd.cc EventPoll.h \ + EventPollEvent.h + +spdyd_SOURCES += EventPoll_epoll.cc EventPoll_epoll.h + bin_PROGRAMS += spdyd endif # HAVE_EPOLL diff --git a/examples/spdyd.cc b/examples/spdyd.cc index 48497a3..8fce25a 100644 --- a/examples/spdyd.cc +++ b/examples/spdyd.cc @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -56,6 +55,7 @@ #include "spdylay_ssl.h" #include "uri.h" #include "util.h" +#include "EventPoll.h" namespace spdylay { @@ -99,17 +99,30 @@ class Sessions; class EventHandler { public: + EventHandler() : mark_del_(false) {} virtual ~EventHandler() {} virtual int execute(Sessions *sessions) = 0; virtual bool want_read() = 0; virtual bool want_write() = 0; virtual int fd() const = 0; virtual bool finish() = 0; + bool mark_del() + { + return mark_del_; + } + void mark_del(bool d) + { + mark_del_ = d; + } +private: + bool mark_del_; }; class Sessions { public: - Sessions(int epfd, SSL_CTX *ssl_ctx) : epfd_(epfd), ssl_ctx_(ssl_ctx) + Sessions(int max_events, SSL_CTX *ssl_ctx) + : eventPoll_(max_events), + ssl_ctx_(ssl_ctx) {} ~Sessions() { @@ -134,31 +147,40 @@ public: } int add_poll(EventHandler *handler) { - return update_poll_internal(handler, EPOLL_CTL_ADD); + return update_poll_internal(handler, EP_ADD); } int mod_poll(EventHandler *handler) { - return update_poll_internal(handler, EPOLL_CTL_MOD); + return update_poll_internal(handler, EP_MOD); + } + int poll(int timeout) + { + return eventPoll_.poll(timeout); + } + void* get_user_data(int p) + { + return eventPoll_.get_user_data(p); + } + int get_events(int p) + { + return eventPoll_.get_events(p); } private: int update_poll_internal(EventHandler *handler, int op) { - epoll_event ev; - ev.events = 0; + int events = 0; if(handler->want_read()) { - ev.events |= EPOLLIN; + events |= EP_POLLIN; } if(handler->want_write()) { - ev.events |= EPOLLOUT; + events |= EP_POLLOUT; } - ev.data.ptr = handler; - int r = epoll_ctl(epfd_, op, handler->fd(), &ev); - return r; + return eventPoll_.ctl_event(op, handler->fd(), events, handler); } std::set handlers_; + EventPoll eventPoll_; SSL_CTX *ssl_ctx_; - int epfd_; }; namespace { @@ -814,47 +836,51 @@ int reactor() } make_non_block(sfd); - int epfd = epoll_create(1); - if(epfd == -1) { - perror("epoll_create"); - return -1; - } - Sessions sessions(epfd, ssl_ctx); + const size_t MAX_EVENTS = 256; + Sessions sessions(MAX_EVENTS, ssl_ctx); ListenEventHandler *listen_hd = new ListenEventHandler(sfd); if(sessions.add_poll(listen_hd) == -1) { std::cerr << "Adding listening socket to poll failed." << std::endl; return -1; } sessions.add_handler(listen_hd); - const int MAX_EVENTS = 256; - epoll_event events[MAX_EVENTS]; + std::vector del_list; while(1) { - int n = epoll_wait(epfd, events, MAX_EVENTS, -1); + int n = sessions.poll(-1); if(n == -1) { - perror("epoll_wait"); + perror("EventPoll"); } else { for(int i = 0; i < n; ++i) { - EventHandler *hd = reinterpret_cast(events[i].data.ptr); + EventHandler *hd = reinterpret_cast + (sessions.get_user_data(i)); + int events = sessions.get_events(i); int r = 0; - if((events[i].events & EPOLLIN) || (events[i].events & EPOLLOUT)) { + if(hd->mark_del()) { + continue; + } + if((events & EP_POLLIN) || (events & EP_POLLOUT)) { r = hd->execute(&sessions); - } else if(events[i].events & (EPOLLERR | EPOLLHUP)) { - on_close(sessions, hd); + } else if(events & (EP_POLLERR | EP_POLLHUP)) { + hd->mark_del(true); } if(r != 0) { - on_close(sessions, hd); + hd->mark_del(true); } else { if(hd->finish()) { - on_close(sessions, hd); + hd->mark_del(true); } else { sessions.mod_poll(hd); } } } + for(std::vector::iterator i = del_list.begin(), + eoi = del_list.end(); i != eoi; ++i) { + on_close(sessions, *i); + } + del_list.clear(); } } on_close(sessions, listen_hd); - close(epfd); return 0; } } // namespace