Titan Core Initial Contribution
[deliverable/titan.core.git] / core / Runtime.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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 #if defined(LINUX) && ! defined(_GNU_SOURCE)
9 // in order to get the prototype of non-standard strsignal()
10 # define _GNU_SOURCE
11 #endif
12
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <ctype.h>
18 #include <netdb.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <signal.h>
22 #include <sys/resource.h>
23 #include <sys/wait.h>
24 #ifdef SOLARIS8
25 #include <sys/utsname.h>
26 #endif
27
28 #include "../common/memory.h"
29 #include "../common/version_internal.h"
30 #include "Runtime.hh"
31 #include "Communication.hh"
32 #include "Error.hh"
33 #include "Logger.hh"
34 #include "Snapshot.hh"
35 #include "Port.hh"
36 #include "Timer.hh"
37 #include "Module_list.hh"
38 #include "Component.hh"
39 #include "Default.hh"
40 #include "Verdicttype.hh"
41 #include "Charstring.hh"
42 #include "Fd_And_Timeout_User.hh"
43 #include <TitanLoggerApi.hh>
44
45 namespace API = TitanLoggerApi;
46
47 #ifndef MAXHOSTNAMELEN
48 # define MAXHOSTNAMELEN 256
49 #endif
50
51 #include "../common/dbgnew.hh"
52
53 TTCN_Runtime::executor_state_enum
54 TTCN_Runtime::executor_state = UNDEFINED_STATE;
55
56 qualified_name TTCN_Runtime::component_type = { NULL, NULL };
57 char *TTCN_Runtime::component_name = NULL;
58 boolean TTCN_Runtime::is_alive = FALSE;
59
60 const char *TTCN_Runtime::control_module_name = NULL;
61 qualified_name TTCN_Runtime::testcase_name = { NULL, NULL };
62
63 char *TTCN_Runtime::host_name = NULL;
64
65 verdicttype TTCN_Runtime::local_verdict = NONE;
66 unsigned int TTCN_Runtime::verdict_count[5] = { 0, 0, 0, 0, 0 },
67 TTCN_Runtime::control_error_count = 0;
68 CHARSTRING TTCN_Runtime::verdict_reason(0, ""); // empty string
69
70 boolean TTCN_Runtime::in_ttcn_try_block = FALSE;
71
72 char *TTCN_Runtime::begin_controlpart_command = NULL,
73 *TTCN_Runtime::end_controlpart_command = NULL,
74 *TTCN_Runtime::begin_testcase_command = NULL,
75 *TTCN_Runtime::end_testcase_command = NULL;
76
77 component TTCN_Runtime::create_done_killed_compref = NULL_COMPREF;
78 boolean TTCN_Runtime::running_alive_result = FALSE;
79
80 alt_status TTCN_Runtime::any_component_done_status = ALT_UNCHECKED,
81 TTCN_Runtime::all_component_done_status = ALT_UNCHECKED,
82 TTCN_Runtime::any_component_killed_status = ALT_UNCHECKED,
83 TTCN_Runtime::all_component_killed_status = ALT_UNCHECKED;
84 int TTCN_Runtime::component_status_table_size = 0;
85 component TTCN_Runtime::component_status_table_offset = FIRST_PTC_COMPREF;
86 struct TTCN_Runtime::component_status_table_struct {
87 alt_status done_status, killed_status;
88 char *return_type;
89 Text_Buf *return_value;
90 } *TTCN_Runtime::component_status_table = NULL;
91
92 struct TTCN_Runtime::component_process_struct {
93 component component_reference;
94 pid_t process_id;
95 boolean process_killed;
96 struct component_process_struct *prev_by_compref, *next_by_compref;
97 struct component_process_struct *prev_by_pid, *next_by_pid;
98 } **TTCN_Runtime::components_by_compref = NULL,
99 **TTCN_Runtime::components_by_pid = NULL;
100
101 boolean TTCN_Runtime::is_idle()
102 {
103 switch (executor_state) {
104 case HC_IDLE:
105 case HC_ACTIVE:
106 case HC_OVERLOADED:
107 case MTC_IDLE:
108 case PTC_IDLE:
109 case PTC_STOPPED:
110 return TRUE;
111 default:
112 return FALSE;
113 }
114 }
115
116 boolean TTCN_Runtime::verdict_enabled()
117 {
118 return executor_state == SINGLE_TESTCASE ||
119 (executor_state >= MTC_TESTCASE && executor_state <= MTC_EXIT) ||
120 (executor_state >= PTC_INITIAL && executor_state <= PTC_EXIT);
121 }
122
123 void TTCN_Runtime::wait_for_state_change()
124 {
125 executor_state_enum old_state = executor_state;
126 do {
127 TTCN_Snapshot::take_new(TRUE);
128 } while (old_state == executor_state);
129 }
130
131 void TTCN_Runtime::clear_qualified_name(qualified_name& q_name)
132 {
133 Free(q_name.module_name);
134 q_name.module_name = NULL;
135 Free(q_name.definition_name);
136 q_name.definition_name = NULL;
137 }
138
139 void TTCN_Runtime::clean_up()
140 {
141 clear_qualified_name(component_type);
142 Free(component_name);
143 component_name = NULL;
144 control_module_name = NULL;
145 clear_qualified_name(testcase_name);
146 Free(host_name);
147 host_name = NULL;
148 clear_external_commands();
149 }
150
151 void TTCN_Runtime::initialize_component_type()
152 {
153 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__start,
154 component_type.module_name, component_type.definition_name, 0, NULL,
155 TTCN_Runtime::get_testcase_name());
156
157 Module_List::initialize_component(component_type.module_name,
158 component_type.definition_name, TRUE);
159 PORT::set_parameters((component)self, component_name);
160 PORT::all_start();
161
162 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__finish,
163 component_type.module_name, component_type.definition_name);
164
165 local_verdict = NONE;
166 verdict_reason = "";
167 }
168
169 void TTCN_Runtime::terminate_component_type()
170 {
171 if (component_type.module_name != NULL &&
172 component_type.definition_name != NULL) {
173 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::terminating__component,
174 component_type.module_name, component_type.definition_name);
175
176 TTCN_Default::deactivate_all();
177 TIMER::all_stop();
178 PORT::deactivate_all();
179
180 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::component__shut__down,
181 component_type.module_name, component_type.definition_name, 0, NULL,
182 TTCN_Runtime::get_testcase_name());
183
184 clear_qualified_name(component_type);
185 Free(component_name);
186 component_name = NULL;
187 }
188 }
189
190 void TTCN_Runtime::set_component_type(const char *component_type_module,
191 const char *component_type_name)
192 {
193 if (component_type_module == NULL || component_type_module[0] == '\0' ||
194 component_type_name == NULL || component_type_name[0] == '\0')
195 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
196 "Trying to set an invalid component type.");
197 if (component_type.module_name != NULL ||
198 component_type.definition_name != NULL)
199 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
200 "Trying to set component type %s.%s while another one is active.",
201 component_type_module, component_type_name);
202
203 component_type.module_name = mcopystr(component_type_module);
204 component_type.definition_name = mcopystr(component_type_name);
205 }
206
207 void TTCN_Runtime::set_component_name(const char *new_component_name)
208 {
209 Free(component_name);
210 if (new_component_name != NULL && new_component_name[0] != '\0')
211 component_name = mcopystr(new_component_name);
212 else component_name = NULL;
213 }
214
215 void TTCN_Runtime::set_testcase_name(const char *par_module_name,
216 const char *par_testcase_name)
217 {
218 if (par_module_name == NULL || par_module_name[0] == '\0' ||
219 par_testcase_name == NULL || par_testcase_name[0] == '\0')
220 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
221 "Trying to set an invalid testcase name.");
222 if (testcase_name.module_name != NULL ||
223 testcase_name.definition_name != NULL)
224 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
225 "Trying to set testcase name %s.%s while another one is active.",
226 par_module_name, par_testcase_name);
227
228 testcase_name.module_name = mcopystr(par_module_name);
229 testcase_name.definition_name = mcopystr(par_testcase_name);
230 }
231
232 const char *TTCN_Runtime::get_host_name()
233 {
234 if (host_name == NULL) {
235 #if defined(SOLARIS8)
236 // Workaround for Solaris10 (lumped under SOLARIS8) + dynamic linking.
237 // "g++ -shared" seems to produce a very strange kind of symbol
238 // for gethostname in the .so, and linking fails with the infamous
239 // "ld: libttcn3-dynamic.so: gethostname: invalid version 3 (max 0)"
240 // The workaround is to use uname instead of gethostname.
241 struct utsname uts;
242 if (uname(&uts) < 0) {
243 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED);
244 TTCN_Logger::log_event_str("System call uname() failed.");
245 TTCN_Logger::OS_error();
246 TTCN_Logger::end_event();
247 host_name = mcopystr("unknown");
248 } else {
249 host_name = mcopystr(uts.nodename);
250 }
251 #else
252 char tmp_str[MAXHOSTNAMELEN + 1];
253 if (gethostname(tmp_str, MAXHOSTNAMELEN)) {
254 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED);
255 TTCN_Logger::log_event_str("System call gethostname() failed.");
256 TTCN_Logger::OS_error();
257 TTCN_Logger::end_event();
258 tmp_str[0] = '\0';
259 } else tmp_str[MAXHOSTNAMELEN] = '\0';
260 if (tmp_str[0] != '\0') host_name = mcopystr(tmp_str);
261 else host_name = mcopystr("unknown");
262 #endif
263 }
264 return host_name;
265 }
266
267 CHARSTRING TTCN_Runtime::get_testcase_id_macro()
268 {
269 if (in_controlpart()) TTCN_error("Macro %%testcaseId cannot be used from "
270 "the control part outside test cases.");
271 if (testcase_name.definition_name == NULL ||
272 testcase_name.definition_name[0] == '\0')
273 TTCN_error("Internal error: Evaluating macro %%testcaseId, but the "
274 "name of the current testcase is not set.");
275 return CHARSTRING(testcase_name.definition_name);
276 }
277
278 CHARSTRING TTCN_Runtime::get_testcasename()
279 {
280 if (in_controlpart()) return CHARSTRING(""); // No error here.
281
282 if (!testcase_name.definition_name || testcase_name.definition_name[0] == 0)
283 TTCN_error("Internal error: Evaluating predefined function testcasename()"
284 ", but the name of the current testcase is not set.");
285
286 return CHARSTRING(testcase_name.definition_name);
287 }
288
289 void TTCN_Runtime::load_logger_plugins()
290 {
291 TTCN_Logger::load_plugins((component)self, component_name);
292 }
293
294 void TTCN_Runtime::set_logger_parameters()
295 {
296 TTCN_Logger::set_plugin_parameters((component)self, component_name);
297 }
298
299 const char *TTCN_Runtime::get_signal_name(int signal_number)
300 {
301 const char *signal_name = strsignal(signal_number);
302 if (signal_name != NULL) return signal_name;
303 else return "Unknown signal";
304 }
305
306 static void sigint_handler(int signum)
307 {
308 if (signum != SIGINT) {
309 TTCN_warning("Unexpected signal %d (%s) was caught by the handler of "
310 "SIGINT.", signum, TTCN_Runtime::get_signal_name(signum));
311 return;
312 }
313 if (TTCN_Runtime::is_single()) {
314 TTCN_Logger::log_str(TTCN_Logger::WARNING_UNQUALIFIED,
315 "Execution was interrupted by the user.");
316 if (TTCN_Runtime::get_state() == TTCN_Runtime::SINGLE_TESTCASE) {
317 TTCN_Logger::log_executor_runtime(
318 API::ExecutorRuntime_reason::stopping__current__testcase);
319 TTCN_Runtime::end_testcase();
320 } else {
321 TIMER::all_stop();
322 }
323 TTCN_Logger::log_executor_runtime(
324 API::ExecutorRuntime_reason::exiting);
325 exit(EXIT_FAILURE);
326 }
327 }
328
329
330 void TTCN_Runtime::set_signal_handler(int signal_number,
331 const char *signal_name, signal_handler_type signal_handler)
332 {
333 struct sigaction sig_act;
334 if (sigaction(signal_number, NULL, &sig_act))
335 TTCN_error("System call sigaction() failed when getting signal "
336 "handling information for %s.", signal_name);
337 sig_act.sa_handler = signal_handler;
338 sig_act.sa_flags = 0;
339 if (sigaction(signal_number, &sig_act, NULL))
340 TTCN_error("System call sigaction() failed when changing the signal "
341 "handling settings for %s.", signal_name);
342 }
343
344 void TTCN_Runtime::restore_default_handler(int signal_number,
345 const char *signal_name)
346 {
347 struct sigaction sig_act;
348 if (sigaction(signal_number, NULL, &sig_act))
349 TTCN_error("System call sigaction() failed when getting signal "
350 "handling information for %s.", signal_name);
351 sig_act.sa_handler = SIG_DFL;
352 sig_act.sa_flags = 0;
353 if (sigaction(signal_number, &sig_act, NULL))
354 TTCN_error("System call sigaction() failed when restoring the "
355 "default signal handling settings for %s.", signal_name);
356 }
357
358 void TTCN_Runtime::ignore_signal(int signal_number, const char *signal_name)
359 {
360 struct sigaction sig_act;
361 if (sigaction(signal_number, NULL, &sig_act))
362 TTCN_error("System call sigaction() failed when getting signal "
363 "handling information for %s.", signal_name);
364 sig_act.sa_handler = SIG_IGN;
365 sig_act.sa_flags = 0;
366 if (sigaction(signal_number, &sig_act, NULL))
367 TTCN_error("System call sigaction() failed when disabling signal "
368 "%s.", signal_name);
369 }
370
371 void TTCN_Runtime::enable_interrupt_handler()
372 {
373 set_signal_handler(SIGINT, "SIGINT", sigint_handler);
374 }
375
376 void TTCN_Runtime::disable_interrupt_handler()
377 {
378 ignore_signal(SIGINT, "SIGINT");
379 }
380
381 void TTCN_Runtime::install_signal_handlers()
382 {
383 if (is_single()) set_signal_handler(SIGINT, "SIGINT", sigint_handler);
384 ignore_signal(SIGPIPE, "SIGPIPE");
385 }
386
387 void TTCN_Runtime::restore_signal_handlers()
388 {
389 if (is_single()) restore_default_handler(SIGINT, "SIGINT");
390 restore_default_handler(SIGPIPE, "SIGPIPE");
391 }
392
393 int TTCN_Runtime::hc_main(const char *local_addr, const char *MC_addr,
394 unsigned short MC_port)
395 {
396 int ret_val = EXIT_SUCCESS;
397 executor_state = HC_INITIAL;
398 TTCN_Logger::log_HC_start(get_host_name());
399 TTCN_Logger::write_logger_settings();
400 TTCN_Snapshot::check_fd_setsize();
401 try {
402 if (local_addr != NULL)
403 TTCN_Communication::set_local_address(local_addr);
404 TTCN_Communication::set_mc_address(MC_addr, MC_port);
405 TTCN_Communication::connect_mc();
406 executor_state = HC_IDLE;
407 TTCN_Communication::send_version();
408 initialize_component_process_tables();
409 do {
410 TTCN_Snapshot::take_new(TRUE);
411 TTCN_Communication::process_all_messages_hc();
412 } while (executor_state >= HC_IDLE && executor_state < HC_EXIT);
413 if (executor_state == HC_EXIT) {
414 // called only on the HC
415 TTCN_Communication::disconnect_mc();
416 clean_up();
417 }
418 } catch (const TC_Error& tc_error) {
419 ret_val = EXIT_FAILURE;
420 clean_up();
421 }
422 // called on the newly created MTC and PTCs as well because
423 // the hashtables are inherited with fork()
424 clear_component_process_tables();
425
426 if (is_hc())
427 TTCN_Logger::log_executor_runtime(
428 API::ExecutorRuntime_reason::host__controller__finished);
429
430 return ret_val;
431 }
432
433 int TTCN_Runtime::mtc_main()
434 {
435 int ret_val = EXIT_SUCCESS;
436 TTCN_Runtime::load_logger_plugins();
437 TTCN_Runtime::set_logger_parameters();
438 TTCN_Logger::open_file();
439 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__started);
440 TTCN_Logger::write_logger_settings();
441 try {
442 TTCN_Communication::connect_mc();
443 executor_state = MTC_IDLE;
444 TTCN_Communication::send_mtc_created();
445 do {
446 TTCN_Snapshot::take_new(TRUE);
447 TTCN_Communication::process_all_messages_tc();
448 } while (executor_state != MTC_EXIT);
449 TTCN_Logger::close_file();
450 TTCN_Communication::disconnect_mc();
451 clean_up();
452 } catch (const TC_Error& tc_error) {
453 ret_val = EXIT_FAILURE;
454 }
455 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__finished);
456 return ret_val;
457 }
458
459 int TTCN_Runtime::ptc_main()
460 {
461 int ret_val = EXIT_SUCCESS;
462 TTCN_Runtime::load_logger_plugins();
463 TTCN_Runtime::set_logger_parameters();
464 TTCN_Logger::open_file();
465 TTCN_Logger::begin_event(TTCN_Logger::EXECUTOR_COMPONENT);
466 TTCN_Logger::log_event("TTCN-3 Parallel Test Component started on %s. "
467 "Component reference: ", get_host_name());
468 self.log();
469 TTCN_Logger::log_event(", component type: %s.%s",
470 component_type.module_name, component_type.definition_name);
471 if (component_name != NULL)
472 TTCN_Logger::log_event(", component name: %s", component_name);
473 TTCN_Logger::log_event_str(". Version: " PRODUCT_NUMBER ".");
474 TTCN_Logger::end_event();
475 TTCN_Logger::write_logger_settings();
476 try {
477 TTCN_Communication::connect_mc();
478 executor_state = PTC_IDLE;
479 TTCN_Communication::send_ptc_created((component)self);
480 try {
481 initialize_component_type();
482 } catch (const TC_Error& tc_error) {
483 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::component__init__fail);
484 ret_val = EXIT_FAILURE;
485 }
486 if (ret_val == EXIT_SUCCESS) {
487 try {
488 do {
489 TTCN_Snapshot::take_new(TRUE);
490 TTCN_Communication::process_all_messages_tc();
491 } while (executor_state != PTC_EXIT);
492 } catch (const TC_Error& tc_error) {
493 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::error__idle__ptc);
494 ret_val = EXIT_FAILURE;
495 }
496 }
497 if (ret_val != EXIT_SUCCESS) {
498 // ignore errors in subsequent operations
499 try {
500 terminate_component_type();
501 } catch (const TC_Error& tc_error) { }
502 try {
503 TTCN_Communication::send_killed(local_verdict, (const char *)verdict_reason);
504 } catch (const TC_Error& tc_error) { }
505 TTCN_Logger::log_final_verdict(true, local_verdict, local_verdict,
506 local_verdict, (const char *)verdict_reason);
507 executor_state = PTC_EXIT;
508 }
509 TTCN_Communication::disconnect_mc();
510 clear_component_status_table();
511 clean_up();
512 } catch (const TC_Error& tc_error) {
513 ret_val = EXIT_FAILURE;
514 }
515 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::ptc__finished);
516 return ret_val;
517 }
518
519 component TTCN_Runtime::create_component(
520 const char *created_component_type_module,
521 const char *created_component_type_name, const char *created_component_name,
522 const char *created_component_location, boolean created_component_alive)
523 {
524 if (in_controlpart())
525 TTCN_error("Create operation cannot be performed in the control part.");
526 else if (is_single())
527 TTCN_error("Create operation cannot be performed in single mode.");
528
529 if (created_component_name != NULL &&
530 created_component_name[0] == '\0') {
531 TTCN_warning("Empty charstring value was ignored as component name "
532 "in create operation.");
533 created_component_name = NULL;
534 }
535 if (created_component_location != NULL &&
536 created_component_location[0] == '\0') {
537 TTCN_warning("Empty charstring value was ignored as component location "
538 "in create operation.");
539 created_component_location = NULL;
540 }
541
542 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED);
543 TTCN_Logger::log_event("Creating new %sPTC with component type %s.%s",
544 created_component_alive ? "alive ": "", created_component_type_module,
545 created_component_type_name);
546 if (created_component_name != NULL)
547 TTCN_Logger::log_event(", component name: %s", created_component_name);
548 if (created_component_location != NULL)
549 TTCN_Logger::log_event(", location: %s", created_component_location);
550 TTCN_Logger::log_char('.');
551 TTCN_Logger::end_event();
552
553 switch (executor_state) {
554 case MTC_TESTCASE:
555 executor_state = MTC_CREATE;
556 break;
557 case PTC_FUNCTION:
558 executor_state = PTC_CREATE;
559 break;
560 default:
561 TTCN_error("Internal error: Executing create operation in invalid "
562 "state.");
563 }
564 TTCN_Communication::send_create_req(created_component_type_module,
565 created_component_type_name, created_component_name,
566 created_component_location, created_component_alive);
567 if (is_mtc()) {
568 // updating the component status flags
569 // 'any component.done' and 'any component.killed' might be successful
570 // from now since the PTC can terminate by itself
571 if (any_component_done_status == ALT_NO)
572 any_component_done_status = ALT_UNCHECKED;
573 if (any_component_killed_status == ALT_NO)
574 any_component_killed_status = ALT_UNCHECKED;
575 // 'all component.killed' must be re-evaluated later
576 all_component_killed_status = ALT_UNCHECKED;
577 }
578 wait_for_state_change();
579
580 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created,
581 created_component_type_module, created_component_type_name,
582 create_done_killed_compref, created_component_name,
583 created_component_location, created_component_alive);
584
585 COMPONENT::register_component_name(create_done_killed_compref,
586 created_component_name);
587 return create_done_killed_compref;
588 }
589
590 void TTCN_Runtime::prepare_start_component(const COMPONENT& component_reference,
591 const char *module_name, const char *function_name, Text_Buf& text_buf)
592 {
593 if (in_controlpart()) TTCN_error("Start test component operation cannot "
594 "be performed in the control part.");
595 else if (is_single()) TTCN_error("Start test component operation cannot "
596 "be performed in single mode.");
597 if (!component_reference.is_bound()) TTCN_error("Performing a start "
598 "operation on an unbound component reference.");
599 component compref = (component)component_reference;
600 switch (compref) {
601 case NULL_COMPREF:
602 TTCN_error("Start operation cannot be performed on the null "
603 "component reference.");
604 case MTC_COMPREF:
605 TTCN_error("Start operation cannot be performed on the component "
606 "reference of MTC.");
607 case SYSTEM_COMPREF:
608 TTCN_error("Start operation cannot be performed on the component "
609 "reference of system.");
610 case ANY_COMPREF:
611 TTCN_error("Internal error: 'any component' cannot be started.");
612 case ALL_COMPREF:
613 TTCN_error("Internal error: 'all component' cannot be started.");
614 default:
615 break;
616 }
617 if (self == compref) TTCN_error("Start operation cannot be performed on "
618 "the own component reference of the initiating component (i.e. "
619 "'self.start' is not allowed).");
620 if (in_component_status_table(compref)) {
621 if (get_killed_status(compref) == ALT_YES) {
622 TTCN_error("PTC with component reference %d is not alive anymore. "
623 "Start operation cannot be performed on it.", compref);
624 }
625 // the done status of the PTC shall be invalidated
626 cancel_component_done(compref);
627 }
628 TTCN_Communication::prepare_start_req(text_buf, compref, module_name,
629 function_name);
630 }
631
632 void TTCN_Runtime::send_start_component(Text_Buf& text_buf)
633 {
634 switch (executor_state) {
635 case MTC_TESTCASE:
636 executor_state = MTC_START;
637 break;
638 case PTC_FUNCTION:
639 executor_state = PTC_START;
640 break;
641 default:
642 TTCN_error("Internal error: Executing component start operation "
643 "in invalid state.");
644 }
645 // text_buf already contains a complete START_REQ message.
646 TTCN_Communication::send_message(text_buf);
647 if (is_mtc()) {
648 // updating the component status flags
649 // 'all component.done' must be re-evaluated later
650 all_component_done_status = ALT_UNCHECKED;
651 }
652 wait_for_state_change();
653 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__started);
654 }
655
656 void TTCN_Runtime::start_function(const char *module_name,
657 const char *function_name, Text_Buf& text_buf)
658 {
659 switch (executor_state) {
660 case PTC_IDLE:
661 case PTC_STOPPED:
662 break;
663 default:
664 // the START message must be dropped here because normally it is
665 // dropped in function_started()
666 text_buf.cut_message();
667 TTCN_error("Internal error: Message START arrived in invalid state.");
668 }
669 try {
670 Module_List::start_function(module_name, function_name, text_buf);
671 // do nothing: the function terminated normally
672 // the message STOPPED or STOPPED_KILLED is already sent out
673 // and the state variable is updated
674 return;
675 } catch (const TC_End& TC_end) {
676 // executor_state is already set by stop_execution or kill_execution
677 switch (executor_state) {
678 case PTC_STOPPED:
679 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
680 "Function %s was stopped. PTC remains alive and is waiting for next start.",
681 function_name);
682 // send a STOPPED message without return value
683 TTCN_Communication::send_stopped();
684 // return and do nothing else
685 return;
686 case PTC_EXIT:
687 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__stopped, NULL,
688 function_name);
689 break;
690 default:
691 TTCN_error("Internal error: PTC was stopped in invalid state.");
692 }
693 } catch (const TC_Error& TC_error) {
694 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__error, NULL,
695 function_name);
696 executor_state = PTC_EXIT;
697 }
698 // the control reaches this code if the PTC has to be terminated
699
700 // first terminate all ports and timers
701 // this may affect the final verdict
702 terminate_component_type();
703 // send a STOPPED_KILLED message without return value
704 TTCN_Communication::send_stopped_killed(local_verdict, verdict_reason);
705 TTCN_Logger::log_final_verdict(true, local_verdict, local_verdict,
706 local_verdict, (const char *)verdict_reason);
707 }
708
709 void TTCN_Runtime::function_started(Text_Buf& text_buf)
710 {
711 // The buffer still contains the incoming START message.
712 text_buf.cut_message();
713 executor_state = PTC_FUNCTION;
714 // The remaining messages must be processed now.
715 TTCN_Communication::process_all_messages_tc();
716 }
717
718 void TTCN_Runtime::prepare_function_finished(const char *return_type,
719 Text_Buf& text_buf)
720 {
721 if (executor_state != PTC_FUNCTION)
722 TTCN_error("Internal error: PTC behaviour function finished in invalid "
723 "state.");
724 if (is_alive) {
725 // Prepare a STOPPED message with the possible return value.
726 TTCN_Communication::prepare_stopped(text_buf, return_type);
727 } else {
728 // First the ports and timers must be stopped and deactivated. The
729 // user_unmap and user_stop functions of Test Ports may detect errors
730 // that must be considered in the final verdict of the PTC.
731 terminate_component_type();
732 // Prepare a STOPPED_KILLED message with the final verdict and the
733 // possible return value.
734 TTCN_Communication::prepare_stopped_killed(text_buf, local_verdict,
735 return_type, verdict_reason);
736 }
737 }
738
739 void TTCN_Runtime::send_function_finished(Text_Buf& text_buf)
740 {
741 // send out the STOPPED or STOPPED_KILLED message, which is already
742 // complete and contains the return value
743 TTCN_Communication::send_message(text_buf);
744 // log the final verdict if necessary and update the state variable
745 if (is_alive) executor_state = PTC_STOPPED;
746 else {
747 TTCN_Logger::log_final_verdict(true, local_verdict, local_verdict,
748 local_verdict, (const char *)verdict_reason);
749 executor_state = PTC_EXIT;
750 }
751 }
752
753 void TTCN_Runtime::function_finished(const char *function_name)
754 {
755 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__finished, NULL,
756 function_name, 0, NULL, NULL, is_alive);
757 Text_Buf text_buf;
758 prepare_function_finished(NULL, text_buf);
759 send_function_finished(text_buf);
760 }
761
762 alt_status TTCN_Runtime::component_done(component component_reference)
763 {
764 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
765 "in the control part.");
766 switch (component_reference) {
767 case NULL_COMPREF:
768 TTCN_error("Done operation cannot be performed on the null "
769 "component reference.");
770 case MTC_COMPREF:
771 TTCN_error("Done operation cannot be performed on the component "
772 "reference of MTC.");
773 case SYSTEM_COMPREF:
774 TTCN_error("Done operation cannot be performed on the component "
775 "reference of system.");
776 case ANY_COMPREF:
777 return any_component_done();
778 case ALL_COMPREF:
779 return all_component_done();
780 default:
781 return ptc_done(component_reference);
782 }
783 }
784
785 alt_status TTCN_Runtime::component_done(component component_reference,
786 const char *return_type, Text_Buf*& text_buf)
787 {
788 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
789 "in the control part.");
790 switch (component_reference) {
791 case NULL_COMPREF:
792 TTCN_error("Done operation cannot be performed on the null "
793 "component reference.");
794 case MTC_COMPREF:
795 TTCN_error("Done operation cannot be performed on the component "
796 "reference of MTC.");
797 case SYSTEM_COMPREF:
798 TTCN_error("Done operation cannot be performed on the component "
799 "reference of system.");
800 case ANY_COMPREF:
801 TTCN_error("Done operation with return value cannot be performed on "
802 "'any component'.");
803 case ALL_COMPREF:
804 TTCN_error("Done operation with return value cannot be performed on "
805 "'all component'.");
806 default:
807 // the argument refers to a PTC
808 break;
809 }
810 if (is_single()) TTCN_error("Done operation on a component reference "
811 "cannot be performed in single mode.");
812 if (self == component_reference) {
813 TTCN_warning("Done operation on the component reference of self "
814 "will never succeed.");
815 return ALT_NO;
816 } else {
817 int index = get_component_status_table_index(component_reference);
818 // we cannot use the killed status because we need the return value
819 switch (component_status_table[index].done_status) {
820 case ALT_UNCHECKED:
821 switch (executor_state) {
822 case MTC_TESTCASE:
823 executor_state = MTC_DONE;
824 break;
825 case PTC_FUNCTION:
826 executor_state = PTC_DONE;
827 break;
828 default:
829 TTCN_error("Internal error: Executing done operation in "
830 "invalid state.");
831 }
832 TTCN_Communication::send_done_req(component_reference);
833 component_status_table[index].done_status = ALT_MAYBE;
834 create_done_killed_compref = component_reference;
835 // wait for DONE_ACK
836 wait_for_state_change();
837 // always re-evaluate the current alternative using a new snapshot
838 return ALT_REPEAT;
839 case ALT_YES:
840 if (component_status_table[index].return_type != NULL) {
841 if (!strcmp(component_status_table[index].return_type,
842 return_type)) {
843 component_status_table[index].return_value->rewind();
844 text_buf = component_status_table[index].return_value;
845 return ALT_YES;
846 } else {
847 TTCN_Logger::log_matching_done(return_type, component_reference,
848 component_status_table[index].return_type,
849 API::MatchingDoneType_reason::done__failed__wrong__return__type);
850 return ALT_NO;
851 }
852 } else {
853 TTCN_Logger::log_matching_done(return_type, component_reference, NULL,
854 API::MatchingDoneType_reason::done__failed__no__return);
855 return ALT_NO;
856 }
857 default:
858 return ALT_MAYBE;
859 }
860 }
861 }
862
863 alt_status TTCN_Runtime::component_killed(component component_reference)
864 {
865 if (in_controlpart()) TTCN_error("Killed operation cannot be performed "
866 "in the control part.");
867 switch (component_reference) {
868 case NULL_COMPREF:
869 TTCN_error("Killed operation cannot be performed on the null "
870 "component reference.");
871 case MTC_COMPREF:
872 TTCN_error("Killed operation cannot be performed on the component "
873 "reference of MTC.");
874 case SYSTEM_COMPREF:
875 TTCN_error("Killed operation cannot be performed on the component "
876 "reference of system.");
877 case ANY_COMPREF:
878 return any_component_killed();
879 case ALL_COMPREF:
880 return all_component_killed();
881 default:
882 return ptc_killed(component_reference);
883 }
884 }
885
886 boolean TTCN_Runtime::component_running(component component_reference)
887 {
888 if (in_controlpart()) TTCN_error("Component running operation "
889 "cannot be performed in the control part.");
890 switch (component_reference) {
891 case NULL_COMPREF:
892 TTCN_error("Running operation cannot be performed on the null "
893 "component reference.");
894 case MTC_COMPREF:
895 TTCN_error("Running operation cannot be performed on the component "
896 "reference of MTC.");
897 case SYSTEM_COMPREF:
898 TTCN_error("Running operation cannot be performed on the component "
899 "reference of system.");
900 case ANY_COMPREF:
901 return any_component_running();
902 case ALL_COMPREF:
903 return all_component_running();
904 default:
905 return ptc_running(component_reference);
906 }
907 }
908
909 boolean TTCN_Runtime::component_alive(component component_reference)
910 {
911 if (in_controlpart()) TTCN_error("Alive operation cannot be performed "
912 "in the control part.");
913 switch (component_reference) {
914 case NULL_COMPREF:
915 TTCN_error("Alive operation cannot be performed on the null "
916 "component reference.");
917 case MTC_COMPREF:
918 TTCN_error("Alive operation cannot be performed on the component "
919 "reference of MTC.");
920 case SYSTEM_COMPREF:
921 TTCN_error("Alive operation cannot be performed on the component "
922 "reference of system.");
923 case ANY_COMPREF:
924 return any_component_alive();
925 case ALL_COMPREF:
926 return all_component_alive();
927 default:
928 return ptc_alive(component_reference);
929 }
930 }
931
932 void TTCN_Runtime::stop_component(component component_reference)
933 {
934 if (in_controlpart()) TTCN_error("Component stop operation cannot be "
935 "performed in the control part.");
936
937 if (self == component_reference) stop_execution();
938 switch (component_reference) {
939 case NULL_COMPREF:
940 TTCN_error("Stop operation cannot be performed on the null component "
941 "reference.");
942 case MTC_COMPREF:
943 stop_mtc();
944 break;
945 case SYSTEM_COMPREF:
946 TTCN_error("Stop operation cannot be performed on the component "
947 "reference of system.");
948 case ANY_COMPREF:
949 TTCN_error("Internal error: 'any component' cannot be stopped.");
950 case ALL_COMPREF:
951 stop_all_component();
952 break;
953 default:
954 stop_ptc(component_reference);
955 }
956 }
957
958 void TTCN_Runtime::stop_execution()
959 {
960 if (in_controlpart()) {
961 TTCN_Logger::log_executor_runtime(
962 API::ExecutorRuntime_reason::stopping__control__part__execution);
963 } else {
964 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED,
965 "Stopping test component execution.");
966 if (is_ptc()) {
967 // the state variable indicates whether the component remains alive
968 // after termination or not
969 if (is_alive) executor_state = PTC_STOPPED;
970 else executor_state = PTC_EXIT;
971 }
972 }
973 throw TC_End();
974 }
975
976 void TTCN_Runtime::kill_component(component component_reference)
977 {
978 if (in_controlpart()) TTCN_error("Kill operation cannot be performed in "
979 "the control part.");
980
981 if (self == component_reference) kill_execution();
982 switch (component_reference) {
983 case NULL_COMPREF:
984 TTCN_error("Kill operation cannot be performed on the null component "
985 "reference.");
986 case MTC_COMPREF:
987 // 'mtc.kill' means exactly the same as 'mtc.stop'
988 stop_mtc();
989 break;
990 case SYSTEM_COMPREF:
991 TTCN_error("Kill operation cannot be performed on the component "
992 "reference of system.");
993 case ANY_COMPREF:
994 TTCN_error("Internal error: 'any component' cannot be killed.");
995 case ALL_COMPREF:
996 kill_all_component();
997 break;
998 default:
999 kill_ptc(component_reference);
1000 }
1001 }
1002
1003 void TTCN_Runtime::kill_execution()
1004 {
1005 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED,
1006 "Terminating test component execution.");
1007 if (is_ptc()) executor_state = PTC_EXIT;
1008 throw TC_End();
1009 }
1010
1011 alt_status TTCN_Runtime::ptc_done(component component_reference)
1012 {
1013 if (is_single()) TTCN_error("Done operation on a component reference "
1014 "cannot be performed in single mode.");
1015 if (self == component_reference) {
1016 TTCN_warning("Done operation on the component reference of self "
1017 "will never succeed.");
1018 return ALT_NO;
1019 }
1020 int index = get_component_status_table_index(component_reference);
1021 // a successful killed operation on the component reference implies done
1022 if (component_status_table[index].killed_status == ALT_YES)
1023 goto success;
1024 switch (component_status_table[index].done_status) {
1025 case ALT_UNCHECKED:
1026 switch (executor_state) {
1027 case MTC_TESTCASE:
1028 executor_state = MTC_DONE;
1029 break;
1030 case PTC_FUNCTION:
1031 executor_state = PTC_DONE;
1032 break;
1033 default:
1034 TTCN_error("Internal error: Executing done operation in "
1035 "invalid state.");
1036 }
1037 TTCN_Communication::send_done_req(component_reference);
1038 component_status_table[index].done_status = ALT_MAYBE;
1039 create_done_killed_compref = component_reference;
1040 // wait for DONE_ACK
1041 wait_for_state_change();
1042 // always re-evaluate the current alternative using a new snapshot
1043 return ALT_REPEAT;
1044 case ALT_YES:
1045 goto success;
1046 default:
1047 return ALT_MAYBE;
1048 }
1049 success:
1050 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__done,
1051 NULL, NULL, component_reference);
1052 return ALT_YES;
1053 }
1054
1055 alt_status TTCN_Runtime::any_component_done()
1056 {
1057 // the operation is never successful in single mode
1058 if (is_single()) goto failure;
1059 if (!is_mtc()) TTCN_error("Operation 'any component.done' can only be "
1060 "performed on the MTC.");
1061 // the operation is successful if there is a component reference with a
1062 // successful done or killed operation
1063 for (int i = 0; i < component_status_table_size; i++) {
1064 if (component_status_table[i].done_status == ALT_YES ||
1065 component_status_table[i].killed_status == ALT_YES) goto success;
1066 }
1067 // a successful 'any component.killed' implies 'any component.done'
1068 if (any_component_killed_status == ALT_YES) goto success;
1069 switch (any_component_done_status) {
1070 case ALT_UNCHECKED:
1071 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1072 "Executing 'any component.done' in invalid state.");
1073 executor_state = MTC_DONE;
1074 TTCN_Communication::send_done_req(ANY_COMPREF);
1075 any_component_done_status = ALT_MAYBE;
1076 create_done_killed_compref = ANY_COMPREF;
1077 // wait for DONE_ACK
1078 wait_for_state_change();
1079 // always re-evaluate the current alternative using a new snapshot
1080 return ALT_REPEAT;
1081 case ALT_YES:
1082 goto success;
1083 case ALT_NO:
1084 goto failure;
1085 default:
1086 return ALT_MAYBE;
1087 }
1088 success:
1089 TTCN_Logger::log_matching_done(0, 0, 0,
1090 API::MatchingDoneType_reason::any__component__done__successful);
1091 return ALT_YES;
1092 failure:
1093 TTCN_Logger::log_matching_done(0, 0, 0,
1094 API::MatchingDoneType_reason::any__component__done__failed);
1095 return ALT_NO;
1096 }
1097
1098 alt_status TTCN_Runtime::all_component_done()
1099 {
1100 // the operation is always successful in single mode
1101 if (is_single()) goto success;
1102 if (!is_mtc()) TTCN_error("Operation 'all component.done' can only be "
1103 "performed on the MTC.");
1104 // a successful 'all component.killed' implies 'all component.done'
1105 if (all_component_killed_status == ALT_YES) goto success;
1106 switch (all_component_done_status) {
1107 case ALT_UNCHECKED:
1108 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1109 "Executing 'all component.done' in invalid state.");
1110 executor_state = MTC_DONE;
1111 TTCN_Communication::send_done_req(ALL_COMPREF);
1112 all_component_done_status = ALT_MAYBE;
1113 create_done_killed_compref = ALL_COMPREF;
1114 // wait for DONE_ACK
1115 wait_for_state_change();
1116 // always re-evaluate the current alternative using a new snapshot
1117 return ALT_REPEAT;
1118 case ALT_YES:
1119 goto success;
1120 default:
1121 return ALT_MAYBE;
1122 }
1123 success:
1124 TTCN_Logger::log_matching_done(0, 0, 0,
1125 API::MatchingDoneType_reason::all__component__done__successful);
1126 return ALT_YES;
1127 }
1128
1129 alt_status TTCN_Runtime::ptc_killed(component component_reference)
1130 {
1131 if (is_single()) TTCN_error("Killed operation on a component reference "
1132 "cannot be performed in single mode.");
1133 if (self == component_reference) {
1134 TTCN_warning("Killed operation on the component reference of self "
1135 "will never succeed.");
1136 return ALT_NO;
1137 }
1138 int index = get_component_status_table_index(component_reference);
1139 switch (component_status_table[index].killed_status) {
1140 case ALT_UNCHECKED:
1141 switch (executor_state) {
1142 case MTC_TESTCASE:
1143 executor_state = MTC_KILLED;
1144 break;
1145 case PTC_FUNCTION:
1146 executor_state = PTC_KILLED;
1147 break;
1148 default:
1149 TTCN_error("Internal error: Executing killed operation in "
1150 "invalid state.");
1151 }
1152 TTCN_Communication::send_killed_req(component_reference);
1153 component_status_table[index].killed_status = ALT_MAYBE;
1154 create_done_killed_compref = component_reference;
1155 // wait for KILLED_ACK
1156 wait_for_state_change();
1157 // always re-evaluate the current alternative using a new snapshot
1158 return ALT_REPEAT;
1159 case ALT_YES:
1160 goto success;
1161 default:
1162 return ALT_MAYBE;
1163 }
1164 success:
1165 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed,
1166 NULL, NULL, component_reference);
1167 return ALT_YES;
1168 }
1169
1170 alt_status TTCN_Runtime::any_component_killed()
1171 {
1172 // the operation is never successful in single mode
1173 if (is_single()) goto failure;
1174 if (!is_mtc()) TTCN_error("Operation 'any component.killed' can only be "
1175 "performed on the MTC.");
1176 // the operation is successful if there is a component reference with a
1177 // successful killed operation
1178 for (int i = 0; i < component_status_table_size; i++) {
1179 if (component_status_table[i].killed_status == ALT_YES) goto success;
1180 }
1181 switch (any_component_killed_status) {
1182 case ALT_UNCHECKED:
1183 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1184 "Executing 'any component.killed' in invalid state.");
1185 executor_state = MTC_KILLED;
1186 TTCN_Communication::send_killed_req(ANY_COMPREF);
1187 any_component_killed_status = ALT_MAYBE;
1188 create_done_killed_compref = ANY_COMPREF;
1189 // wait for KILLED_ACK
1190 wait_for_state_change();
1191 // always re-evaluate the current alternative using a new snapshot
1192 return ALT_REPEAT;
1193 case ALT_YES:
1194 goto success;
1195 case ALT_NO:
1196 goto failure;
1197 default:
1198 return ALT_MAYBE;
1199 }
1200 success:
1201 TTCN_Logger::log_matching_done(0, 0, 0,
1202 API::MatchingDoneType_reason::any__component__killed__successful);
1203 return ALT_YES;
1204 failure:
1205 TTCN_Logger::log_matching_done(0, 0, 0,
1206 API::MatchingDoneType_reason::any__component__killed__failed);
1207 return ALT_NO;
1208 }
1209
1210 alt_status TTCN_Runtime::all_component_killed()
1211 {
1212 // the operation is always successful in single mode
1213 if (is_single()) goto success;
1214 if (!is_mtc()) TTCN_error("Operation 'all component.killed' can only be "
1215 "performed on the MTC.");
1216 switch (all_component_killed_status) {
1217 case ALT_UNCHECKED:
1218 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1219 "Executing 'all component.killed' in invalid state.");
1220 executor_state = MTC_KILLED;
1221 TTCN_Communication::send_killed_req(ALL_COMPREF);
1222 all_component_killed_status = ALT_MAYBE;
1223 create_done_killed_compref = ALL_COMPREF;
1224 // wait for KILLED_ACK
1225 wait_for_state_change();
1226 // always re-evaluate the current alternative using a new snapshot
1227 return ALT_REPEAT;
1228 case ALT_YES:
1229 goto success;
1230 default:
1231 return ALT_MAYBE;
1232 }
1233 success:
1234 TTCN_Logger::log_matching_done(0, 0, 0,
1235 API::MatchingDoneType_reason::all__component__killed__successful);
1236 return ALT_YES;
1237 }
1238
1239 boolean TTCN_Runtime::ptc_running(component component_reference)
1240 {
1241 if (is_single()) TTCN_error("Running operation on a component reference "
1242 "cannot be performed in single mode.");
1243 // the answer is always true if the operation refers to self
1244 if (self == component_reference) {
1245 TTCN_warning("Running operation on the component reference of self "
1246 "always returns true.");
1247 return TRUE;
1248 }
1249 // look into the component status tables
1250 if (in_component_status_table(component_reference)) {
1251 int index = get_component_status_table_index(component_reference);
1252 // the answer is false if a successful done or killed operation was
1253 // performed on the component reference
1254 if (component_status_table[index].done_status == ALT_YES ||
1255 component_status_table[index].killed_status == ALT_YES)
1256 return FALSE;
1257 }
1258 // status flags all_component_done or all_component_killed cannot be used
1259 // because the component reference might be invalid (e.g. stale)
1260
1261 // the decision cannot be made locally, MC must be asked
1262 switch (executor_state) {
1263 case MTC_TESTCASE:
1264 executor_state = MTC_RUNNING;
1265 break;
1266 case PTC_FUNCTION:
1267 executor_state = PTC_RUNNING;
1268 break;
1269 default:
1270 TTCN_error("Internal error: Executing component running operation "
1271 "in invalid state.");
1272 }
1273 TTCN_Communication::send_is_running(component_reference);
1274 // wait for RUNNING
1275 wait_for_state_change();
1276 return running_alive_result;
1277 }
1278
1279 boolean TTCN_Runtime::any_component_running()
1280 {
1281 // the answer is always false in single mode
1282 if (is_single()) return FALSE;
1283 if (!is_mtc()) TTCN_error("Operation 'any component.running' can only be "
1284 "performed on the MTC.");
1285 // the answer is false if 'all component.done' or 'all component.killed'
1286 // operation was successful
1287 if (all_component_done_status == ALT_YES ||
1288 all_component_killed_status == ALT_YES) return FALSE;
1289 // the decision cannot be made locally, MC must be asked
1290 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1291 "Executing 'any component.running' in invalid state.");
1292 TTCN_Communication::send_is_running(ANY_COMPREF);
1293 executor_state = MTC_RUNNING;
1294 // wait for RUNNING
1295 wait_for_state_change();
1296 // update the status of 'all component.done' in case of negative answer
1297 if (!running_alive_result) all_component_done_status = ALT_YES;
1298 return running_alive_result;
1299 }
1300
1301 boolean TTCN_Runtime::all_component_running()
1302 {
1303 // the answer is always true in single mode
1304 if (is_single()) return TRUE;
1305 if (!is_mtc()) TTCN_error("Operation 'all component.running' can only be "
1306 "performed on the MTC.");
1307 // return true if no PTCs exist
1308 if (any_component_done_status == ALT_NO) return TRUE;
1309 // the done and killed status flags cannot be used since the components
1310 // that were explicitly stopped or killed must be ignored
1311
1312 // the decision cannot be made locally, MC must be asked
1313 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1314 "Executing 'all component.running' in invalid state.");
1315 TTCN_Communication::send_is_running(ALL_COMPREF);
1316 executor_state = MTC_RUNNING;
1317 // wait for RUNNING
1318 wait_for_state_change();
1319 return running_alive_result;
1320 }
1321
1322 boolean TTCN_Runtime::ptc_alive(component component_reference)
1323 {
1324 if (is_single()) TTCN_error("Alive operation on a component reference "
1325 "cannot be performed in single mode.");
1326 // the answer is always true if the operation refers to self
1327 if (self == component_reference) {
1328 TTCN_warning("Alive operation on the component reference of self "
1329 "always returns true.");
1330 return TRUE;
1331 }
1332 // the answer is false if a successful killed operation was performed
1333 // on the component reference
1334 if (in_component_status_table(component_reference) &&
1335 get_killed_status(component_reference) == ALT_YES) return FALSE;
1336 // status flag of 'all component.killed' cannot be used because the
1337 // component reference might be invalid (e.g. stale)
1338
1339 // the decision cannot be made locally, MC must be asked
1340 switch (executor_state) {
1341 case MTC_TESTCASE:
1342 executor_state = MTC_ALIVE;
1343 break;
1344 case PTC_FUNCTION:
1345 executor_state = PTC_ALIVE;
1346 break;
1347 default:
1348 TTCN_error("Internal error: Executing component running operation "
1349 "in invalid state.");
1350 }
1351 TTCN_Communication::send_is_alive(component_reference);
1352 // wait for ALIVE
1353 wait_for_state_change();
1354 return running_alive_result;
1355 }
1356
1357 boolean TTCN_Runtime::any_component_alive()
1358 {
1359 // the answer is always false in single mode
1360 if (is_single()) return FALSE;
1361 if (!is_mtc()) TTCN_error("Operation 'any component.alive' can only be "
1362 "performed on the MTC.");
1363 // the answer is false if 'all component.killed' operation was successful
1364 if (all_component_killed_status == ALT_YES) return FALSE;
1365 // the decision cannot be made locally, MC must be asked
1366 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1367 "Executing 'any component.alive' in invalid state.");
1368 TTCN_Communication::send_is_alive(ANY_COMPREF);
1369 executor_state = MTC_ALIVE;
1370 // wait for ALIVE
1371 wait_for_state_change();
1372 // update the status of 'all component.killed' in case of negative answer
1373 if (!running_alive_result) all_component_killed_status = ALT_YES;
1374 return running_alive_result;
1375 }
1376
1377 boolean TTCN_Runtime::all_component_alive()
1378 {
1379 // the answer is always true in single mode
1380 if (is_single()) return TRUE;
1381 if (!is_mtc()) TTCN_error("Operation 'all component.alive' can only be "
1382 "performed on the MTC.");
1383 // return true if no PTCs exist
1384 if (any_component_killed_status == ALT_NO) return TRUE;
1385 // return false if at least one PTC has been created and
1386 // 'all component.killed' was successful after the create operation
1387 if (all_component_killed_status == ALT_YES) return FALSE;
1388 // the operation is successful if there is a component reference with a
1389 // successful killed operation
1390 for (int i = 0; i < component_status_table_size; i++) {
1391 if (component_status_table[i].killed_status == ALT_YES) return FALSE;
1392 }
1393
1394 // the decision cannot be made locally, MC must be asked
1395 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1396 "Executing 'all component.alive' in invalid state.");
1397 TTCN_Communication::send_is_alive(ALL_COMPREF);
1398 executor_state = MTC_ALIVE;
1399 // wait for ALIVE
1400 wait_for_state_change();
1401 return running_alive_result;
1402 }
1403
1404 void TTCN_Runtime::stop_mtc()
1405 {
1406 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::stopping__mtc);
1407 TTCN_Communication::send_stop_req(MTC_COMPREF);
1408 stop_execution();
1409 }
1410
1411 void TTCN_Runtime::stop_ptc(component component_reference)
1412 {
1413 if (is_single()) TTCN_error("Stop operation on a component reference "
1414 "cannot be performed in single mode.");
1415 // do nothing if a successful done or killed operation was performed on
1416 // the component reference
1417 if (in_component_status_table(component_reference)) {
1418 int index = get_component_status_table_index(component_reference);
1419 if (component_status_table[index].done_status == ALT_YES ||
1420 component_status_table[index].killed_status == ALT_YES)
1421 goto ignore;
1422 }
1423 // status flags all_component_done or all_component_killed cannot be used
1424 // because the component reference might be invalid (e.g. stale)
1425
1426 // MC must be asked to stop the PTC
1427 switch (executor_state) {
1428 case MTC_TESTCASE:
1429 executor_state = MTC_STOP;
1430 break;
1431 case PTC_FUNCTION:
1432 executor_state = PTC_STOP;
1433 break;
1434 default:
1435 TTCN_error("Internal error: Executing component stop operation "
1436 "in invalid state.");
1437 }
1438 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
1439 "Stopping PTC with component reference %d.", component_reference);
1440 TTCN_Communication::send_stop_req(component_reference);
1441 // wait for STOP_ACK
1442 wait_for_state_change();
1443 // done status of the PTC cannot be updated because its return type and
1444 // return value is unknown
1445 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__stopped,
1446 NULL, NULL, component_reference);
1447 return;
1448 ignore:
1449 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
1450 "PTC with component reference %d is not running. "
1451 "Stop operation had no effect.", component_reference);
1452 }
1453
1454 void TTCN_Runtime::stop_all_component()
1455 {
1456 // do nothing in single mode
1457 if (is_single()) goto ignore;
1458 if (!is_mtc()) TTCN_error("Operation 'all component.stop' can only be "
1459 "performed on the MTC.");
1460 // do nothing if 'all component.done' or 'all component.killed'
1461 // was successful
1462 if (all_component_done_status == ALT_YES ||
1463 all_component_killed_status == ALT_YES) goto ignore;
1464 // a request must be sent to MC
1465 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1466 "Executing 'all component.stop' in invalid state.");
1467 executor_state = MTC_STOP;
1468 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED, "Stopping all components.");
1469 TTCN_Communication::send_stop_req(ALL_COMPREF);
1470 // wait for STOP_ACK
1471 wait_for_state_change();
1472 // 'all component.done' will be successful later
1473 all_component_done_status = ALT_YES;
1474 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__stopped);
1475 return;
1476 ignore:
1477 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED, "No PTCs are running. "
1478 "Operation 'all component.stop' had no effect.");
1479 }
1480
1481 void TTCN_Runtime::kill_ptc(component component_reference)
1482 {
1483 if (is_single()) TTCN_error("Kill operation on a component reference "
1484 "cannot be performed in single mode.");
1485 // do nothing if a successful killed operation was performed on
1486 // the component reference
1487 if (in_component_status_table(component_reference) &&
1488 get_killed_status(component_reference) == ALT_YES) goto ignore;
1489 // status flags all_component_killed cannot be used because the component
1490 // reference might be invalid (e.g. stale)
1491
1492 // MC must be asked to kill the PTC
1493 switch (executor_state) {
1494 case MTC_TESTCASE:
1495 executor_state = MTC_KILL;
1496 break;
1497 case PTC_FUNCTION:
1498 executor_state = PTC_KILL;
1499 break;
1500 default:
1501 TTCN_error("Internal error: Executing kill operation in invalid "
1502 "state.");
1503 }
1504 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
1505 "Killing PTC with component reference %d.", component_reference);
1506 TTCN_Communication::send_kill_req(component_reference);
1507 // wait for KILL_ACK
1508 wait_for_state_change();
1509 // updating the killed status of the PTC
1510 {
1511 int index = get_component_status_table_index(component_reference);
1512 component_status_table[index].killed_status = ALT_YES;
1513 }
1514 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed, NULL, NULL,
1515 component_reference);
1516 return;
1517 ignore:
1518 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
1519 "PTC with component reference %d is not alive anymore. "
1520 "Kill operation had no effect.", component_reference);
1521 }
1522
1523 void TTCN_Runtime::kill_all_component()
1524 {
1525 // do nothing in single mode
1526 if (is_single()) goto ignore;
1527 if (!is_mtc()) TTCN_error("Operation 'all component.kill' can only be "
1528 "performed on the MTC.");
1529 // do nothing if 'all component.killed' was successful
1530 if (all_component_killed_status == ALT_YES) goto ignore;
1531 // a request must be sent to MC
1532 if (executor_state != MTC_TESTCASE) TTCN_error("Internal error: "
1533 "Executing 'all component.kill' in invalid state.");
1534 executor_state = MTC_KILL;
1535 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED, "Killing all components.");
1536 TTCN_Communication::send_kill_req(ALL_COMPREF);
1537 // wait for KILL_ACK
1538 wait_for_state_change();
1539 // 'all component.done' and 'all component.killed' will be successful later
1540 all_component_done_status = ALT_YES;
1541 all_component_killed_status = ALT_YES;
1542 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__killed);
1543 return;
1544 ignore:
1545 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED,
1546 "There are no alive PTCs. Operation 'all component.kill' had no effect.");
1547 }
1548
1549 void TTCN_Runtime::check_port_name(const char *port_name,
1550 const char *operation_name, const char *which_argument)
1551 {
1552 if (port_name == NULL)
1553 TTCN_error("Internal error: The port name in the %s argument of %s "
1554 "operation is a NULL pointer.", which_argument, operation_name);
1555 if (port_name[0] == '\0')
1556 TTCN_error("Internal error: The %s argument of %s operation contains "
1557 "an empty string as port name.", which_argument, operation_name);
1558 /** \todo check whether port_name contains a valid TTCN-3 identifier
1559 * (and array index) */
1560 }
1561
1562 void TTCN_Runtime::connect_port(
1563 const COMPONENT& src_compref, const char *src_port,
1564 const COMPONENT& dst_compref, const char *dst_port)
1565 {
1566 check_port_name(src_port, "connect", "first");
1567 check_port_name(dst_port, "connect", "second");
1568
1569 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED);
1570 TTCN_Logger::log_event_str("Connecting ports ");
1571 COMPONENT::log_component_reference(src_compref);
1572 TTCN_Logger::log_event(":%s and ", src_port);
1573 COMPONENT::log_component_reference(dst_compref);
1574 TTCN_Logger::log_event(":%s.", dst_port);
1575 TTCN_Logger::end_event();
1576
1577 if (!src_compref.is_bound()) TTCN_error("The first argument of connect "
1578 "operation contains an unbound component reference.");
1579 component src_component = src_compref;
1580 switch (src_component) {
1581 case NULL_COMPREF:
1582 TTCN_error("The first argument of connect operation contains the "
1583 "null component reference.");
1584 case SYSTEM_COMPREF:
1585 TTCN_error("The first argument of connect operation refers to a "
1586 "system port.");
1587 default:
1588 break;
1589 }
1590 if (!dst_compref.is_bound()) TTCN_error("The second argument of connect "
1591 "operation contains an unbound component reference.");
1592 component dst_component = dst_compref;
1593 switch (dst_component) {
1594 case NULL_COMPREF:
1595 TTCN_error("The second argument of connect operation contains the "
1596 "null component reference.");
1597 case SYSTEM_COMPREF:
1598 TTCN_error("The second argument of connect operation refers to a "
1599 "system port.");
1600 default:
1601 break;
1602 }
1603
1604 switch (executor_state) {
1605 case SINGLE_TESTCASE:
1606 if (src_component != MTC_COMPREF || dst_component != MTC_COMPREF)
1607 TTCN_error("Both endpoints of connect operation must refer to "
1608 "ports of mtc in single mode.");
1609 PORT::make_local_connection(src_port, dst_port);
1610 break;
1611 case MTC_TESTCASE:
1612 TTCN_Communication::send_connect_req(src_component, src_port,
1613 dst_component, dst_port);
1614 executor_state = MTC_CONNECT;
1615 wait_for_state_change();
1616 break;
1617 case PTC_FUNCTION:
1618 TTCN_Communication::send_connect_req(src_component, src_port,
1619 dst_component, dst_port);
1620 executor_state = PTC_CONNECT;
1621 wait_for_state_change();
1622 break;
1623 default:
1624 if (in_controlpart()) {
1625 TTCN_error("Connect operation cannot be performed in the "
1626 "control part.");
1627 } else {
1628 TTCN_error("Internal error: Executing connect operation "
1629 "in invalid state.");
1630 }
1631 }
1632
1633 TTCN_Logger::log_portconnmap(API::ParPort_operation::connect__,
1634 src_compref, src_port, dst_compref, dst_port);
1635 }
1636
1637 void TTCN_Runtime::disconnect_port(
1638 const COMPONENT& src_compref, const char *src_port,
1639 const COMPONENT& dst_compref, const char *dst_port)
1640 {
1641 check_port_name(src_port, "disconnect", "first");
1642 check_port_name(dst_port, "disconnect", "second");
1643
1644 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED);
1645 TTCN_Logger::log_event_str("Disconnecting ports ");
1646 COMPONENT::log_component_reference(src_compref);
1647 TTCN_Logger::log_event(":%s and ", src_port);
1648 COMPONENT::log_component_reference(dst_compref);
1649 TTCN_Logger::log_event(":%s.", dst_port);
1650 TTCN_Logger::end_event();
1651
1652 if (!src_compref.is_bound()) TTCN_error("The first argument of disconnect "
1653 "operation contains an unbound component reference.");
1654 component src_component = src_compref;
1655 switch (src_component) {
1656 case NULL_COMPREF:
1657 TTCN_error("The first argument of disconnect operation contains the "
1658 "null component reference.");
1659 case SYSTEM_COMPREF:
1660 TTCN_error("The first argument of disconnect operation refers to a "
1661 "system port.");
1662 default:
1663 break;
1664 }
1665 if (!dst_compref.is_bound()) TTCN_error("The second argument of disconnect "
1666 "operation contains an unbound component reference.");
1667 component dst_component = dst_compref;
1668 switch (dst_component) {
1669 case NULL_COMPREF:
1670 TTCN_error("The second argument of disconnect operation contains the "
1671 "null component reference.");
1672 case SYSTEM_COMPREF:
1673 TTCN_error("The second argument of disconnect operation refers to a "
1674 "system port.");
1675 default:
1676 break;
1677 }
1678
1679 switch (executor_state) {
1680 case SINGLE_TESTCASE:
1681 if (src_component != MTC_COMPREF || dst_component != MTC_COMPREF)
1682 TTCN_error("Both endpoints of disconnect operation must refer to "
1683 "ports of mtc in single mode.");
1684 PORT::terminate_local_connection(src_port, dst_port);
1685 break;
1686 case MTC_TESTCASE:
1687 TTCN_Communication::send_disconnect_req(src_component, src_port,
1688 dst_component, dst_port);
1689 executor_state = MTC_DISCONNECT;
1690 wait_for_state_change();
1691 break;
1692 case PTC_FUNCTION:
1693 TTCN_Communication::send_disconnect_req(src_component, src_port,
1694 dst_component, dst_port);
1695 executor_state = PTC_DISCONNECT;
1696 wait_for_state_change();
1697 break;
1698 default:
1699 if (in_controlpart()) {
1700 TTCN_error("Disonnect operation cannot be performed in the "
1701 "control part.");
1702 } else {
1703 TTCN_error("Internal error: Executing disconnect operation "
1704 "in invalid state.");
1705 }
1706 }
1707
1708 TTCN_Logger::log_portconnmap(API::ParPort_operation::disconnect__,
1709 src_compref, src_port, dst_compref, dst_port);
1710 }
1711
1712 void TTCN_Runtime::map_port(
1713 const COMPONENT& src_compref, const char *src_port,
1714 const COMPONENT& dst_compref, const char *dst_port)
1715 {
1716 check_port_name(src_port, "map", "first");
1717 check_port_name(dst_port, "map", "second");
1718
1719 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED);
1720 TTCN_Logger::log_event_str("Mapping port ");
1721 COMPONENT::log_component_reference(src_compref);
1722 TTCN_Logger::log_event(":%s to ", src_port);
1723 COMPONENT::log_component_reference(dst_compref);
1724 TTCN_Logger::log_event(":%s.", dst_port);
1725 TTCN_Logger::end_event();
1726
1727 if (!src_compref.is_bound()) TTCN_error("The first argument of map "
1728 "operation contains an unbound component reference.");
1729 component src_component = src_compref;
1730 if (src_component == NULL_COMPREF) TTCN_error("The first argument of "
1731 "map operation contains the null component reference.");
1732 if (!dst_compref.is_bound()) TTCN_error("The second argument of map "
1733 "operation contains an unbound component reference.");
1734 component dst_component = dst_compref;
1735 if (dst_component == NULL_COMPREF) TTCN_error("The second argument of "
1736 "map operation contains the null component reference.");
1737
1738 component comp_reference;
1739 const char *comp_port, *system_port;
1740
1741 if (src_component == SYSTEM_COMPREF) {
1742 if (dst_component == SYSTEM_COMPREF) TTCN_error("Both arguments of "
1743 "map operation refer to system ports.");
1744 comp_reference = dst_component;
1745 comp_port = dst_port;
1746 system_port = src_port;
1747 } else if (dst_component == SYSTEM_COMPREF) {
1748 comp_reference = src_component;
1749 comp_port = src_port;
1750 system_port = dst_port;
1751 } else {
1752 TTCN_error("Both arguments of map operation refer to test component "
1753 "ports.");
1754 // to avoid warnings
1755 return;
1756 }
1757
1758 switch (executor_state) {
1759 case SINGLE_TESTCASE:
1760 if (comp_reference != MTC_COMPREF) TTCN_error("Only the ports of mtc "
1761 "can be mapped in single mode.");
1762 PORT::map_port(comp_port, system_port);
1763 break;
1764 case MTC_TESTCASE:
1765 TTCN_Communication::send_map_req(comp_reference, comp_port,
1766 system_port);
1767 executor_state = MTC_MAP;
1768 wait_for_state_change();
1769 break;
1770 case PTC_FUNCTION:
1771 TTCN_Communication::send_map_req(comp_reference, comp_port,
1772 system_port);
1773 executor_state = PTC_MAP;
1774 wait_for_state_change();
1775 break;
1776 default:
1777 if (in_controlpart()) {
1778 TTCN_error("Map operation cannot be performed in the "
1779 "control part.");
1780 } else {
1781 TTCN_error("Internal error: Executing map operation "
1782 "in invalid state.");
1783 }
1784 }
1785
1786 TTCN_Logger::log_portconnmap(API::ParPort_operation::map__,
1787 src_compref, src_port, dst_compref, dst_port);
1788 }
1789
1790 void TTCN_Runtime::unmap_port(
1791 const COMPONENT& src_compref, const char *src_port,
1792 const COMPONENT& dst_compref, const char *dst_port)
1793 {
1794 check_port_name(src_port, "unmap", "first");
1795 check_port_name(dst_port, "unmap", "second");
1796
1797 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED);
1798 TTCN_Logger::log_event_str("Unmapping port ");
1799 COMPONENT::log_component_reference(src_compref);
1800 TTCN_Logger::log_event(":%s from ", src_port);
1801 COMPONENT::log_component_reference(dst_compref);
1802 TTCN_Logger::log_event(":%s.", dst_port);
1803 TTCN_Logger::end_event();
1804
1805 if (!src_compref.is_bound()) TTCN_error("The first argument of unmap "
1806 "operation contains an unbound component reference.");
1807 component src_component = src_compref;
1808 if (src_component == NULL_COMPREF) TTCN_error("The first argument of "
1809 "unmap operation contains the null component reference.");
1810 if (!dst_compref.is_bound()) TTCN_error("The second argument of unmap "
1811 "operation contains an unbound component reference.");
1812 component dst_component = dst_compref;
1813 if (dst_component == NULL_COMPREF) TTCN_error("The second argument of "
1814 "unmap operation contains the null component reference.");
1815
1816 component comp_reference;
1817 const char *comp_port, *system_port;
1818
1819 if (src_component == SYSTEM_COMPREF) {
1820 if (dst_component == SYSTEM_COMPREF) TTCN_error("Both arguments of "
1821 "unmap operation refer to system ports.");
1822 comp_reference = dst_component;
1823 comp_port = dst_port;
1824 system_port = src_port;
1825 } else if (dst_component == SYSTEM_COMPREF) {
1826 comp_reference = src_component;
1827 comp_port = src_port;
1828 system_port = dst_port;
1829 } else {
1830 TTCN_error("Both arguments of unmap operation refer to test component "
1831 "ports.");
1832 // to avoid warnings
1833 return;
1834 }
1835
1836 switch (executor_state) {
1837 case SINGLE_TESTCASE:
1838 if (comp_reference != MTC_COMPREF) TTCN_error("Only the ports of mtc "
1839 "can be unmapped in single mode.");
1840 PORT::unmap_port(comp_port, system_port);
1841 break;
1842 case MTC_TESTCASE:
1843 TTCN_Communication::send_unmap_req(comp_reference, comp_port,
1844 system_port);
1845 executor_state = MTC_UNMAP;
1846 wait_for_state_change();
1847 break;
1848 case PTC_FUNCTION:
1849 TTCN_Communication::send_unmap_req(comp_reference, comp_port,
1850 system_port);
1851 executor_state = PTC_UNMAP;
1852 wait_for_state_change();
1853 break;
1854 default:
1855 if (in_controlpart()) {
1856 TTCN_error("Unmap operation cannot be performed in the "
1857 "control part.");
1858 } else {
1859 TTCN_error("Internal error: Executing unmap operation "
1860 "in invalid state.");
1861 }
1862 }
1863
1864 TTCN_Logger::log_portconnmap(API::ParPort_operation::unmap__,
1865 src_compref, src_port, dst_compref, dst_port);
1866 }
1867
1868 void TTCN_Runtime::begin_controlpart(const char *module_name)
1869 {
1870 control_module_name = module_name;
1871 execute_command(begin_controlpart_command, module_name);
1872 TTCN_Logger::log_controlpart_start_stop(module_name, 0);
1873 }
1874
1875 void TTCN_Runtime::end_controlpart()
1876 {
1877 TTCN_Default::deactivate_all();
1878 TTCN_Default::reset_counter();
1879 TIMER::all_stop();
1880 TTCN_Logger::log_controlpart_start_stop(control_module_name, 1);
1881 execute_command(end_controlpart_command, control_module_name);
1882 control_module_name = NULL;
1883 }
1884
1885 void TTCN_Runtime::check_begin_testcase(boolean has_timer, double timer_value)
1886 {
1887 if (!in_controlpart()) {
1888 if (is_single() || is_mtc()) TTCN_error("Test case cannot be executed "
1889 "while another one (%s.%s) is running.", testcase_name.module_name,
1890 testcase_name.definition_name);
1891 else if (is_ptc()) TTCN_error("Test case cannot be executed on a PTC.");
1892 else TTCN_error("Internal error: Executing a test case in an invalid "
1893 "state.");
1894 }
1895 if (has_timer && timer_value < 0.0) TTCN_error("The test case supervisor "
1896 "timer has negative duration (%g s).", timer_value);
1897 }
1898
1899 void TTCN_Runtime::begin_testcase(
1900 const char *par_module_name, const char *par_testcase_name,
1901 const char *mtc_comptype_module, const char *mtc_comptype_name,
1902 const char *system_comptype_module, const char *system_comptype_name,
1903 boolean has_timer, double timer_value)
1904 {
1905 switch (executor_state) {
1906 case SINGLE_CONTROLPART:
1907 executor_state = SINGLE_TESTCASE;
1908 break;
1909 case MTC_CONTROLPART:
1910 TTCN_Communication::send_testcase_started(par_module_name,
1911 par_testcase_name, mtc_comptype_module, mtc_comptype_name,
1912 system_comptype_module, system_comptype_name);
1913 executor_state = MTC_TESTCASE;
1914 break;
1915 default:
1916 TTCN_error("Internal error: Executing a test case in an invalid "
1917 "state.");
1918 }
1919 TIMER::save_control_timers();
1920 TTCN_Default::save_control_defaults();
1921 set_testcase_name(par_module_name, par_testcase_name);
1922 char *command_arguments = mprintf("%s.%s", testcase_name.module_name,
1923 testcase_name.definition_name);
1924 execute_command(begin_testcase_command, command_arguments);
1925 Free(command_arguments);
1926 TTCN_Logger::log_testcase_started(testcase_name);
1927 if (has_timer) testcase_timer.start(timer_value);
1928 set_component_type(mtc_comptype_module, mtc_comptype_name);
1929 initialize_component_type();
1930 // at the beginning of the testcase no PTCs exist
1931 any_component_done_status = ALT_NO;
1932 all_component_done_status = ALT_YES;
1933 any_component_killed_status = ALT_NO;
1934 all_component_killed_status = ALT_YES;
1935 }
1936
1937 verdicttype TTCN_Runtime::end_testcase()
1938 {
1939 switch (executor_state) {
1940 case MTC_CREATE:
1941 case MTC_START:
1942 case MTC_STOP:
1943 case MTC_KILL:
1944 case MTC_RUNNING:
1945 case MTC_ALIVE:
1946 case MTC_DONE:
1947 case MTC_KILLED:
1948 case MTC_CONNECT:
1949 case MTC_DISCONNECT:
1950 case MTC_MAP:
1951 case MTC_UNMAP:
1952 executor_state = MTC_TESTCASE;
1953 case MTC_TESTCASE:
1954 break;
1955 case SINGLE_TESTCASE:
1956 disable_interrupt_handler();
1957 break;
1958 default:
1959 TTCN_error("Internal error: Ending a testcase in an invalid state.");
1960 }
1961 testcase_timer.stop();
1962 terminate_component_type();
1963 if (executor_state == MTC_TESTCASE) {
1964 TTCN_Logger::log_executor_runtime(
1965 API::ExecutorRuntime_reason::waiting__for__ptcs__to__finish);
1966 TTCN_Communication::send_testcase_finished(local_verdict, verdict_reason);
1967 executor_state = MTC_TERMINATING_TESTCASE;
1968 wait_for_state_change();
1969 } else if (executor_state == SINGLE_TESTCASE) {
1970 executor_state = SINGLE_CONTROLPART;
1971 enable_interrupt_handler();
1972 }
1973 TTCN_Logger::log_testcase_finished(testcase_name, local_verdict,
1974 verdict_reason);
1975 verdict_count[local_verdict]++;
1976 // testcase name should come first for backward compatibility
1977 char *command_arguments = mprintf("%s.%s %s",
1978 testcase_name.module_name, testcase_name.definition_name,
1979 verdict_name[local_verdict]);
1980 execute_command(end_testcase_command, command_arguments);
1981 Free(command_arguments);
1982 clear_qualified_name(testcase_name);
1983 // clean up component status caches
1984 clear_component_status_table();
1985 any_component_done_status = ALT_UNCHECKED;
1986 all_component_done_status = ALT_UNCHECKED;
1987 any_component_killed_status = ALT_UNCHECKED;
1988 all_component_killed_status = ALT_UNCHECKED;
1989 // restore the control part timers and defaults
1990 TTCN_Default::restore_control_defaults();
1991 TIMER::restore_control_timers();
1992 if (executor_state == MTC_PAUSED) {
1993 TTCN_Logger::log_executor_runtime(
1994 API::ExecutorRuntime_reason::user__paused__waiting__to__resume);
1995 wait_for_state_change();
1996 if (executor_state != MTC_TERMINATING_EXECUTION)
1997 TTCN_Logger::log_executor_runtime(
1998 API::ExecutorRuntime_reason::resuming__execution);
1999 }
2000 if (executor_state == MTC_TERMINATING_EXECUTION) {
2001 executor_state = MTC_CONTROLPART;
2002 TTCN_Logger::log_executor_runtime(
2003 API::ExecutorRuntime_reason::terminating__execution);
2004 throw TC_End();
2005 }
2006 return local_verdict;
2007 }
2008
2009 void TTCN_Runtime::log_verdict_statistics()
2010 {
2011 unsigned int total_testcases = verdict_count[NONE] + verdict_count[PASS] +
2012 verdict_count[INCONC] + verdict_count[FAIL] + verdict_count[ERROR];
2013
2014 verdicttype overall_verdict;
2015 if (control_error_count > 0 || verdict_count[ERROR] > 0)
2016 overall_verdict = ERROR;
2017 else if (verdict_count[FAIL] > 0) overall_verdict = FAIL;
2018 else if (verdict_count[INCONC] > 0) overall_verdict = INCONC;
2019 else if (verdict_count[PASS] > 0) overall_verdict = PASS;
2020 else overall_verdict = NONE;
2021
2022 if (total_testcases > 0) {
2023 TTCN_Logger::log_verdict_statistics(verdict_count[NONE], (100.0 * verdict_count[NONE]) / total_testcases,
2024 verdict_count[PASS], (100.0 * verdict_count[PASS]) / total_testcases,
2025 verdict_count[INCONC], (100.0 * verdict_count[INCONC]) / total_testcases,
2026 verdict_count[FAIL], (100.0 * verdict_count[FAIL]) / total_testcases,
2027 verdict_count[ERROR], (100.0 * verdict_count[ERROR]) / total_testcases);
2028 } else {
2029 TTCN_Logger::log_verdict_statistics(0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0);
2030 }
2031
2032 if (control_error_count > 0) {
2033 TTCN_Logger::log_controlpart_errors(control_error_count);
2034 }
2035
2036 TTCN_Logger::log(TTCN_Logger::STATISTICS_VERDICT, "Test execution summary: "
2037 "%u test case%s executed. Overall verdict: %s", total_testcases,
2038 total_testcases > 1 ? "s were" : " was", verdict_name[overall_verdict]);
2039
2040 verdict_count[NONE] = 0;
2041 verdict_count[PASS] = 0;
2042 verdict_count[INCONC] = 0;
2043 verdict_count[FAIL] = 0;
2044 verdict_count[ERROR] = 0;
2045 control_error_count = 0;
2046 }
2047
2048 void TTCN_Runtime::begin_action()
2049 {
2050 TTCN_Logger::begin_event(TTCN_Logger::ACTION_UNQUALIFIED);
2051 TTCN_Logger::log_event_str("Action: ");
2052 }
2053
2054 void TTCN_Runtime::end_action()
2055 {
2056 TTCN_Logger::end_event();
2057 }
2058
2059 void TTCN_Runtime::setverdict(verdicttype new_value, const char* reason)
2060 {
2061 if (verdict_enabled()) {
2062 if (new_value == ERROR)
2063 TTCN_error("Error verdict cannot be set explicitly.");
2064 setverdict_internal(new_value, reason);
2065 } else if (in_controlpart()) {
2066 TTCN_error("Verdict cannot be set in the control part.");
2067 } else {
2068 TTCN_error("Internal error: Setting the verdict in invalid state.");
2069 }
2070 }
2071
2072 void TTCN_Runtime::setverdict(const VERDICTTYPE& new_value, const char* reason)
2073 {
2074 if (!new_value.is_bound()) TTCN_error("The argument of setverdict "
2075 "operation is an unbound verdict value.");
2076 setverdict((verdicttype)new_value, reason);
2077 }
2078
2079 void TTCN_Runtime::set_error_verdict()
2080 {
2081 if (verdict_enabled()) setverdict_internal(ERROR);
2082 else if (is_single() || is_mtc()) control_error_count++;
2083 }
2084
2085 verdicttype TTCN_Runtime::getverdict()
2086 {
2087 if (verdict_enabled())
2088 TTCN_Logger::log_getverdict(local_verdict);
2089 else if (in_controlpart()) TTCN_error("Getverdict operation cannot be "
2090 "performed in the control part.");
2091 else TTCN_error("Internal error: Performing getverdict operation in "
2092 "invalid state.");
2093 return local_verdict;
2094 }
2095
2096 void TTCN_Runtime::setverdict_internal(verdicttype new_value,
2097 const char* reason)
2098 {
2099 if (new_value < NONE || new_value > ERROR)
2100 TTCN_error("Internal error: setting an invalid verdict value (%d).",
2101 new_value);
2102 verdicttype old_verdict = local_verdict;
2103 if (local_verdict < new_value) {
2104 verdict_reason = reason;
2105 local_verdict = new_value;
2106 if (reason == NULL || reason[0] == '\0')
2107 TTCN_Logger::log_setverdict(new_value, old_verdict, local_verdict);
2108 else TTCN_Logger::log_setverdict(new_value, old_verdict, local_verdict, reason, reason);
2109 } else if (local_verdict == new_value) {
2110 if (reason == NULL || reason[0] == '\0')
2111 TTCN_Logger::log_setverdict(new_value, old_verdict, local_verdict);
2112 else TTCN_Logger::log_setverdict(new_value, old_verdict, local_verdict, reason, reason);
2113 }
2114 }
2115
2116 void TTCN_Runtime::set_begin_controlpart_command(const char *new_command)
2117 {
2118 Free(begin_controlpart_command);
2119 begin_controlpart_command = shell_escape(new_command);
2120 }
2121
2122 void TTCN_Runtime::set_end_controlpart_command(const char *new_command)
2123 {
2124 Free(end_controlpart_command);
2125 end_controlpart_command = shell_escape(new_command);
2126 }
2127
2128 void TTCN_Runtime::set_begin_testcase_command(const char *new_command)
2129 {
2130 Free(begin_testcase_command);
2131 begin_testcase_command = shell_escape(new_command);
2132 }
2133
2134 void TTCN_Runtime::set_end_testcase_command(const char *new_command)
2135 {
2136 Free(end_testcase_command);
2137 end_testcase_command = shell_escape(new_command);
2138 }
2139
2140 void TTCN_Runtime::clear_external_commands()
2141 {
2142 Free(begin_controlpart_command);
2143 begin_controlpart_command = NULL;
2144 Free(end_controlpart_command);
2145 end_controlpart_command = NULL;
2146 Free(begin_testcase_command);
2147 begin_testcase_command = NULL;
2148 Free(end_testcase_command);
2149 end_testcase_command = NULL;
2150 }
2151
2152 char *TTCN_Runtime::shell_escape(const char *command_str)
2153 {
2154 if (command_str == NULL || command_str[0] == '\0') return NULL;
2155 boolean has_special_char = FALSE;
2156 for (int i = 0; !has_special_char && command_str[i] != '\0'; i++) {
2157 switch (command_str[i]) {
2158 case ' ':
2159 case '*':
2160 case '?':
2161 case '[':
2162 case ']':
2163 case '<':
2164 case '>':
2165 case '|':
2166 case '&':
2167 case '$':
2168 case '{':
2169 case '}':
2170 case ';':
2171 case '(':
2172 case ')':
2173 case '#':
2174 case '!':
2175 case '=':
2176 case '"':
2177 case '`':
2178 case '\\':
2179 // special characters interpreted by the shell except '
2180 has_special_char = TRUE;
2181 break;
2182 default:
2183 // non-printable characters also need special handling
2184 if (!isprint(command_str[i])) has_special_char = TRUE;
2185 }
2186 }
2187 char *ret_val = memptystr();
2188 // indicates whether we are in an unclosed ' string
2189 boolean in_apostrophes = FALSE;
2190 for (int i = 0; command_str[i] != '\0'; i++) {
2191 if (command_str[i] == '\'') {
2192 if (in_apostrophes) {
2193 // close the open literal
2194 ret_val = mputc(ret_val, '\'');
2195 in_apostrophes = FALSE;
2196 }
2197 // substitute with \'
2198 ret_val = mputstr(ret_val, "\\'");
2199 } else {
2200 if (has_special_char && !in_apostrophes) {
2201 // open the literal
2202 ret_val = mputc(ret_val, '\'');
2203 in_apostrophes = TRUE;
2204 }
2205 // append the single character
2206 ret_val = mputc(ret_val, command_str[i]);
2207 }
2208 }
2209 // close the open literal
2210 if (in_apostrophes) ret_val = mputc(ret_val, '\'');
2211 return ret_val;
2212 }
2213
2214 void TTCN_Runtime::execute_command(const char *command_name,
2215 const char *argument_string)
2216 {
2217 if (command_name != NULL) {
2218 char *command_string = mprintf("%s %s", command_name, argument_string);
2219 try {
2220 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_START, command_string);
2221 int return_status = system(command_string);
2222 if (return_status == -1) TTCN_error("Execution of external "
2223 "command `%s' failed.", command_string);
2224 else if (WIFEXITED(return_status)) {
2225 int exit_status = WEXITSTATUS(return_status);
2226 if (exit_status == EXIT_SUCCESS)
2227 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_SUCCESS, command_string);
2228 else TTCN_warning("External command `%s' returned "
2229 "unsuccessful exit status (%d).", command_string,
2230 exit_status);
2231 } else if (WIFSIGNALED(return_status)) {
2232 int signal_number = WTERMSIG(return_status);
2233 TTCN_warning("External command `%s' was terminated by signal "
2234 "%d (%s).", command_string, signal_number,
2235 get_signal_name(signal_number));
2236 } else {
2237 TTCN_warning("External command `%s' was terminated by an "
2238 "unknown reason (return status: %d).", command_string,
2239 return_status);
2240 }
2241 } catch (...) {
2242 // to prevent from memory leaks
2243 Free(command_string);
2244 throw;
2245 }
2246 Free(command_string);
2247 }
2248 }
2249
2250 void TTCN_Runtime::process_create_mtc()
2251 {
2252 switch (executor_state) {
2253 case HC_ACTIVE:
2254 case HC_OVERLOADED:
2255 break;
2256 default:
2257 TTCN_Communication::send_error("Message CREATE_MTC arrived in invalid "
2258 "state.");
2259 return;
2260 }
2261
2262 // clean Emergency log buffer before fork, to avoid duplication
2263 TTCN_Logger::ring_buffer_dump(false);
2264
2265 pid_t mtc_pid = fork();
2266 if (mtc_pid < 0) {
2267 // fork() failed
2268 TTCN_Communication::send_create_nak(MTC_COMPREF, "system call fork() "
2269 "failed (%s)", strerror(errno));
2270 failed_process_creation();
2271 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
2272 TTCN_Logger::log_event_str("System call fork() failed when creating "
2273 "MTC.");
2274 TTCN_Logger::OS_error();
2275 TTCN_Logger::end_event();
2276 } else if (mtc_pid > 0) {
2277 // fork() was successful, this code runs on the parent process (HC)
2278 TTCN_Logger::log_mtc_created(mtc_pid);
2279 add_component(MTC_COMPREF, mtc_pid);
2280 successful_process_creation();
2281 } else {
2282 // fork() was successful, this code runs on the child process (MTC)
2283 // The inherited epoll fd has to be closed first, and then the mc fd
2284 // (The inherited epoll fd shares its database with the parent process.)
2285 Fd_And_Timeout_User::reopenEpollFd();
2286 TTCN_Communication::close_mc_connection();
2287 self = MTC_COMPREF;
2288 executor_state = MTC_INITIAL;
2289 }
2290 }
2291
2292 void TTCN_Runtime::process_create_ptc(component component_reference,
2293 const char *component_type_module, const char *component_type_name,
2294 const char *par_component_name, boolean par_is_alive,
2295 const char *current_testcase_module, const char *current_testcase_name)
2296 {
2297 switch (executor_state) {
2298 case HC_ACTIVE:
2299 case HC_OVERLOADED:
2300 break;
2301 default:
2302 TTCN_Communication::send_error("Message CREATE_PTC arrived in invalid "
2303 "state.");
2304 return;
2305 }
2306
2307 // clean Emergency log buffer before fork, to avoid duplication
2308 TTCN_Logger::ring_buffer_dump(false);
2309
2310 pid_t ptc_pid = fork();
2311 if (ptc_pid < 0) {
2312 // fork() failed
2313 TTCN_Communication::send_create_nak(component_reference, "system call "
2314 "fork() failed (%s)", strerror(errno));
2315 failed_process_creation();
2316 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
2317 TTCN_Logger::log_event("System call fork() failed when creating PTC "
2318 "with component reference %d.", component_reference);
2319 TTCN_Logger::OS_error();
2320 TTCN_Logger::end_event();
2321 } else if (ptc_pid > 0) {
2322 // fork() was successful, this code runs on the parent process (HC)
2323 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created__pid,
2324 component_type_module, component_type_name, component_reference,
2325 par_component_name, current_testcase_name, ptc_pid);
2326 add_component(component_reference, ptc_pid);
2327 COMPONENT::register_component_name(component_reference,
2328 par_component_name);
2329 successful_process_creation();
2330 } else {
2331 // fork() was successful, this code runs on the child process (PTC)
2332 // The inherited epoll fd has to be closed first, and then the mc fd
2333 // (The inherited epoll fd shares its database with the parent process.)
2334 Fd_And_Timeout_User::reopenEpollFd();
2335 TTCN_Communication::close_mc_connection();
2336 self = component_reference;
2337 set_component_type(component_type_module, component_type_name);
2338 set_component_name(par_component_name);
2339 is_alive = par_is_alive;
2340 set_testcase_name(current_testcase_module, current_testcase_name);
2341 executor_state = PTC_INITIAL;
2342 }
2343 }
2344
2345 void TTCN_Runtime::process_create_ack(component new_component)
2346 {
2347 switch (executor_state) {
2348 case MTC_CREATE:
2349 executor_state = MTC_TESTCASE;
2350 case MTC_TERMINATING_TESTCASE:
2351 break;
2352 case PTC_CREATE:
2353 executor_state = PTC_FUNCTION;
2354 break;
2355 default:
2356 TTCN_error("Internal error: Message CREATE_ACK arrived in invalid "
2357 "state.");
2358 }
2359 create_done_killed_compref = new_component;
2360 }
2361
2362 void TTCN_Runtime::process_running(boolean result_value)
2363 {
2364 switch (executor_state) {
2365 case MTC_RUNNING:
2366 executor_state = MTC_TESTCASE;
2367 case MTC_TERMINATING_TESTCASE:
2368 break;
2369 case PTC_RUNNING:
2370 executor_state = PTC_FUNCTION;
2371 break;
2372 default:
2373 TTCN_error("Internal error: Message RUNNING arrived in invalid state.");
2374 }
2375 running_alive_result = result_value;
2376 }
2377
2378 void TTCN_Runtime::process_alive(boolean result_value)
2379 {
2380 switch (executor_state) {
2381 case MTC_ALIVE:
2382 executor_state = MTC_TESTCASE;
2383 case MTC_TERMINATING_TESTCASE:
2384 break;
2385 case PTC_ALIVE:
2386 executor_state = PTC_FUNCTION;
2387 break;
2388 default:
2389 TTCN_error("Internal error: Message ALIVE arrived in invalid state.");
2390 }
2391 running_alive_result = result_value;
2392 }
2393
2394 void TTCN_Runtime::process_done_ack(boolean done_status,
2395 const char *return_type, int return_value_len, const void *return_value)
2396 {
2397 switch (executor_state) {
2398 case MTC_DONE:
2399 executor_state = MTC_TESTCASE;
2400 case MTC_TERMINATING_TESTCASE:
2401 break;
2402 case PTC_DONE:
2403 executor_state = PTC_FUNCTION;
2404 break;
2405 default:
2406 TTCN_error("Internal error: Message DONE_ACK arrived in invalid "
2407 "state.");
2408 }
2409 if (done_status) set_component_done(create_done_killed_compref,
2410 return_type, return_value_len, return_value);
2411 create_done_killed_compref = NULL_COMPREF;
2412 }
2413
2414 void TTCN_Runtime::process_killed_ack(boolean killed_status)
2415 {
2416 switch (executor_state) {
2417 case MTC_KILLED:
2418 executor_state = MTC_TESTCASE;
2419 case MTC_TERMINATING_TESTCASE:
2420 break;
2421 case PTC_KILLED:
2422 executor_state = PTC_FUNCTION;
2423 break;
2424 default:
2425 TTCN_error("Internal error: Message KILLED_ACK arrived in invalid "
2426 "state.");
2427 }
2428 if (killed_status) set_component_killed(create_done_killed_compref);
2429 create_done_killed_compref = NULL_COMPREF;
2430 }
2431
2432 void TTCN_Runtime::process_ptc_verdict(Text_Buf& text_buf)
2433 {
2434 if (executor_state != MTC_TERMINATING_TESTCASE)
2435 TTCN_error("Internal error: Message PTC_VERDICT arrived in invalid state.");
2436
2437 TTCN_Logger::log_final_verdict(false, local_verdict, local_verdict,
2438 local_verdict, (const char *)verdict_reason,
2439 TitanLoggerApi::FinalVerdictType_choice_notification::setting__final__verdict__of__the__test__case);
2440 TTCN_Logger::log_final_verdict(false, local_verdict, local_verdict,
2441 local_verdict, (const char *)verdict_reason);
2442 int n_ptcs = text_buf.pull_int().get_val();
2443 if (n_ptcs > 0) {
2444 for (int i = 0; i < n_ptcs; i++) {
2445 component ptc_compref = text_buf.pull_int().get_val();
2446 char *ptc_name = text_buf.pull_string();
2447 verdicttype ptc_verdict = (verdicttype)text_buf.pull_int().get_val();
2448 char *ptc_verdict_reason = text_buf.pull_string();
2449 if (ptc_verdict < NONE || ptc_verdict > ERROR) {
2450 delete [] ptc_name;
2451 TTCN_error("Internal error: Invalid PTC verdict was "
2452 "received from MC: %d.", ptc_verdict);
2453 }
2454 verdicttype new_verdict =
2455 local_verdict < ptc_verdict ? ptc_verdict : local_verdict;
2456 TTCN_Logger::log_final_verdict(true, ptc_verdict, local_verdict,
2457 new_verdict, ptc_verdict_reason, -1, ptc_compref, ptc_name);
2458 delete [] ptc_name;
2459 delete [] ptc_verdict_reason;
2460 local_verdict = new_verdict;
2461 }
2462 } else {
2463 TTCN_Logger::log_final_verdict(false, local_verdict, local_verdict,
2464 local_verdict, (const char *)verdict_reason,
2465 TitanLoggerApi::FinalVerdictType_choice_notification::no__ptcs__were__created);
2466 }
2467
2468 boolean continue_execution = (boolean)text_buf.pull_int().get_val();
2469 if (continue_execution) executor_state = MTC_CONTROLPART;
2470 else executor_state = MTC_PAUSED;
2471 }
2472
2473 void TTCN_Runtime::process_kill()
2474 {
2475 if (!is_ptc())
2476 TTCN_error("Internal error: Message KILL arrived in invalid state.");
2477 switch (executor_state) {
2478 case PTC_IDLE:
2479 case PTC_STOPPED:
2480 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::kill__request__frm__mc);
2481 // This may affect the final verdict.
2482 terminate_component_type();
2483 // Send a KILLED message so that the value returned by previous behaviour
2484 // function remains active.
2485 TTCN_Communication::send_killed(local_verdict);
2486 TTCN_Logger::log_final_verdict(true, local_verdict, local_verdict,
2487 local_verdict, (const char *)verdict_reason);
2488 executor_state = PTC_EXIT;
2489 case PTC_EXIT:
2490 break;
2491 default:
2492 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED,
2493 "Kill was requested from MC.");
2494 kill_execution();
2495 }
2496 }
2497
2498 void TTCN_Runtime::process_kill_process(component component_reference)
2499 {
2500 if (!is_hc()) TTCN_error("Internal error: Message KILL_PROCESS arrived "
2501 "in invalid state.");
2502 component_process_struct *comp =
2503 get_component_by_compref(component_reference);
2504 if (comp != NULL) {
2505 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
2506 "Killing component with component reference %d, process id: %ld.",
2507 component_reference, (long)comp->process_id);
2508 if (comp->process_killed) TTCN_warning("Process with process id %ld "
2509 "has been already killed. Killing it again.",
2510 (long)comp->process_id);
2511 if (kill(comp->process_id, SIGKILL)) {
2512 if (errno == ESRCH) {
2513 errno = 0;
2514 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
2515 "Process with process id %ld has already terminated.", (long)comp->process_id);
2516 } else TTCN_error("kill() system call failed on process id %ld.",
2517 (long)comp->process_id);
2518 }
2519 comp->process_killed = TRUE;
2520 } else {
2521 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
2522 "Component with component reference %d does not exist. "
2523 "Request for killing was ignored.", component_reference);
2524 }
2525 }
2526
2527 void TTCN_Runtime::set_component_done(component component_reference,
2528 const char *return_type, int return_value_len,
2529 const void *return_value)
2530 {
2531 switch (component_reference) {
2532 case ANY_COMPREF:
2533 if (is_mtc()) any_component_done_status = ALT_YES;
2534 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2535 "ANY_COMPREF): can be used only on MTC.");
2536 break;
2537 case ALL_COMPREF:
2538 if (is_mtc()) all_component_done_status = ALT_YES;
2539 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2540 "ALL_COMPREF): can be used only on MTC.");
2541 break;
2542 case NULL_COMPREF:
2543 case MTC_COMPREF:
2544 case SYSTEM_COMPREF:
2545 TTCN_error("Internal error: TTCN_Runtime::set_component_done: "
2546 "invalid component reference: %d.", component_reference);
2547 break;
2548 default: {
2549 int index = get_component_status_table_index(component_reference);
2550 component_status_table[index].done_status = ALT_YES;
2551 Free(component_status_table[index].return_type);
2552 delete component_status_table[index].return_value;
2553 if (return_type != NULL && return_type[0] != '\0') {
2554 component_status_table[index].return_type = mcopystr(return_type);
2555 component_status_table[index].return_value = new Text_Buf;
2556 component_status_table[index].return_value->push_raw(
2557 return_value_len, return_value);
2558 } else {
2559 component_status_table[index].return_type = NULL;
2560 component_status_table[index].return_value = NULL;
2561 }
2562 }
2563 }
2564 }
2565
2566 void TTCN_Runtime::set_component_killed(component component_reference)
2567 {
2568 switch (component_reference) {
2569 case ANY_COMPREF:
2570 if (is_mtc()) any_component_killed_status = ALT_YES;
2571 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2572 "ANY_COMPREF): can be used only on MTC.");
2573 break;
2574 case ALL_COMPREF:
2575 if (is_mtc()) all_component_killed_status = ALT_YES;
2576 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2577 "ALL_COMPREF): can be used only on MTC.");
2578 break;
2579 case NULL_COMPREF:
2580 case MTC_COMPREF:
2581 case SYSTEM_COMPREF:
2582 TTCN_error("Internal error: TTCN_Runtime::set_component_killed: "
2583 "invalid component reference: %d.", component_reference);
2584 default:
2585 component_status_table[get_component_status_table_index(
2586 component_reference)].killed_status = ALT_YES;
2587 }
2588 }
2589
2590 void TTCN_Runtime::cancel_component_done(component component_reference)
2591 {
2592 switch (component_reference) {
2593 case ANY_COMPREF:
2594 if (is_mtc()) any_component_done_status = ALT_UNCHECKED;
2595 else TTCN_error("Internal error: TTCN_Runtime::cancel_component_done("
2596 "ANY_COMPREF): can be used only on MTC.");
2597 break;
2598 case ALL_COMPREF:
2599 case NULL_COMPREF:
2600 case MTC_COMPREF:
2601 case SYSTEM_COMPREF:
2602 TTCN_error("Internal error: TTCN_Runtime::cancel_component_done: "
2603 "invalid component reference: %d.", component_reference);
2604 default:
2605 if (in_component_status_table(component_reference)) {
2606 int index = get_component_status_table_index(component_reference);
2607 component_status_table[index].done_status = ALT_UNCHECKED;
2608 Free(component_status_table[index].return_type);
2609 component_status_table[index].return_type = NULL;
2610 delete component_status_table[index].return_value;
2611 component_status_table[index].return_value = NULL;
2612 }
2613 }
2614 }
2615
2616 int TTCN_Runtime::get_component_status_table_index(
2617 component component_reference)
2618 {
2619 if (component_reference < FIRST_PTC_COMPREF) {
2620 TTCN_error("Internal error: TTCN_Runtime::"
2621 "get_component_status_table_index: invalid component reference: "
2622 "%d.", component_reference);
2623 }
2624 if (component_status_table_size == 0) {
2625 // the table is empty
2626 // this will be the first entry
2627 component_status_table = (component_status_table_struct*)
2628 Malloc(sizeof(*component_status_table));
2629 component_status_table[0].done_status = ALT_UNCHECKED;
2630 component_status_table[0].killed_status = ALT_UNCHECKED;
2631 component_status_table[0].return_type = NULL;
2632 component_status_table[0].return_value = NULL;
2633 component_status_table_size = 1;
2634 component_status_table_offset = component_reference;
2635 return 0;
2636 } else if (component_reference >= component_status_table_offset) {
2637 // the table contains at least one entry that is smaller than
2638 // component_reference
2639 int component_index =
2640 component_reference - component_status_table_offset;
2641 if (component_index >= component_status_table_size) {
2642 // component_reference is still not in the table
2643 // the table has to be extended at the end
2644 component_status_table = (component_status_table_struct*)
2645 Realloc(component_status_table,
2646 (component_index + 1) * sizeof(*component_status_table));
2647 // initializing the new table entries at the end
2648 for (int i = component_status_table_size;
2649 i <= component_index; i++) {
2650 component_status_table[i].done_status = ALT_UNCHECKED;
2651 component_status_table[i].killed_status = ALT_UNCHECKED;
2652 component_status_table[i].return_type = NULL;
2653 component_status_table[i].return_value = NULL;
2654 }
2655 component_status_table_size = component_index + 1;
2656 }
2657 return component_index;
2658 } else {
2659 // component_reference has to be inserted before the existing table
2660 int offset_diff = component_status_table_offset - component_reference;
2661 // offset_diff indicates how many new elements have to be inserted
2662 // before the existing table
2663 int new_size = component_status_table_size + offset_diff;
2664 component_status_table = (component_status_table_struct*)
2665 Realloc(component_status_table,
2666 new_size * sizeof(*component_status_table));
2667 // moving forward the existing table
2668 memmove(component_status_table + offset_diff, component_status_table,
2669 component_status_table_size * sizeof(*component_status_table));
2670 // initializing the first table entries
2671 for (int i = 0; i < offset_diff; i++) {
2672 component_status_table[i].done_status = ALT_UNCHECKED;
2673 component_status_table[i].killed_status = ALT_UNCHECKED;
2674 component_status_table[i].return_type = NULL;
2675 component_status_table[i].return_value = NULL;
2676 }
2677 component_status_table_size = new_size;
2678 component_status_table_offset = component_reference;
2679 return 0;
2680 }
2681 }
2682
2683 alt_status TTCN_Runtime::get_killed_status(component component_reference)
2684 {
2685 return component_status_table
2686 [get_component_status_table_index(component_reference)].killed_status;
2687 }
2688
2689 boolean TTCN_Runtime::in_component_status_table(component component_reference)
2690 {
2691 return component_reference >= component_status_table_offset &&
2692 component_reference <
2693 component_status_table_size + component_status_table_offset;
2694 }
2695
2696 void TTCN_Runtime::clear_component_status_table()
2697 {
2698 for (component i = 0; i < component_status_table_size; i++) {
2699 Free(component_status_table[i].return_type);
2700 delete component_status_table[i].return_value;
2701 }
2702 Free(component_status_table);
2703 component_status_table = NULL;
2704 component_status_table_size = 0;
2705 component_status_table_offset = FIRST_PTC_COMPREF;
2706 }
2707
2708 #define HASHTABLE_SIZE 97
2709
2710 void TTCN_Runtime::initialize_component_process_tables()
2711 {
2712 components_by_compref = new component_process_struct*[HASHTABLE_SIZE];
2713 components_by_pid = new component_process_struct*[HASHTABLE_SIZE];
2714 for (unsigned int i = 0; i < HASHTABLE_SIZE; i++) {
2715 components_by_compref[i] = NULL;
2716 components_by_pid[i] = NULL;
2717 }
2718 }
2719
2720 void TTCN_Runtime::add_component(component component_reference,
2721 pid_t process_id)
2722 {
2723 if (component_reference != MTC_COMPREF &&
2724 get_component_by_compref(component_reference) != NULL)
2725 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2726 "duplicated component reference (%d)", component_reference);
2727 if (get_component_by_pid(process_id) != NULL)
2728 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2729 "duplicated pid (%ld)", (long)process_id);
2730
2731 component_process_struct *new_comp = new component_process_struct;
2732 new_comp->component_reference = component_reference;
2733 new_comp->process_id = process_id;
2734 new_comp->process_killed = FALSE;
2735
2736 new_comp->prev_by_compref = NULL;
2737 component_process_struct*& head_by_compref =
2738 components_by_compref[component_reference % HASHTABLE_SIZE];
2739 new_comp->next_by_compref = head_by_compref;
2740 if (head_by_compref != NULL) head_by_compref->prev_by_compref = new_comp;
2741 head_by_compref = new_comp;
2742
2743 new_comp->prev_by_pid = NULL;
2744 component_process_struct*& head_by_pid =
2745 components_by_pid[process_id % HASHTABLE_SIZE];
2746 new_comp->next_by_pid = head_by_pid;
2747 if (head_by_pid != NULL) head_by_pid->prev_by_pid = new_comp;
2748 head_by_pid = new_comp;
2749 }
2750
2751 void TTCN_Runtime::remove_component(component_process_struct *comp)
2752 {
2753 if (comp->next_by_compref != NULL)
2754 comp->next_by_compref->prev_by_compref = comp->prev_by_compref;
2755 if (comp->prev_by_compref != NULL)
2756 comp->prev_by_compref->next_by_compref = comp->next_by_compref;
2757 else components_by_compref[comp->component_reference % HASHTABLE_SIZE] =
2758 comp->next_by_compref;
2759 if (comp->next_by_pid != NULL)
2760 comp->next_by_pid->prev_by_pid = comp->prev_by_pid;
2761 if (comp->prev_by_pid != NULL)
2762 comp->prev_by_pid->next_by_pid = comp->next_by_pid;
2763 else components_by_pid[comp->process_id % HASHTABLE_SIZE] =
2764 comp->next_by_pid;
2765 delete comp;
2766 }
2767
2768 TTCN_Runtime::component_process_struct *TTCN_Runtime::get_component_by_compref(
2769 component component_reference)
2770 {
2771 component_process_struct *iter =
2772 components_by_compref[component_reference % HASHTABLE_SIZE];
2773 while (iter != NULL) {
2774 if (iter->component_reference == component_reference) break;
2775 iter = iter->next_by_compref;
2776 }
2777 return iter;
2778 }
2779
2780 TTCN_Runtime::component_process_struct *TTCN_Runtime::get_component_by_pid(
2781 pid_t process_id)
2782 {
2783 component_process_struct *iter =
2784 components_by_pid[process_id % HASHTABLE_SIZE];
2785 while (iter != NULL) {
2786 if (iter->process_id == process_id) break;
2787 iter = iter->next_by_pid;
2788 }
2789 return iter;
2790 }
2791
2792 void TTCN_Runtime::clear_component_process_tables()
2793 {
2794 if (components_by_compref == NULL) return;
2795 for (unsigned int i = 0; i < HASHTABLE_SIZE; i++) {
2796 while (components_by_compref[i] != NULL)
2797 remove_component(components_by_compref[i]);
2798 while (components_by_pid[i] != NULL)
2799 remove_component(components_by_pid[i]);
2800 }
2801 delete [] components_by_compref;
2802 components_by_compref = NULL;
2803 delete [] components_by_pid;
2804 components_by_pid = NULL;
2805 }
2806
2807 void TTCN_Runtime::successful_process_creation()
2808 {
2809 if (is_overloaded()) {
2810 TTCN_Communication::send_hc_ready();
2811 TTCN_Communication::disable_periodic_call();
2812 executor_state = HC_ACTIVE;
2813 }
2814 }
2815
2816 void TTCN_Runtime::failed_process_creation()
2817 {
2818 if (executor_state == HC_ACTIVE) {
2819 TTCN_Communication::enable_periodic_call();
2820 executor_state = HC_OVERLOADED;
2821 }
2822 }
2823
2824 void TTCN_Runtime::wait_terminated_processes()
2825 {
2826 // this function might be called from TCs too while returning from
2827 // TTCN_Communication::process_all_messages_hc() after fork()
2828 if (!is_hc()) return;
2829 errno = 0;
2830 for ( ; ; ) {
2831 int statuscode;
2832 struct rusage r_usage = {{0,0},{0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2833 #ifdef INTERIX
2834 pid_t child_pid = waitpid(-1, &statuscode, WNOHANG);
2835 getrusage(RUSAGE_CHILDREN, &r_usage);
2836 #else
2837 pid_t child_pid = wait3(&statuscode, WNOHANG, &r_usage);
2838 #endif
2839 if (child_pid <= 0) {
2840 switch (errno) {
2841 case ECHILD:
2842 errno = 0;
2843 // no break
2844 case 0:
2845 return;
2846 default:
2847 TTCN_error("System call wait3() failed when waiting for "
2848 "terminated test component processes.");
2849 }
2850 }
2851 component_process_struct *comp = get_component_by_pid(child_pid);
2852 if (comp != NULL) {
2853 int reason;
2854 const char *comp_name = NULL;
2855 if (comp->component_reference == MTC_COMPREF) {
2856 reason = API::ParallelPTC_reason::mtc__finished;
2857 }
2858 else {
2859 reason = API::ParallelPTC_reason::ptc__finished;
2860 comp_name = COMPONENT::get_component_name(comp->component_reference);
2861 }
2862 char *rusage = NULL;
2863 rusage = mprintf(
2864 "user time: %ld.%06ld s, system time: %ld.%06ld s, "
2865 "maximum resident set size: %ld, "
2866 "integral resident set size: %ld, "
2867 "page faults not requiring physical I/O: %ld, "
2868 "page faults requiring physical I/O: %ld, "
2869 "swaps: %ld, "
2870 "block input operations: %ld, block output operations: %ld, "
2871 "messages sent: %ld, messages received: %ld, "
2872 "signals received: %ld, "
2873 "voluntary context switches: %ld, "
2874 "involuntary context switches: %ld }",
2875 (long)r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,
2876 (long)r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec,
2877 r_usage.ru_maxrss, r_usage.ru_idrss,
2878 r_usage.ru_minflt, r_usage.ru_majflt, r_usage.ru_nswap,
2879 r_usage.ru_inblock, r_usage.ru_oublock,
2880 r_usage.ru_msgsnd, r_usage.ru_msgrcv, r_usage.ru_nsignals,
2881 r_usage.ru_nvcsw, r_usage.ru_nivcsw);
2882 // There are too many different integer types in the rusage structure.
2883 // Just format them into a string and and pass that to the logger.
2884 TTCN_Logger::log_par_ptc(reason, NULL, NULL,
2885 comp->component_reference, comp_name, rusage, child_pid, statuscode);
2886 Free(rusage);
2887 remove_component(comp);
2888 } else {
2889 TTCN_warning("wait3() system call returned unknown process id %ld.",
2890 (long)child_pid);
2891 }
2892 }
2893 }
2894
2895 void TTCN_Runtime::check_overload()
2896 {
2897 if (!is_hc()) TTCN_error("Internal error: TTCN_Runtime::check_overload() "
2898 "can be used on HCs only.");
2899 if (!is_overloaded()) return;
2900 TTCN_Logger::log_executor_runtime(
2901 API::ExecutorRuntime_reason::overload__check);
2902 pid_t child_pid = fork();
2903 if (child_pid < 0) {
2904 // fork failed, the host is still overloaded
2905 TTCN_Logger::log_executor_runtime(
2906 API::ExecutorRuntime_reason::overload__check__fail);
2907 //TODO TTCN_Logger::OS_error();
2908 if (executor_state == HC_OVERLOADED_TIMEOUT) {
2909 // increase the call interval if the function was called because of
2910 // a timeout
2911 TTCN_Communication::increase_call_interval();
2912 executor_state = HC_OVERLOADED;
2913 }
2914 } else if (child_pid > 0) {
2915 // fork was successful, this code runs on the parent process (HC)
2916 int statuscode;
2917 // wait until the dummy child terminates
2918 pid_t result_pid = waitpid(child_pid, &statuscode, 0);
2919 if (result_pid != child_pid) TTCN_error("System call waitpid() "
2920 "returned unexpected status code %ld when waiting for the dummy "
2921 "child process with PID %ld.", (long)result_pid, (long)child_pid);
2922 successful_process_creation();
2923 TTCN_Logger::log_executor_runtime(
2924 API::ExecutorRuntime_reason::overloaded__no__more);
2925 // FIXME pid is not logged; it would need a separate function
2926
2927 // analyze the status code and issue a warning if something strange
2928 // happened
2929 if (WIFEXITED(statuscode)) {
2930 int exitstatus = WEXITSTATUS(statuscode);
2931 if (exitstatus != EXIT_SUCCESS) TTCN_warning("Dummy child process "
2932 "with PID %ld returned unsuccessful exit status (%d).",
2933 (long)child_pid, exitstatus);
2934 } else if (WIFSIGNALED(statuscode)) {
2935 int signum = WTERMSIG(statuscode);
2936 TTCN_warning("Dummy child process with PID %ld was terminated by "
2937 "signal %d (%s).", (long)child_pid, signum,
2938 get_signal_name(signum));
2939 } else {
2940 TTCN_warning("Dummy child process with PID %ld was terminated by "
2941 "an unknown reason (return status: %d).", (long)child_pid,
2942 statuscode);
2943 }
2944 // try to clean up some more zombies if possible
2945 wait_terminated_processes();
2946 } else {
2947 // fork was successful, this code runs on the dummy child process
2948 // the dummy child process shall exit immediately
2949 exit(EXIT_SUCCESS);
2950 }
2951 }
This page took 0.113038 seconds and 6 git commands to generate.