1 // Copyright (C) 2007  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_TIMEr_Hh_
4 #define DLIB_TIMEr_Hh_
5 
6 #include <memory>
7 
8 #include "../threads.h"
9 #include "../algs.h"
10 #include "../misc_api.h"
11 #include "timer_abstract.h"
12 #include "../uintn.h"
13 #include "../binary_search_tree.h"
14 #include "timer_heavy.h"
15 
16 namespace dlib
17 {
18 
19     struct timer_base : public threaded_object
20     {
21         /*!
22             WHAT THIS OBJECT REPRESENTS
23                 This object contains the base members of the timer object.
24                 It exists so that we can access them from outside any templated functions.
25         !*/
26 
27         unsigned long delay;
28         // these are only modified by the global_clock
29         uint64 next_time_to_run;
30         timestamper ts;
31         bool running;
32         bool in_global_clock;
33     };
34 
35 // ----------------------------------------------------------------------------------------
36 
37     class timer_global_clock : private threaded_object
38     {
39         /*!
40             This object sets up a timer that triggers the action function
41             for timer objects that are tracked inside this object.
42             INITIAL VALUE
43                 - shutdown == false
44                 - running == false
45 
46             CONVENTION
47                 - if (shutdown) then
48                     - thread() should terminate
49                 - else (running) then
50                     - thread() is running
51 
52                 - tm[time] == pointer to a timer_base object
53         !*/
54         typedef binary_search_tree<uint64,timer_base*,memory_manager<char>::kernel_2b>::kernel_2a_c time_map;
55     public:
56 
57         ~timer_global_clock();
58 
59         void add (
60             timer_base* r
61         );
62         /*!
63             requires
64                 - m is locked
65             ensures
66                 - starts the thread if it isn't already started
67                 - adds r to tm
68                 - #r->in_global_clock == true
69                 - updates r->next_time_to_run appropriately according to
70                     r->delay
71         !*/
72 
73         void remove (
74             timer_base* r
75         );
76         /*!
77             requires
78                 - m is locked
79             ensures
80                 - if (r is in tm) then
81                     - removes r from tm
82                 - #r->in_global_clock == false
83         !*/
84 
85         void adjust_delay (
86             timer_base* r,
87             unsigned long new_delay
88         );
89         /*!
90             requires
91                 - m is locked
92             ensures
93                 - #r->delay == new_delay
94                 - if (r->in_global_clock) then
95                     - the time to the next event will have been appropriately adjusted
96         !*/
97 
98         mutex m;
99 
100         friend std::shared_ptr<timer_global_clock> get_global_clock();
101 
102     private:
103         timer_global_clock();
104 
105         time_map tm;
106         signaler s;
107         bool shutdown;
108         bool running;
109         timestamper ts;
110 
111         void thread();
112         /*!
113             ensures
114                 - spawns timer tasks as is appropriate
115         !*/
116     };
117     std::shared_ptr<timer_global_clock> get_global_clock();
118     /*!
119         ensures
120             - returns the global instance of the timer_global_clock object
121     !*/
122 
123 // ----------------------------------------------------------------------------------------
124 
125     template <
126         typename T
127         >
128     class timer : private timer_base
129     {
130         /*!
131             INITIAL VALUE
132                 - running   == false
133                 - delay     == 1000
134                 - ao        == a pointer to the action_object()
135                 - af        == a pointer to the action_function()
136                 - in_global_clock == false
137                 - next_time_to_run == 0
138                 - gc == get_global_clock()
139 
140             CONVENTION
141                 - the mutex used to lock everything is gc->m
142                 - running == is_running()
143                 - delay == delay_time()
144                 - *ao == action_object()
145                 - af == action_function()
146                 - if (!running) then
147                     - in_global_clock == false
148                 - else
149                     - next_time_to_run == the next time this timer should run according
150                       to the timestamper in the global_clock
151         !*/
152 
153     public:
154 
155         // These typedefs are here for backwards compatibility with previous versions of
156         // dlib.
157         typedef timer_heavy<T> kernel_1a;
158         typedef timer kernel_2a;
159 
160         typedef void (T::*af_type)();
161 
162         timer(
163             T& ao_,
164             af_type af_
165         );
166 
167         virtual ~timer(
168         );
169 
170         void clear(
171         );
172 
173         af_type action_function (
174         ) const;
175 
176         const T& action_object (
177         ) const;
178 
179         T& action_object (
180         );
181 
182         bool is_running (
183         ) const;
184 
185         unsigned long delay_time (
186         ) const;
187 
188         void set_delay_time (
189             unsigned long milliseconds
190         );
191 
192         void start (
193         );
194 
195         void stop (
196         );
197 
198         void stop_and_wait (
199         );
200 
201     private:
202 
203         void thread (
204         );
205         /*!
206             ensures
207                 - calls the action function
208         !*/
209 
210         // data members
211         T& ao;
212         const af_type af;
213         std::shared_ptr<timer_global_clock> gc;
214 
215         // restricted functions
216         timer(const timer&);        // copy constructor
217         timer& operator=(const timer&);    // assignment operator
218 
219     };
220 
221 // ----------------------------------------------------------------------------------------
222 // ----------------------------------------------------------------------------------------
223     // member function definitions
224 // ----------------------------------------------------------------------------------------
225 // ----------------------------------------------------------------------------------------
226 
227     template <
228         typename T
229         >
230     timer<T>::
timer(T & ao_,af_type af_)231     timer(
232         T& ao_,
233         af_type af_
234     ) :
235         ao(ao_),
236         af(af_),
237         gc(get_global_clock())
238     {
239         delay = 1000;
240         next_time_to_run = 0;
241         running = false;
242         in_global_clock = false;
243     }
244 
245 // ----------------------------------------------------------------------------------------
246 
247     template <
248         typename T
249         >
250     timer<T>::
~timer()251     ~timer(
252     )
253     {
254         clear();
255         wait();
256     }
257 
258 // ----------------------------------------------------------------------------------------
259 
260     template <
261         typename T
262         >
263     void timer<T>::
clear()264     clear(
265     )
266     {
267         auto_mutex M(gc->m);
268         running = false;
269         gc->remove(this);
270         delay = 1000;
271         next_time_to_run = 0;
272     }
273 
274 // ----------------------------------------------------------------------------------------
275 
276     template <
277         typename T
278         >
279     typename timer<T>::af_type timer<T>::
action_function()280     action_function (
281     ) const
282     {
283         return af;
284     }
285 
286 // ----------------------------------------------------------------------------------------
287 
288     template <
289         typename T
290         >
291     const T& timer<T>::
action_object()292     action_object (
293     ) const
294     {
295         return ao;
296     }
297 
298 // ----------------------------------------------------------------------------------------
299 
300     template <
301         typename T
302         >
303     T& timer<T>::
action_object()304     action_object (
305     )
306     {
307         return ao;
308     }
309 
310 // ----------------------------------------------------------------------------------------
311 
312     template <
313         typename T
314         >
315     bool timer<T>::
is_running()316     is_running (
317     ) const
318     {
319         auto_mutex M(gc->m);
320         return running;
321     }
322 
323 // ----------------------------------------------------------------------------------------
324 
325     template <
326         typename T
327         >
328     unsigned long timer<T>::
delay_time()329     delay_time (
330     ) const
331     {
332         auto_mutex M(gc->m);
333         return delay;
334     }
335 
336 // ----------------------------------------------------------------------------------------
337 
338     template <
339         typename T
340         >
341     void timer<T>::
set_delay_time(unsigned long milliseconds)342     set_delay_time (
343         unsigned long milliseconds
344     )
345     {
346         auto_mutex M(gc->m);
347         gc->adjust_delay(this,milliseconds);
348     }
349 
350 // ----------------------------------------------------------------------------------------
351 
352     template <
353         typename T
354         >
355     void timer<T>::
start()356     start (
357     )
358     {
359         auto_mutex M(gc->m);
360         if (!running)
361         {
362             gc->add(this);
363             running = true;
364         }
365     }
366 
367 // ----------------------------------------------------------------------------------------
368 
369     template <
370         typename T
371         >
372     void timer<T>::
stop()373     stop (
374     )
375     {
376         gc->m.lock();
377         running = false;
378         gc->remove(this);
379         gc->m.unlock();
380     }
381 
382 // ----------------------------------------------------------------------------------------
383 
384     template <
385         typename T
386         >
387     void timer<T>::
thread()388     thread (
389     )
390     {
391         // call the action function
392         (ao.*af)();
393         auto_mutex M(gc->m);
394         if (running)
395         {
396             gc->remove(this);
397             gc->add(this);
398         }
399     }
400 
401 // ----------------------------------------------------------------------------------------
402 
403     template <
404         typename T
405         >
406     void timer<T>::
stop_and_wait()407     stop_and_wait (
408     )
409     {
410         gc->m.lock();
411         running = false;
412         gc->remove(this);
413         gc->m.unlock();
414         wait();
415     }
416 
417 // ----------------------------------------------------------------------------------------
418 
419 }
420 
421 #ifdef NO_MAKEFILE
422 #include "timer.cpp"
423 #endif
424 
425 #endif // DLIB_TIMEr_Hh_
426 
427 
428