Savarese Software Research Corporation
EventLoop.cc
Go to the documentation of this file.
1 /* Copyright 2006-2009, 2016 Savarese Software Research Corporation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.savarese.com/software/ApacheLicense-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vector>
17 
18 #include <boost/multi_index_container.hpp>
19 #include <boost/multi_index/mem_fun.hpp>
20 #include <boost/multi_index/ordered_index.hpp>
21 #include <boost/multi_index/hashed_index.hpp>
22 
25 
27 
28 using namespace std::rel_ops;
29 
31 
34 typedef std::vector<event_type> io_event_container;
35 
36 struct EventLoopState {
37  typedef boost::multi_index_container<
38  EventHandler*,
39  boost::multi_index::indexed_by<
40  boost::multi_index::ordered_non_unique<
41  boost::multi_index::const_mem_fun<EventHandler, const TimeValue &,
43  boost::multi_index::hashed_unique<boost::multi_index::identity<EventHandler*> >
45 
46  bool running;
47  EventPort port;
48  unsigned int io_handler_count;
51 
53  running(false), port(),
54  io_handler_count(0), io_events(), event_handlers()
55  { }
56 };
57 
59 
60 const EventLoop::EventIO EventLoop::None = EventPort::None;
61 const EventLoop::EventIO EventLoop::Read = EventPort::Read;
62 const EventLoop::EventIO EventLoop::Write = EventPort::Write;
63 const EventLoop::EventIO EventLoop::Error = EventPort::Error;
64 const EventLoop::EventIO EventLoop::Hangup = EventPort::Hangup;
65 /*
66 const EventLoop::EventIO EventLoop::Signal = EventPort::Signal;
67 const EventLoop::EventIO EventLoop::Timeout = EventPort::Timeout;
68 */
69 
70 EventLoop::EventLoop() SSRC_DECL_THROW(std::runtime_error) :
71  _state(std::make_unique<EventLoopState>())
72 { }
73 
74 EventLoop::~EventLoop() = default;
75 
76 unsigned int EventLoop::count_handlers() {
77  return _state->event_handlers.size();
78 }
79 
80 unsigned int EventLoop::count_io_handlers() {
81  return _state->io_handler_count;
82 }
83 
85  return _state->running;
86 }
87 
88 void EventLoop::add_handler(EventHandler & handler,
89  const int events,
90  const TimeValue & timeout,
91  const bool once)
92  SSRC_DECL_THROW(std::runtime_error)
93 {
94  if(handler.event_descriptor() != EventHandler::NoDescriptor && events != None) {
95  if(_state->port.add(handler.event_descriptor(), events, &handler, once)) {
96  if(_state->io_events.size() == _state->io_handler_count)
97  _state->io_events.push_back(event_type());
98  ++_state->io_handler_count;
99  }
100  }
101 
102  handler._handled_timeout = false;
103  handler._once = once;
104  handler._timeout = timeout;
105 
106 #if defined(WISP_HAVE_NONPERSISTENT_EVENTS) || defined(WISP_HAVE_KQUEUE)
107  handler._events = events;
108 #endif
109 
110  if(timeout == InfiniteTimeValue)
111  handler._expiration = InfiniteTimeValue;
112  else {
113  TimeValue expiration;
114  expiration.now_mono()+=timeout;
115  handler._expiration = expiration;
116  }
117 
118  _state->event_handlers.insert(&handler);
119 
120 }
121 
122 void EventLoop::remove_handler(EventHandler & handler) {
123  const bool is_io_event =
125 
126  if(is_io_event) {
127  // We do not check return value of remove because it returns false
128  // only if the descriptor is not associated with the port. When
129  // that happens (should happen only on HAVE_NONPERSISTENT_EVENTS
130  // platforms such as Solaris and with automatically removed events
131  // such as EV_ONESHOT on FreeBSD), we want to remove the handler anyway.
132  // Other errors throw an exception.
133 #if defined(WISP_HAVE_KQUEUE)
134  if(!handler._once) {
135  _state->port.remove(handler.event_descriptor(), handler.events());
136  }
137 #elif defined(WISP_HAVE_NONPERSISTENT_EVENTS)
138  if(!handler._once) {
139  _state->port.remove(handler.event_descriptor());
140  }
141 #else
142  _state->port.remove(handler.event_descriptor());
143 #endif
144  }
145 
146  // CAREFUL! The order of the tests matters as we erase as a side-effect
147  // and don't want to decrement io_handler_count for timeout handlers.
148  if(_state->event_handlers.get<ByIdentity>().erase(&handler) > 0 &&
149  is_io_event)
150  {
151  --_state->io_handler_count;
152  // We can't shrink the vector because it could mess up start loop.
153  //_state->io_events.pop_back();
154  }
155 }
156 
158  EventInfo info(*this);
159  TimeValue now;
160  io_event_container & io_events = _state->io_events;
161  event_handler_container & event_handlers = _state->event_handlers;
162  EventPort & port = _state->port;
163 
164  _state->running = true;
165  while(count_io_handlers() > 0 && _state->running) {
166  int fd_count, timeout = -1;
167  event_handler_container::iterator it = event_handlers.begin();
168  EventHandler *handler = *it;
169 
170  if(io_events.size() != count_io_handlers())
171  io_events.resize(count_io_handlers());
172 
173  if(handler->has_timeout()) {
174  now.now_mono();
175 
176  if(now >= handler->expiration())
177  timeout = 0;
178  else
179  timeout = (handler->expiration() - now).to_milliseconds();
180  }
181 
182  fd_count = port.wait(&io_events[0], count_io_handlers(), timeout);
183 
184  if(fd_count < 0) {
185  // TODO: log exit condition, including errno and strerror(errno).
186  stop();
187  break;
188  }
189 
190  info._now = now.now_mono();
191 
192  for(int i = 0; i < fd_count; ++i) {
193  handler = EventPort::get_handler(io_events[i]);
194  info._io_events = EventPort::get_events(io_events[i]);
195  info._timeout = (handler->expiration() <= now);
196 
197  /*
198  if(info.signal_event())
199  handler->handle_signal(info);
200  */
201 
202  if(info.error_event())
203  handler->handle_error(info);
204 
205  if(info.hangup_event())
206  handler->handle_hangup(info);
207 
208  if(info.read_event())
209  handler->handle_read(info);
210 
211  if(info.write_event())
212  handler->handle_write(info);
213 
214  if(info.timeout_event()) {
215  handler->handle_timeout(info);
216  handler->_handled_timeout = true;
217  } else if(handler->_once) {
218  remove_handler(*handler);
219  }
220 
221 #if defined(WISP_HAVE_NONPERSISTENT_EVENTS)
222  // Solaris ports require reassociation after every event.
223  // TODO: log error and decrement io_handler_count if this fails?
224  if(!handler->_once) {
225  port.add(handler->event_descriptor(), handler->_events, handler,
226  handler->_once);
227  }
228 #endif
229  }
230 
231  info._timeout = true;
232  info._io_events = None;
233 
234  it = event_handlers.begin();
235  std::iterator_traits<event_handler_container::iterator>::difference_type
236  count = std::distance(it, event_handlers.upper_bound(now));
237 
238  while(count-- > 0) {
239  handler = *it;
240  it = event_handlers.erase(it);
241 
242  // Insert beforehand to allow handler the option to remove itself.
243  if(!handler->_once) {
244  handler->_expiration = now + handler->timeout();
245  event_handlers.insert(handler);
246  } else
247  remove_handler(*handler);
248 
249  if(!handler->_handled_timeout)
250  handler->handle_timeout(info);
251  else
252  handler->_handled_timeout = false;
253  }
254  }
255 }
256 
257 void EventLoop::stop() {
258  // TODO: do something to wake up the poll.
259  _state->running = false;
260 }
261 
262 

Savarese Software Research Corporation
Copyright © 2006-2012 Savarese Software Research Corporation. All rights reserved.