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