libiqxmlrpc  0.12.4
 All Classes Namespaces Files Functions Typedefs Enumerations
reactor_impl.h
1 // Libiqxmlrpc - an object-oriented XML-RPC solution.
2 // Copyright (C) 2011 Anton Dedov
3 
4 #ifndef _iqxmlrpc_reactor_impl_h_
5 #define _iqxmlrpc_reactor_impl_h_
6 
7 #include "config.h"
8 #include "reactor.h"
9 
10 #ifdef HAVE_POLL
11 #include "reactor_poll_impl.h"
12  namespace iqnet
13  {
14  typedef Reactor_poll_impl ReactorImpl;
15  }
16 #else
17 #include "reactor_select_impl.h"
18  namespace iqnet
19  {
20  typedef Reactor_select_impl ReactorImpl;
21  }
22 #endif // HAVE_POLL
23 
24 #include <boost/utility.hpp>
25 
26 #include <assert.h>
27 #include <map>
28 #include <algorithm>
29 
30 namespace iqnet
31 {
32 
35 template <class Lock>
36 class Reactor: public Reactor_base, boost::noncopyable {
37 public:
38  Reactor();
39  ~Reactor() {}
40 
41  void register_handler( Event_handler*, Event_mask );
42  void unregister_handler( Event_handler*, Event_mask );
43  void unregister_handler( Event_handler* );
44 
45  void fake_event( Event_handler*, Event_mask );
46 
47  bool handle_events( Timeout ms = -1 );
48 
49 private:
50  typedef typename Lock::scoped_lock scoped_lock;
51  typedef std::map<Socket::Handler, Event_handler*> EventHandlersMap;
52  typedef EventHandlersMap::iterator h_iterator;
53  typedef HandlerStateList::const_iterator hs_const_iterator;
54  typedef HandlerStateList::iterator hs_iterator;
55 
56  size_t size() const { return handlers_states.size(); }
57  hs_const_iterator begin() const { return handlers_states.begin(); }
58  hs_iterator begin() { return handlers_states.begin(); }
59  hs_const_iterator end() const { return handlers_states.end(); }
60  hs_iterator end() { return handlers_states.end(); }
61 
62  Event_handler* find_handler(Socket::Handler);
63  hs_iterator find_handler_state(Event_handler*);
64 
65  void handle_user_events();
66  bool handle_system_events( Timeout );
67 
68  void invoke_clients_handler( Event_handler*, HandlerState&, bool& terminate );
69  void invoke_servers_handler( Event_handler*, HandlerState&, bool& terminate );
70  void invoke_event_handler( HandlerState& );
71 
72 private:
73  Lock lock;
74  ReactorImpl impl;
75 
76  EventHandlersMap handlers;
77  HandlerStateList handlers_states;
78 
79  unsigned num_stoppers;
80 };
81 
82 
83 // ----------------------------- Implementation -----------------------------
84 
85 template <class Lock>
87  num_stoppers(0)
88 {
89 }
90 
91 template <class Lock>
92 typename Reactor<Lock>::hs_iterator
93 Reactor<Lock>::find_handler_state(Event_handler* eh)
94 {
95  return std::find(begin(), end(), HandlerState(eh->get_handler()));
96 }
97 
98 template <class Lock>
99 iqnet::Event_handler* Reactor<Lock>::find_handler(Socket::Handler fd)
100 {
101  scoped_lock lk(lock);
102  h_iterator i = handlers.find(fd);
103  return i == handlers.end() ? NULL : i->second;
104 }
105 
106 template <class Lock>
107 void Reactor<Lock>::register_handler( Event_handler* eh, Event_mask mask )
108 {
109  scoped_lock lk(lock);
110 
111  if (eh->is_stopper())
112  num_stoppers++;
113 
114  Socket::Handler fd = eh->get_handler();
115 
116  if( handlers.find(fd) == handlers.end() )
117  {
118  handlers_states.push_back( HandlerState(fd, mask) );
119  handlers[fd] = eh;
120  }
121  else
122  {
123  typename Reactor<Lock>::hs_iterator i = find_handler_state(eh);
124  i->mask |= mask;
125  }
126 }
127 
128 template <class Lock>
129 void Reactor<Lock>::unregister_handler( Event_handler* eh, Event_mask mask )
130 {
131  scoped_lock lk(lock);
132  hs_iterator i = find_handler_state( eh );
133 
134  if( i != end() )
135  {
136  int newmask = (i->mask &= !mask);
137 
138  if( !newmask )
139  {
140  handlers.erase(eh->get_handler());
141  handlers_states.erase(i);
142 
143  if (eh->is_stopper())
144  num_stoppers--;
145  }
146  }
147 }
148 
149 template <class Lock>
150 void Reactor<Lock>::unregister_handler( Event_handler* eh )
151 {
152  scoped_lock lk(lock);
153  h_iterator i = handlers.find(eh->get_handler());
154 
155  if( i != handlers.end() )
156  {
157  handlers.erase(i);
158  handlers_states.erase(find_handler_state(eh));
159 
160  if (eh->is_stopper())
161  num_stoppers--;
162  }
163 }
164 
165 template <class Lock>
166 void Reactor<Lock>::fake_event( Event_handler* eh, Event_mask mask )
167 {
168  scoped_lock lk(lock);
169  hs_iterator i = find_handler_state( eh );
170 
171  if( i != end() )
172  i->revents |= mask;
173 }
174 
175 template <class Lock>
176 void Reactor<Lock>::invoke_clients_handler(
177  Event_handler* handler, HandlerState& hs, bool& terminate )
178 {
179  bool in = (hs.revents & Reactor_base::INPUT) != 0;
180  bool out = (hs.revents & Reactor_base::OUTPUT) != 0;
181 
182  if( in )
183  handler->handle_input( terminate );
184  else if( out )
185  handler->handle_output( terminate );
186 }
187 
188 template <class Lock>
189 void Reactor<Lock>::invoke_servers_handler(
190  Event_handler* handler, HandlerState& hs, bool& terminate )
191 {
192  try {
193  invoke_clients_handler( handler, hs, terminate );
194  }
195  catch( const std::exception& e )
196  {
197  handler->log_exception( e );
198  terminate = true;
199  }
200  catch( ... )
201  {
202  handler->log_unknown_exception();
203  terminate = true;
204  }
205 }
206 
207 template <class Lock>
208 void Reactor<Lock>::invoke_event_handler( Reactor_base::HandlerState& hs )
209 {
210  bool terminate = false;
211 
212  Event_handler* handler = find_handler(hs.fd);
213  assert(handler);
214 
215  if( handler->catch_in_reactor() )
216  invoke_servers_handler( handler, hs, terminate );
217  else
218  invoke_clients_handler( handler, hs, terminate );
219 
220  if( terminate )
221  {
222  unregister_handler( handler );
223  handler->finish();
224  }
225 }
226 
227 template <class Lock>
228 void Reactor<Lock>::handle_user_events()
229 {
230  HandlerStateList called_by_user;
231  scoped_lock lk(lock);
232 
233  for( hs_iterator i = begin(); i != end(); ++i )
234  {
235  if( i->revents && (i->mask | i->revents) )
236  {
237  called_by_user.push_back( *i );
238  i->revents &= !i->mask;
239  }
240  }
241 
242  lk.unlock();
243 
244  while( !called_by_user.empty() )
245  {
246  HandlerState hs(called_by_user.front());
247  called_by_user.pop_front();
248  invoke_event_handler(hs);
249  }
250 }
251 
252 template <class Lock>
253 bool Reactor<Lock>::handle_system_events(Reactor_base::Timeout ms)
254 {
255  scoped_lock lk(lock);
256  HandlerStateList tmp(handlers_states);
257  lk.unlock();
258 
259  // if all events were of "user" type
260  if (tmp.empty())
261  return true;
262 
263  impl.reset(tmp);
264  HandlerStateList ret;
265  bool succ = impl.poll(ret, ms);
266 
267  if (!succ)
268  return false;
269 
270  while (!ret.empty())
271  {
272  HandlerState hs(ret.front());
273  ret.pop_front();
274  invoke_event_handler(hs);
275  }
276 
277  return true;
278 }
279 
280 template <class Lock>
281 bool Reactor<Lock>::handle_events(Reactor_base::Timeout ms)
282 {
283  if (handlers.empty())
284  return false;
285 
286  if (handlers.size() - num_stoppers <= 0)
287  throw No_handlers();
288 
289  handle_user_events();
290  return handle_system_events(ms);
291 }
292 
293 } // namespace iqnet
294 
295 #endif