1 /*
2 * Copyright (C) 2012 Frafos GmbH
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. This program is released under
10 * the GPL with the additional exemption that compiling, linking,
11 * and/or using OpenSSL is allowed.
12 *
13 * For a license to use the SEMS software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
16 * info@iptel.org
17 *
18 * SEMS is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27 /** @file AmPeriodicThread.cpp */
28
29 #include "AmPeriodicThread.h"
30 #include <assert.h>
31
32 #include "log.h"
33
infinite_loop(struct timeval * tick,unsigned int max_ticks_behind,void * usr_data)34 void AmPeriodicThread::infinite_loop(struct timeval* tick, unsigned int max_ticks_behind, void* usr_data)
35 {
36 struct timeval now,next_tick,diff;
37 unsigned int ticks_passed;
38 unsigned long ms_diff, ms_tick;
39
40 assert(tick);
41 ms_tick = tick->tv_sec * 1000 + tick->tv_usec / 1000;
42
43 gettimeofday(&next_tick,NULL);
44
45 while (true) {
46
47 gettimeofday(&now,NULL);
48 timeradd(tick,&next_tick,&next_tick);
49
50 if(timercmp(&now,&next_tick,<)){
51
52 struct timespec sdiff,rem;
53 timersub(&next_tick,&now,&diff);
54
55 // detect backward clockdrift
56 ms_diff = diff.tv_sec * 1000 + diff.tv_usec / 1000;
57 if(ms_diff / ms_tick > 1) {
58 // at least 2 ticks ahead...
59 next_tick = now;
60 sdiff.tv_sec = tick->tv_sec;
61 sdiff.tv_nsec = tick->tv_usec * 1000;
62
63 WARN("clock drift backwards detected (%lu ticks ahead), "
64 "resetting sw clock\n", ms_diff / ms_tick - 1);
65 }
66 else {
67 // everything ok
68 sdiff.tv_sec = diff.tv_sec;
69 sdiff.tv_nsec = diff.tv_usec * 1000;
70 }
71
72 if(sdiff.tv_nsec > 2000000) // 2 ms
73 nanosleep(&sdiff,&rem);
74
75 ticks_passed = 1;
76 }
77 else {
78 // compute missed ticks
79 unsigned long ms_diff;
80 timersub(&now,&next_tick,&diff);
81 ms_diff = diff.tv_sec * 1000 + diff.tv_usec / 1000;
82 ticks_passed = ms_diff / ms_tick + 1;
83
84 // missed too many ticks: resync
85 if(ticks_passed > max_ticks_behind) {
86 // resync to clock if clock is farther than max_behind_tick in the future
87 WARN("clock drift detected (missed %d ticks), resetting sw clock\n",
88 ticks_passed);
89 next_tick = now;
90 }
91 }
92
93 // execute looping step code
94 if(!looping_step(usr_data))
95 break;
96 }
97 }
98