EpcTools
An event based multi-threaded C++ development framework.
etimerpool.h
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2019 Sprint
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.apache.org/licenses/LICENSE-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 #ifndef __ETIMERPOOL_H
18 #define __ETIMERPOOL_H
19 
20 #include <atomic>
21 #include <unordered_map>
22 
23 #include <sys/time.h>
24 #include <pthread.h>
25 #include <signal.h>
26 
27 #include "esynch.h"
28 #include "etevent.h"
29 #include "etime.h"
30 
31 DECLARE_ERROR_ADVANCED(ETimerPoolError_CreatingTimer);
32 DECLARE_ERROR_ADVANCED(ETimerPoolError_TimerSetTimeFailed);
33 
35 typedef Void (*ETimerPoolExpirationCallback)(ULong timerid, pVoid data);
36 
38 {
39 protected:
40  // forward declarations
41  class Timer;
42  typedef std::shared_ptr<Timer> TimerPtr;
43  typedef std::list<TimerPtr> TimerPtrList;
44 
45  class Entry;
46  typedef std::shared_ptr<Entry> EntryPtr;
47  typedef std::unordered_map<ULong,EntryPtr> EntryMap;
48 
49  class ExpirationTime;
50  class ExpirationTimeEntry;
51  typedef std::shared_ptr<ExpirationTimeEntry> ExpirationTimeEntryPtr;
52  typedef std::unordered_map<LongLong,ExpirationTimeEntryPtr> ExpirationTimeEntryMap;
53  typedef std::unordered_map<ULong,ExpirationTimeEntryPtr> ExpirationTimeEntryIdMap;
54 
55  class Thread;
56 
57  friend ExpirationTime;
58 public:
60  enum class Rounding
61  {
63  up,
65  down
66  };
67 
70  static ETimerPool &Instance()
71  {
72  if (!m_instance)
73  m_instance = new ETimerPool();
74  return *m_instance;
75  }
76 
78  ETimerPool();
80  ~ETimerPool();
81 
85  LongLong getResolution(Bool raw=False) { return raw ? m_resolution : m_resolution / 1000; }
88  Rounding getRounding() { return m_rounding; }
91  Int getTimerSignal() { return m_sigtimer; }
94  Int getQuitSignal() { return m_sigquit; }
95 
99  ETimerPool &setResolution(LongLong ms) { m_resolution = ms * 1000; return *this; }
103  ETimerPool &setRounding(Rounding r) { m_rounding = r; return *this; }
107  ETimerPool &setTimerSignal(Int sig) { m_sigtimer = sig; return *this; }
111  ETimerPool &setQuitSignal(Int sig) { m_sigquit = sig; return *this; }
112 
118  ULong registerTimer(LongLong ms, _EThreadEventMessageBase *msg, _EThreadEventBase &thread);
124  ULong registerTimer(LongLong ms, ETimerPoolExpirationCallback func, pVoid data);
128  ETimerPool &unregisterTimer(ULong timerid);
130  Void init();
132  Void uninit(Bool dumpit=False);
133 
135  Void dump();
136 
137 protected:
140 
141  class Timer
142  {
143  friend class ETimerPool;
144 
145  public:
146  Timer();
147  ~Timer();
148 
149  Bool create(pid_t tid, int sig);
150 
151  Timer &setExpirationTimeEntry(ExpirationTimeEntryPtr &etep) { m_etep = etep; return *this; }
152  ExpirationTimeEntryPtr &getExpirationTimeEntry() { return m_etep; }
153  Timer & clearExpirationTimeEntry() { m_etep.reset(); return *this; }
154 
155  Void start();
156  Void stop();
157 
158  timer_t getHandle() { return m_timer; }
159 
160  private:
161  timer_t m_timer;
162  ExpirationTimeEntryPtr m_etep;
163  };
164 
166 
167  class ExpirationTime
168  {
169  public:
171  : m_duration(0),
172  m_expiretime(0)
173  {
174  }
175  ExpirationTime(LongLong ms, Rounding rounding = Instance().m_rounding)
176  : m_duration(0),
177  m_expiretime(0)
178  {
179  setDuration( ms, rounding );
180  }
181  ExpirationTime(const ExpirationTime &exptm)
182  : m_duration(0),
183  m_expiretime(0)
184  {
185  m_duration = exptm.m_duration;
186  m_expiretime = exptm.m_expiretime;
187  }
188 
189  ExpirationTime &operator=(const ExpirationTime et)
190  {
191  m_duration = et.m_duration;
192  m_expiretime = et.m_expiretime;
193  return *this;
194  }
195 
196  LongLong getDuration() { return m_duration; }
197  ExpirationTime &setDuration(LongLong ms, Rounding rounding = Instance().m_rounding)
198  {
199  LongLong resolution = Instance().getResolution(True);
200 
201  m_duration = ms;
202 
203  ETime et = ETime() + ETime(m_duration);
204 
205  m_expiretime =
206  ((et.getTimeVal().tv_sec * 1000000 + et.getTimeVal().tv_usec % 1000000) / resolution +
207  (rounding == Rounding::down ? 0 : 1)) * resolution;
208 
209  return *this;
210  }
211 
212  LongLong getExpireTime()
213  {
214  return m_expiretime;
215  }
216 
217  private:
218  LongLong m_duration; // in milliseconds
219  LongLong m_expiretime; // m_expiretime = tv_sec * 1000000 + tv_usec % 1000000;
220  };
221 
223 
224  enum class ExpirationInfoType
225  {
226  Unknown,
227  Callback,
228  Thread
229  };
230 
231  struct ExpirationInfo
232  {
233  ExpirationInfo()
234  {
235  type = ExpirationInfoType::Unknown;
236  memset(&u, 0, sizeof(u));
237  }
238 
239  ExpirationInfo(_EThreadEventBase &thread, _EThreadEventMessageBase *msg)
240  {
241  type = ExpirationInfoType::Thread;
242  u.thrd.thread = &thread;
243  u.thrd.msg = msg;
244  }
245 
246  ExpirationInfo(ETimerPoolExpirationCallback func, pVoid data)
247  {
248  type = ExpirationInfoType::Callback;
249  u.cb.func = func;
250  u.cb.data = data;
251  }
252 
253  ExpirationInfo(const ExpirationInfo &src)
254  {
255  *this = src;
256  }
257 
258  ~ExpirationInfo()
259  {
260  switch (type)
261  {
262  case ExpirationInfoType::Thread:
263  if (u.thrd.msg)
264  delete u.thrd.msg;
265  break;
266  case ExpirationInfoType::Callback:
267  break;
268  default:
269  break;
270  }
271  }
272 
273  ExpirationInfo &operator=(const ExpirationInfo &info)
274  {
275  type = info.type;
276  switch (type)
277  {
278  case ExpirationInfoType::Thread:
279  u.thrd.thread = info.u.thrd.thread;
280  u.thrd.msg = info.u.thrd.msg;
281  break;
282  case ExpirationInfoType::Callback:
283  u.cb.func = info.u.cb.func;
284  u.cb.data = info.u.cb.data;
285  break;
286  default:
287  memcpy(&u, &info.u, sizeof(u));
288  break;
289  }
290 
291  return *this;
292  }
293 
294  ExpirationInfo &clear()
295  {
296  type = ExpirationInfoType::Unknown;
297  memset(&u, 0, sizeof(u));
298  return *this;
299  }
300 
301  ExpirationInfoType type;
302  union ExpirationInfoUnion
303  {
304  struct
305  {
306  _EThreadEventBase *thread;
308  } thrd;
309  struct
310  {
312  pVoid data;
313  } cb;
314  } u;
315  };
316 
317  class Entry
318  {
319  public:
320  Entry(ULong id, ExpirationTime &exptm, const ExpirationInfo &info)
321  : m_id( id ),
322  m_exptm( exptm ),
323  m_info( info )
324  {
325  }
326  Entry(const Entry &e)
327  : m_id( e.m_id ),
328  m_exptm( e.m_exptm ),
329  m_info( e.m_info )
330  {
331  }
332 
333  ULong getId() { return m_id; }
334  ExpirationInfo &getExpirationInfo() { return m_info; }
335  ExpirationTime &getExpirationTime() { return m_exptm; }
336 
337  Void notify();
338 
339  private:
340  Entry();
341 
342  ULong m_id;
343  ExpirationTime m_exptm;
344  ExpirationInfo m_info;
345  };
346 
347  class ExpirationTimeEntry
348  {
349  public:
350  ExpirationTimeEntry(LongLong expiretime)
351  : m_expiretime( expiretime )
352  {
353  }
354 
355  LongLong getExpireTime() { return m_expiretime; }
356  ExpirationTimeEntry &setExpireTime(LongLong exp) { m_expiretime = exp; return *this; }
357 
358  ExpirationTimeEntry &addEntry(EntryPtr &ep)
359  {
360  m_map[ep->getId()] = ep;
361  return *this;
362  }
363 
364  Void removeEntry(ULong id)
365  {
366  m_map.erase( id );
367  }
368 
369  Bool isEntryMapEmpty()
370  {
371  return m_map.empty();
372  }
373 
374  ExpirationTimeEntry &setTimer(TimerPtr &tp)
375  {
376  m_timer = tp;
377  return *this;
378  }
379 
380  TimerPtr &getTimer()
381  {
382  return m_timer;
383  }
384 
385  EntryMap &getEntryMap()
386  {
387  return m_map;
388  }
389 
390  ExpirationTimeEntry &notify()
391  {
392  for (auto it = m_map.begin(); it != m_map.end();)
393  {
394  // send the notificaiton for the entry
395  it->second->notify();
396 
397  // remove the entry
398  it = m_map.erase( it );
399  }
400 
401  return *this;
402  }
403 
404  private:
405  ExpirationTimeEntry();
406  LongLong m_expiretime;
407  TimerPtr m_timer;
408  EntryMap m_map;
409  };
410 
412 
413  class Thread : public EThreadBasic
414  {
415  public:
416  Thread(ETimerPool &tp);
417 
418  pid_t getThreadId() { return m_tid; }
419 
420  Void quit();
421 
422  Dword threadProc(Void *arg);
423 
424  private:
425  Thread();
426 
427  ETimerPool &m_tp;
428  pid_t m_tid;
429  };
430 
431  friend Thread;
432 
434 
435  Void sendNotifications(ExpirationTimeEntryPtr &etep);
436 
438 
439 private:
440  static ETimerPool *m_instance;
441 
442  ULong _registerTimer(LongLong ms, const ETimerPool::ExpirationInfo &info);
443  ULong assignNextId();
444  ETimerPool &removeExpirationTimeEntry(ETimerPool::ExpirationTimeEntryPtr &etep);
445 
446  EMutexPrivate m_mutex;
447  std::atomic<ULong> m_nextid;
448  Int m_sigtimer;
449  Int m_sigquit;
450  Rounding m_rounding;
451  LongLong m_resolution; // in microseconds
452  ExpirationTimeEntryMap m_etmap;
453  ExpirationTimeEntryIdMap m_etidmap;
454  TimerPtrList m_freetimers;
455  Thread m_thread;
456 };
457 
458 #endif // #define __ETIMERPOOL_H
ETimerPool::EntryMap
std::unordered_map< ULong, EntryPtr > EntryMap
Definition: etimerpool.h:47
ETimerPool::getQuitSignal
Int getQuitSignal()
Retrieves the current quit signal value.
Definition: etimerpool.h:94
ETimerPool::ETimerPool
ETimerPool()
Default constructor.
Definition: etimerpool.cpp:54
ETime
Class for manipulating date and time of day values.
Definition: etime.h:199
ETimerPool::ExpirationTimeEntryMap
std::unordered_map< LongLong, ExpirationTimeEntryPtr > ExpirationTimeEntryMap
Definition: etimerpool.h:52
ETimerPool::ExpirationTimeEntryPtr
std::shared_ptr< ExpirationTimeEntry > ExpirationTimeEntryPtr
Definition: etimerpool.h:50
True
#define True
True.
Definition: ebase.h:25
ETimerPool::uninit
Void uninit(Bool dumpit=False)
Uninitializes the ETimerPool.
ETimerPool::Rounding::down
Rounds down.
ETimerPool::TimerPtrList
std::list< TimerPtr > TimerPtrList
Definition: etimerpool.h:43
DECLARE_ERROR_ADVANCED
DECLARE_ERROR_ADVANCED(ETimerPoolError_CreatingTimer)
_EThreadEventBase
Definition: etevent.h:833
EMutexPrivate
A private mutex (the mutex data is allocated from either the heap or stack).
Definition: esynch.h:175
ETimerPool::setQuitSignal
ETimerPool & setQuitSignal(Int sig)
Assigns the quit signal value.
Definition: etimerpool.h:111
esynch.h
Contains definitions for synchronization objects.
ETimerPoolExpirationCallback
Void(* ETimerPoolExpirationCallback)(ULong timerid, pVoid data)
Defines the timer expiration callback function.
Definition: etimerpool.h:35
ETimerPool::ExpirationTimeEntryIdMap
std::unordered_map< ULong, ExpirationTimeEntryPtr > ExpirationTimeEntryIdMap
Definition: etimerpool.h:53
etevent.h
ETimerPool::ExpirationTime
friend ExpirationTime
Definition: etimerpool.h:55
ETimerPool::unregisterTimer
ETimerPool & unregisterTimer(ULong timerid)
Unregisters an expiration timer.
Definition: etimerpool.cpp:143
etime.h
Provides class for manipulating time of day values.
ETimerPool::setResolution
ETimerPool & setResolution(LongLong ms)
Assigns the timer resolution value.
Definition: etimerpool.h:99
False
#define False
False.
Definition: ebase.h:27
ETimerPool::getTimerSignal
Int getTimerSignal()
Retrieves the current timer signal value.
Definition: etimerpool.h:91
ETimerPool::dump
Void dump()
Prints the contents of the internal collections.
ETimerPool::Rounding::up
Rounds up.
ETimerPool::getResolution
LongLong getResolution(Bool raw=False)
Retrieves the current timer resolution value.
Definition: etimerpool.h:85
ETime::getTimeVal
const timeval & getTimeVal()
Retrieves a reference to the timeval structure.
Definition: etime.h:446
ETimerPool::getRounding
Rounding getRounding()
Retrieves the current rounding value.
Definition: etimerpool.h:88
ETimerPool::~ETimerPool
~ETimerPool()
Class destructor.
Definition: etimerpool.cpp:64
ETimerPool::Instance
static ETimerPool & Instance()
Retrieves the single instance of the ETimerPool object.
Definition: etimerpool.h:70
_EThreadEventMessageBase
The event message base class.
Definition: etevent.h:197
ETimerPool
Definition: etimerpool.h:37
EThreadBasic
An abstract class that represents contains the threadProc() that will be run in a separate thread.
Definition: etbasic.h:53
ETimerPool::setTimerSignal
ETimerPool & setTimerSignal(Int sig)
Assigns the timer signal value.
Definition: etimerpool.h:107
ETimerPool::setRounding
ETimerPool & setRounding(Rounding r)
Assigns the timer rounding method.
Definition: etimerpool.h:103
ETimerPool::Rounding
Rounding
Defines how rounding will be performed.
Definition: etimerpool.h:60
ETimerPool::TimerPtr
std::shared_ptr< Timer > TimerPtr
Definition: etimerpool.h:41
ETimerPool::registerTimer
ULong registerTimer(LongLong ms, _EThreadEventMessageBase *msg, _EThreadEventBase &thread)
Registers an expiration timer.
Definition: etimerpool.cpp:68
ETimerPool::init
Void init()
Initializes the ETimerPool.
ETimerPool::EntryPtr
std::shared_ptr< Entry > EntryPtr
Definition: etimerpool.h:45