Open Lighting Architecture
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SelectServer.h
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * SelectServer.h
17  * The select server interface
18  * Copyright (C) 2005-2008 Simon Newton
19  */
20 
21 #ifndef INCLUDE_OLA_IO_SELECTSERVER_H_
22 #define INCLUDE_OLA_IO_SELECTSERVER_H_
23 
24 #include <ola/Callback.h>
25 #include <ola/Clock.h>
26 #include <ola/ExportMap.h>
27 #include <ola/io/Descriptor.h>
28 #include <ola/io/SelectServerInterface.h>
29 #include <ola/network/Socket.h>
30 #include <ola/thread/Thread.h>
31 
32 #include <queue>
33 #include <set>
34 #include <string>
35 #include <vector>
36 
37 class SelectServerTest;
38 
39 namespace ola {
40 namespace io {
41 
42 using ola::ExportMap;
43 using ola::thread::timeout_id;
44 using std::priority_queue;
45 using std::set;
46 using std::string;
47 
48 
55  public :
56  enum Direction {READ, WRITE};
57 
58  SelectServer(ExportMap *export_map = NULL,
59  Clock *clock = NULL);
60  ~SelectServer();
61 
62  bool IsRunning() const { return !m_terminate; }
63  const TimeStamp *WakeUpTime() const { return &m_wake_up_time; }
64 
65  void Terminate();
66 
67  void SetDefaultInterval(const TimeInterval &poll_interval);
68  void Run();
69  void RunOnce(unsigned int delay_sec = POLL_INTERVAL_SECOND,
70  unsigned int delay_usec = POLL_INTERVAL_USECOND);
71 
72  bool AddReadDescriptor(ReadFileDescriptor *descriptor);
73  bool AddReadDescriptor(ConnectedDescriptor *descriptor,
74  bool delete_on_close = false);
75  bool RemoveReadDescriptor(ReadFileDescriptor *descriptor);
76  bool RemoveReadDescriptor(ConnectedDescriptor *descriptor);
77 
78  bool AddWriteDescriptor(WriteFileDescriptor *descriptor);
79  bool RemoveWriteDescriptor(WriteFileDescriptor *descriptor);
80 
81  timeout_id RegisterRepeatingTimeout(unsigned int ms,
82  ola::Callback0<bool> *closure);
83  timeout_id RegisterRepeatingTimeout(const ola::TimeInterval &interval,
84  ola::Callback0<bool> *closure);
85 
86  timeout_id RegisterSingleTimeout(unsigned int ms,
88  timeout_id RegisterSingleTimeout(const ola::TimeInterval &interval,
90  void RemoveTimeout(timeout_id id);
91 
92  void RunInLoop(ola::Callback0<void> *closure);
93 
94  void Execute(ola::BaseCallback0<void> *closure);
95 
96  // these are pubic so that the tests can access them
97  static const char K_READ_DESCRIPTOR_VAR[];
98  static const char K_WRITE_DESCRIPTOR_VAR[];
99  static const char K_CONNECTED_DESCRIPTORS_VAR[];
100  static const char K_TIMER_VAR[];
101  static const char K_LOOP_TIME[];
102  static const char K_LOOP_COUNT[];
103 
104  private :
105  /*
106  * These are timer events, they are used inside the SelectServer class
107  */
108  class Event {
109  public:
110  explicit Event(const TimeInterval &interval, const Clock *clock)
111  : m_interval(interval) {
112  TimeStamp now;
113  clock->CurrentTime(&now);
114  m_next = now + m_interval;
115  }
116  virtual ~Event() {}
117  virtual bool Trigger() = 0;
118 
119  void UpdateTime(const TimeStamp &now) {
120  m_next = now + m_interval;
121  }
122 
123  TimeStamp NextTime() const { return m_next; }
124 
125  private:
126  TimeInterval m_interval;
127  TimeStamp m_next;
128  };
129 
130  // An event that only happens once
131  class SingleEvent: public Event {
132  public:
133  SingleEvent(const TimeInterval &interval,
134  const Clock *clock,
135  ola::BaseCallback0<void> *closure):
136  Event(interval, clock),
137  m_closure(closure) {
138  }
139 
140  virtual ~SingleEvent() {
141  if (m_closure)
142  delete m_closure;
143  }
144 
145  bool Trigger() {
146  if (m_closure) {
147  m_closure->Run();
148  // it's deleted itself at this point
149  m_closure = NULL;
150  }
151  return false;
152  }
153 
154  private:
155  ola::BaseCallback0<void> *m_closure;
156  };
157 
158 
159  /*
160  * An event that occurs more than once. The closure can return false to
161  * indicate that it should not be called again.
162  */
163  class RepeatingEvent: public Event {
164  public:
165  RepeatingEvent(const TimeInterval &interval,
166  const Clock *clock,
167  ola::BaseCallback0<bool> *closure):
168  Event(interval, clock),
169  m_closure(closure) {
170  }
171  ~RepeatingEvent() {
172  delete m_closure;
173  }
174  bool Trigger() {
175  if (!m_closure)
176  return false;
177  return m_closure->Run();
178  }
179 
180  private:
181  ola::BaseCallback0<bool> *m_closure;
182  };
183 
184  typedef struct {
185  ConnectedDescriptor *descriptor;
186  bool delete_on_close;
187  } connected_descriptor_t;
188 
189  struct connected_descriptor_t_lt {
190  bool operator()(const connected_descriptor_t &c1,
191  const connected_descriptor_t &c2) const {
192  return c1.descriptor->ReadDescriptor() <
193  c2.descriptor->ReadDescriptor();
194  }
195  };
196 
197  struct ltevent {
198  bool operator()(Event *e1, Event *e2) const {
199  return e1->NextTime() > e2->NextTime();
200  }
201  };
202 
203  typedef set<ReadFileDescriptor*> ReadDescriptorSet;
204  typedef set<WriteFileDescriptor*> WriteDescriptorSet;
205  typedef set<connected_descriptor_t, connected_descriptor_t_lt>
206  ConnectedDescriptorSet;
207  typedef set<ola::Callback0<void>*> LoopClosureSet;
208 
209  bool m_terminate, m_is_running;
210  TimeInterval m_poll_interval;
211  unsigned int m_next_id;
212  ReadDescriptorSet m_read_descriptors;
213  ConnectedDescriptorSet m_connected_read_descriptors;
214  WriteDescriptorSet m_write_descriptors;
215  set<timeout_id> m_removed_timeouts;
216  ExportMap *m_export_map;
217 
218  typedef priority_queue<Event*, vector<Event*>, ltevent> event_queue_t;
219  event_queue_t m_events;
220  CounterVariable *m_loop_iterations;
221  CounterVariable *m_loop_time;
222  TimeStamp m_wake_up_time;
223  Clock *m_clock;
224  bool m_free_clock;
225  LoopClosureSet m_loop_closures;
226  std::queue<ola::BaseCallback0<void>*> m_incoming_queue;
227  ola::thread::Mutex m_incoming_mutex;
228  LoopbackDescriptor m_incoming_descriptor;
229 
230  SelectServer(const SelectServer&);
231  SelectServer operator=(const SelectServer&);
232  bool CheckForEvents(const TimeInterval &poll_interval);
233  void CheckDescriptors(fd_set *r_set, fd_set *w_set);
234  bool AddDescriptorsToSet(fd_set *r_set, fd_set *w_set, int *max_sd);
235  TimeStamp CheckTimeouts(const TimeStamp &now);
236  void UnregisterAll();
237  void DrainAndExecute();
238  void SetTerminate() { m_terminate = true; }
239  void SafeIncrement(const string &var_name);
240  void SafeDecrement(const string &var_name);
241 
242  static const int K_MS_IN_SECOND = 1000;
243  static const int K_US_IN_SECOND = 1000000;
244  // the maximum time we'll wait in the select call
245  static const unsigned int POLL_INTERVAL_SECOND = 10;
246  static const unsigned int POLL_INTERVAL_USECOND = 0;
247 
248  friend class ::SelectServerTest;
249 };
250 } // namespace io
251 } // namespace ola
252 #endif // INCLUDE_OLA_IO_SELECTSERVER_H_