Merge pull request #63 from BenceJanosSzabo/master
[deliverable/titan.core.git] / core / Timer.cc
1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Balasko, Jeno
10 * Delic, Adam
11 * Kovacs, Ferenc
12 * Raduly, Csaba
13 * Szabo, Janos Zoltan – initial implementation
14 *
15 ******************************************************************************/
16 #include "Timer.hh"
17 #include "Float.hh"
18 #include "Error.hh"
19 #include "Logger.hh"
20 #include "Snapshot.hh"
21
22 TIMER *TIMER::list_head = NULL, *TIMER::list_tail = NULL,
23 *TIMER::backup_head = NULL, *TIMER::backup_tail = NULL;
24 boolean TIMER::control_timers_saved = FALSE;
25
26 void TIMER::add_to_list()
27 {
28 // do nothing if already a member of list
29 if (this == list_head || list_prev != NULL) return;
30 if (list_head == NULL) list_head = this;
31 else if (list_tail != NULL) list_tail->list_next = this;
32 list_prev = list_tail;
33 list_next = NULL;
34 list_tail = this;
35 }
36
37 void TIMER::remove_from_list()
38 {
39 if (list_prev != NULL) list_prev->list_next = list_next;
40 else if (list_head == this) list_head = list_next;
41 if (list_next != NULL) list_next->list_prev = list_prev;
42 else if (list_tail == this) list_tail = list_prev;
43 list_prev = NULL;
44 list_next = NULL;
45 }
46
47 TIMER::TIMER(const char *par_timer_name)
48 {
49 timer_name = par_timer_name != NULL ? par_timer_name : "<unknown>";
50 has_default = FALSE;
51 is_started = FALSE;
52 list_prev = NULL;
53 list_next = NULL;
54 }
55
56 TIMER::TIMER(const char *par_timer_name, double def_val)
57 {
58 if (par_timer_name == NULL)
59 TTCN_error("Internal error: Creating a timer with an invalid name.");
60 timer_name = par_timer_name;
61 set_default_duration(def_val);
62 is_started = FALSE;
63 list_prev = NULL;
64 list_next = NULL;
65 }
66
67 TIMER::TIMER(const char *par_timer_name, const FLOAT& def_val)
68 {
69 if (par_timer_name == NULL)
70 TTCN_error("Internal error: Creating a timer with an invalid name.");
71 timer_name = par_timer_name;
72 def_val.must_bound("Initializing a timer duration with an unbound "
73 "float value.");
74 set_default_duration(def_val.float_value);
75 is_started = FALSE;
76 list_prev = NULL;
77 list_next = NULL;
78 }
79
80 TIMER::~TIMER()
81 {
82 if (is_started) remove_from_list();
83 }
84
85 void TIMER::set_name(const char * name)
86 {
87 if (name == NULL) TTCN_error("Internal error: Setting an "
88 "invalid name for a single element of a timer array.");
89 timer_name = name;
90 }
91
92 void TIMER::set_default_duration(double def_val)
93 {
94 if (def_val < 0.0) {
95 TTCN_error("Setting the default duration of timer %s "
96 "to a negative float value (%g).", timer_name, def_val);
97 } else if (FLOAT::is_special(def_val)) {
98 TTCN_error("Setting the default duration of timer %s "
99 "to a non-numeric float value (%g).", timer_name, def_val);
100 }
101 has_default = TRUE;
102 default_val = def_val;
103 }
104
105 void TIMER::set_default_duration(const FLOAT& def_val)
106 {
107 if (!def_val.is_bound()) TTCN_error("Setting the default duration of "
108 "timer %s to an unbound float value.", timer_name);
109 set_default_duration(def_val.float_value);
110 }
111
112 void TIMER::start()
113 {
114 if (!has_default)
115 TTCN_error("Timer %s does not have default duration. "
116 "It can only be started with a given duration.", timer_name);
117 start(default_val);
118 }
119
120 void TIMER::start(double start_val)
121 {
122 if (this != &testcase_timer) {
123 if (start_val < 0.0)
124 TTCN_error("Starting timer %s with a negative duration (%g).",
125 timer_name, start_val);
126 if (is_started) {
127 TTCN_warning("Re-starting timer %s, which is already active (running "
128 "or expired).", timer_name);
129 remove_from_list();
130 } else {
131 is_started = TRUE;
132 }
133 TTCN_Logger::log_timer_start(timer_name, start_val);
134 add_to_list();
135 } else {
136 if (start_val < 0.0)
137 TTCN_error("Using a negative duration (%g) for the guard timer of the "
138 "test case.", start_val);
139 is_started = TRUE;
140 TTCN_Logger::log_timer_guard(start_val);
141 }
142 t_started = TTCN_Snapshot::time_now();
143 t_expires = t_started + start_val;
144 }
145
146 void TIMER::start(const FLOAT& start_val)
147 {
148 if (!start_val.is_bound())
149 TTCN_error("Starting timer %s with an unbound float value as duration.",
150 timer_name);
151 start(start_val.float_value);
152 }
153
154 void TIMER::stop()
155 {
156 if (this != &testcase_timer) {
157 if (is_started) {
158 is_started = FALSE;
159 TTCN_Logger::log_timer_stop(timer_name, t_expires - t_started);
160 remove_from_list();
161 } else TTCN_warning("Stopping inactive timer %s.", timer_name);
162 } else is_started = FALSE;
163 }
164
165 double TIMER::read() const
166 {
167 // the time is not frozen (i.e. time_now() is used)
168 double ret_val;
169 if (is_started) {
170 double current_time = TTCN_Snapshot::time_now();
171 if (current_time >= t_expires) ret_val = 0.0;
172 else ret_val = current_time - t_started;
173 } else {
174 ret_val = 0.0;
175 }
176 TTCN_Logger::log_timer_read(timer_name, ret_val);
177 return ret_val;
178 }
179
180 boolean TIMER::running() const
181 {
182 // the time is not frozen (i.e. time_now() is used)
183 return is_started && TTCN_Snapshot::time_now() < t_expires;
184 }
185
186 alt_status TIMER::timeout()
187 {
188 // the time is frozen (i.e. get_alt_begin() is used)
189 if (is_started) {
190 if (TTCN_Snapshot::get_alt_begin() < t_expires) return ALT_MAYBE;
191 is_started = FALSE;
192 if (this != &testcase_timer) {
193 TTCN_Logger::log_timer_timeout(timer_name, t_expires - t_started);
194 remove_from_list();
195 }
196 return ALT_YES;
197 } else {
198 if (this != &testcase_timer) {
199 TTCN_Logger::log_matching_timeout(timer_name);
200 }
201 return ALT_NO;
202 }
203 }
204
205 void TIMER::log() const
206 {
207 // the time is not frozen (i.e. time_now() is used)
208 TTCN_Logger::log_event("timer: { name: %s, default duration: ", timer_name);
209 if (has_default) TTCN_Logger::log_event("%g s", default_val);
210 else TTCN_Logger::log_event_str("none");
211 TTCN_Logger::log_event_str(", state: ");
212 if (is_started) {
213 double current_time = TTCN_Snapshot::time_now();
214 if (current_time < t_expires) TTCN_Logger::log_event_str("running");
215 else TTCN_Logger::log_event_str("expired");
216 TTCN_Logger::log_event(", actual duration: %g s, "
217 "elapsed time: %g s", t_expires - t_started,
218 current_time - t_started);
219 } else TTCN_Logger::log_event_str("inactive");
220 TTCN_Logger::log_event_str(" }");
221 }
222
223 void TIMER::all_stop()
224 {
225 while (list_head != NULL) list_head->stop(); // also removes from list
226 }
227
228 boolean TIMER::any_running()
229 {
230 for (TIMER *list_iter = list_head; list_iter != NULL;
231 list_iter = list_iter->list_next) {
232 if (list_iter->running()) return TRUE;
233 }
234 return FALSE;
235 }
236
237 alt_status TIMER::any_timeout()
238 {
239 alt_status ret_val = ALT_NO;
240 for (TIMER *list_iter = list_head; list_iter != NULL;
241 list_iter = list_iter->list_next) {
242 switch (list_iter->timeout()) {
243 case ALT_YES:
244 TTCN_Logger::log_timer_any_timeout();
245 return ALT_YES;
246 case ALT_MAYBE:
247 ret_val = ALT_MAYBE;
248 break;
249 default:
250 TTCN_error("Internal error: Timer %s returned unexpected status "
251 "code while evaluating `any timer.timeout'.",
252 list_iter->timer_name);
253 }
254 }
255 if (ret_val == ALT_NO) {
256 TTCN_Logger::log_matching_timeout(NULL);
257 }
258 return ret_val;
259 }
260
261 boolean TIMER::get_min_expiration(double& min_val)
262 {
263 boolean min_flag = FALSE;
264 double alt_begin = TTCN_Snapshot::get_alt_begin();
265 if (testcase_timer.is_started && testcase_timer.t_expires >= alt_begin) {
266 min_val = testcase_timer.t_expires;
267 min_flag = TRUE;
268 }
269 for (TIMER *list_iter = list_head; list_iter != NULL;
270 list_iter = list_iter->list_next) {
271 // timers that are expired before the previous snapshot are ignored
272 if (list_iter->t_expires < alt_begin) continue;
273 else if (!min_flag || list_iter->t_expires < min_val) {
274 min_val = list_iter->t_expires;
275 min_flag = TRUE;
276 }
277 }
278 return min_flag;
279 }
280
281 void TIMER::save_control_timers()
282 {
283 if (control_timers_saved)
284 TTCN_error("Internal error: Control part timers are already saved.");
285 // put the list of control part timers into the backup
286 backup_head = list_head;
287 list_head = NULL;
288 backup_tail = list_tail;
289 list_tail = NULL;
290 control_timers_saved = TRUE;
291 }
292
293 void TIMER::restore_control_timers()
294 {
295 if (!control_timers_saved)
296 TTCN_error("Internal error: Control part timers are not saved.");
297 if (list_head != NULL)
298 TTCN_error("Internal error: There are active timers. "
299 "Control part timers cannot be restored.");
300 // restore the list of control part timers from the backup
301 list_head = backup_head;
302 backup_head = NULL;
303 list_tail = backup_tail;
304 backup_tail = NULL;
305 control_timers_saved = FALSE;
306 }
307
308 TIMER testcase_timer("<testcase guard timer>");
This page took 0.037881 seconds and 5 git commands to generate.