1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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()
19 #include <sys/types.h>
22 #include <sys/resource.h>
25 #include <sys/utsname.h>
28 #include "../common/memory.h"
29 #include "../common/version_internal.h"
31 #include "Communication.hh"
34 #include "Snapshot.hh"
37 #include "Module_list.hh"
38 #include "Component.hh"
40 #include "Verdicttype.hh"
41 #include "Charstring.hh"
42 #include "Fd_And_Timeout_User.hh"
43 #include <TitanLoggerApi.hh>
44 #include "Profiler.hh"
46 namespace API
= TitanLoggerApi
;
48 #ifndef MAXHOSTNAMELEN
49 # define MAXHOSTNAMELEN 256
52 #include "../common/dbgnew.hh"
54 TTCN_Runtime::executor_state_enum
55 TTCN_Runtime::executor_state
= UNDEFINED_STATE
;
57 qualified_name
TTCN_Runtime::component_type
= { NULL
, NULL
};
58 char *TTCN_Runtime::component_name
= NULL
;
59 boolean
TTCN_Runtime::is_alive
= FALSE
;
61 const char *TTCN_Runtime::control_module_name
= NULL
;
62 qualified_name
TTCN_Runtime::testcase_name
= { NULL
, NULL
};
64 char *TTCN_Runtime::host_name
= NULL
;
66 verdicttype
TTCN_Runtime::local_verdict
= NONE
;
67 unsigned int TTCN_Runtime::verdict_count
[5] = { 0, 0, 0, 0, 0 },
68 TTCN_Runtime::control_error_count
= 0;
69 CHARSTRING
TTCN_Runtime::verdict_reason(0, ""); // empty string
71 boolean
TTCN_Runtime::in_ttcn_try_block
= FALSE
;
73 char *TTCN_Runtime::begin_controlpart_command
= NULL
,
74 *TTCN_Runtime::end_controlpart_command
= NULL
,
75 *TTCN_Runtime::begin_testcase_command
= NULL
,
76 *TTCN_Runtime::end_testcase_command
= NULL
;
78 component
TTCN_Runtime::create_done_killed_compref
= NULL_COMPREF
;
79 boolean
TTCN_Runtime::running_alive_result
= FALSE
;
81 alt_status
TTCN_Runtime::any_component_done_status
= ALT_UNCHECKED
,
82 TTCN_Runtime::all_component_done_status
= ALT_UNCHECKED
,
83 TTCN_Runtime::any_component_killed_status
= ALT_UNCHECKED
,
84 TTCN_Runtime::all_component_killed_status
= ALT_UNCHECKED
;
85 int TTCN_Runtime::component_status_table_size
= 0;
86 component
TTCN_Runtime::component_status_table_offset
= FIRST_PTC_COMPREF
;
87 struct TTCN_Runtime::component_status_table_struct
{
88 alt_status done_status
, killed_status
;
90 Text_Buf
*return_value
;
91 } *TTCN_Runtime::component_status_table
= NULL
;
93 struct TTCN_Runtime::component_process_struct
{
94 component component_reference
;
96 boolean process_killed
;
97 struct component_process_struct
*prev_by_compref
, *next_by_compref
;
98 struct component_process_struct
*prev_by_pid
, *next_by_pid
;
99 } **TTCN_Runtime::components_by_compref
= NULL
,
100 **TTCN_Runtime::components_by_pid
= NULL
;
102 boolean
TTCN_Runtime::is_idle()
104 switch (executor_state
) {
117 boolean
TTCN_Runtime::verdict_enabled()
119 return executor_state
== SINGLE_TESTCASE
||
120 (executor_state
>= MTC_TESTCASE
&& executor_state
<= MTC_EXIT
) ||
121 (executor_state
>= PTC_INITIAL
&& executor_state
<= PTC_EXIT
);
124 void TTCN_Runtime::wait_for_state_change()
126 executor_state_enum old_state
= executor_state
;
128 TTCN_Snapshot::take_new(TRUE
);
129 } while (old_state
== executor_state
);
132 void TTCN_Runtime::clear_qualified_name(qualified_name
& q_name
)
134 Free(q_name
.module_name
);
135 q_name
.module_name
= NULL
;
136 Free(q_name
.definition_name
);
137 q_name
.definition_name
= NULL
;
140 void TTCN_Runtime::clean_up()
142 clear_qualified_name(component_type
);
143 Free(component_name
);
144 component_name
= NULL
;
145 control_module_name
= NULL
;
146 clear_qualified_name(testcase_name
);
149 clear_external_commands();
152 void TTCN_Runtime::initialize_component_type()
154 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__start
,
155 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
156 TTCN_Runtime::get_testcase_name());
158 Module_List::initialize_component(component_type
.module_name
,
159 component_type
.definition_name
, TRUE
);
160 PORT::set_parameters((component
)self
, component_name
);
163 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__finish
,
164 component_type
.module_name
, component_type
.definition_name
);
166 local_verdict
= NONE
;
170 void TTCN_Runtime::terminate_component_type()
172 if (component_type
.module_name
!= NULL
&&
173 component_type
.definition_name
!= NULL
) {
174 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::terminating__component
,
175 component_type
.module_name
, component_type
.definition_name
);
177 TTCN_Default::deactivate_all();
179 PORT::deactivate_all();
181 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::component__shut__down
,
182 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
183 TTCN_Runtime::get_testcase_name());
185 clear_qualified_name(component_type
);
186 Free(component_name
);
187 component_name
= NULL
;
191 void TTCN_Runtime::set_component_type(const char *component_type_module
,
192 const char *component_type_name
)
194 if (component_type_module
== NULL
|| component_type_module
[0] == '\0' ||
195 component_type_name
== NULL
|| component_type_name
[0] == '\0')
196 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
197 "Trying to set an invalid component type.");
198 if (component_type
.module_name
!= NULL
||
199 component_type
.definition_name
!= NULL
)
200 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
201 "Trying to set component type %s.%s while another one is active.",
202 component_type_module
, component_type_name
);
204 component_type
.module_name
= mcopystr(component_type_module
);
205 component_type
.definition_name
= mcopystr(component_type_name
);
208 void TTCN_Runtime::set_component_name(const char *new_component_name
)
210 Free(component_name
);
211 if (new_component_name
!= NULL
&& new_component_name
[0] != '\0')
212 component_name
= mcopystr(new_component_name
);
213 else component_name
= NULL
;
216 void TTCN_Runtime::set_testcase_name(const char *par_module_name
,
217 const char *par_testcase_name
)
219 if (par_module_name
== NULL
|| par_module_name
[0] == '\0' ||
220 par_testcase_name
== NULL
|| par_testcase_name
[0] == '\0')
221 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
222 "Trying to set an invalid testcase name.");
223 if (testcase_name
.module_name
!= NULL
||
224 testcase_name
.definition_name
!= NULL
)
225 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
226 "Trying to set testcase name %s.%s while another one is active.",
227 par_module_name
, par_testcase_name
);
229 testcase_name
.module_name
= mcopystr(par_module_name
);
230 testcase_name
.definition_name
= mcopystr(par_testcase_name
);
233 const char *TTCN_Runtime::get_host_name()
235 if (host_name
== NULL
) {
236 #if defined(SOLARIS8)
237 // Workaround for Solaris10 (lumped under SOLARIS8) + dynamic linking.
238 // "g++ -shared" seems to produce a very strange kind of symbol
239 // for gethostname in the .so, and linking fails with the infamous
240 // "ld: libttcn3-dynamic.so: gethostname: invalid version 3 (max 0)"
241 // The workaround is to use uname instead of gethostname.
243 if (uname(&uts
) < 0) {
244 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
245 TTCN_Logger::log_event_str("System call uname() failed.");
246 TTCN_Logger::OS_error();
247 TTCN_Logger::end_event();
248 host_name
= mcopystr("unknown");
250 host_name
= mcopystr(uts
.nodename
);
253 char tmp_str
[MAXHOSTNAMELEN
+ 1];
254 if (gethostname(tmp_str
, MAXHOSTNAMELEN
)) {
255 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
256 TTCN_Logger::log_event_str("System call gethostname() failed.");
257 TTCN_Logger::OS_error();
258 TTCN_Logger::end_event();
260 } else tmp_str
[MAXHOSTNAMELEN
] = '\0';
261 if (tmp_str
[0] != '\0') host_name
= mcopystr(tmp_str
);
262 else host_name
= mcopystr("unknown");
268 CHARSTRING
TTCN_Runtime::get_testcase_id_macro()
270 if (in_controlpart()) TTCN_error("Macro %%testcaseId cannot be used from "
271 "the control part outside test cases.");
272 if (testcase_name
.definition_name
== NULL
||
273 testcase_name
.definition_name
[0] == '\0')
274 TTCN_error("Internal error: Evaluating macro %%testcaseId, but the "
275 "name of the current testcase is not set.");
276 return CHARSTRING(testcase_name
.definition_name
);
279 CHARSTRING
TTCN_Runtime::get_testcasename()
281 if (in_controlpart() || is_hc()) return CHARSTRING(""); // No error here.
283 if (!testcase_name
.definition_name
|| testcase_name
.definition_name
[0] == 0)
284 TTCN_error("Internal error: Evaluating predefined function testcasename()"
285 ", but the name of the current testcase is not set.");
287 return CHARSTRING(testcase_name
.definition_name
);
290 void TTCN_Runtime::load_logger_plugins()
292 TTCN_Logger::load_plugins((component
)self
, component_name
);
295 void TTCN_Runtime::set_logger_parameters()
297 TTCN_Logger::set_plugin_parameters((component
)self
, component_name
);
300 const char *TTCN_Runtime::get_signal_name(int signal_number
)
302 const char *signal_name
= strsignal(signal_number
);
303 if (signal_name
!= NULL
) return signal_name
;
304 else return "Unknown signal";
307 static void sigint_handler(int signum
)
309 if (signum
!= SIGINT
) {
310 TTCN_warning("Unexpected signal %d (%s) was caught by the handler of "
311 "SIGINT.", signum
, TTCN_Runtime::get_signal_name(signum
));
314 if (TTCN_Runtime::is_single()) {
315 TTCN_Logger::log_str(TTCN_Logger::WARNING_UNQUALIFIED
,
316 "Execution was interrupted by the user.");
317 if (TTCN_Runtime::get_state() == TTCN_Runtime::SINGLE_TESTCASE
) {
318 TTCN_Logger::log_executor_runtime(
319 API::ExecutorRuntime_reason::stopping__current__testcase
);
320 TTCN_Runtime::end_testcase();
324 TTCN_Logger::log_executor_runtime(
325 API::ExecutorRuntime_reason::exiting
);
331 void TTCN_Runtime::set_signal_handler(int signal_number
,
332 const char *signal_name
, signal_handler_type signal_handler
)
334 struct sigaction sig_act
;
335 if (sigaction(signal_number
, NULL
, &sig_act
))
336 TTCN_error("System call sigaction() failed when getting signal "
337 "handling information for %s.", signal_name
);
338 sig_act
.sa_handler
= signal_handler
;
339 sig_act
.sa_flags
= 0;
340 if (sigaction(signal_number
, &sig_act
, NULL
))
341 TTCN_error("System call sigaction() failed when changing the signal "
342 "handling settings for %s.", signal_name
);
345 void TTCN_Runtime::restore_default_handler(int signal_number
,
346 const char *signal_name
)
348 struct sigaction sig_act
;
349 if (sigaction(signal_number
, NULL
, &sig_act
))
350 TTCN_error("System call sigaction() failed when getting signal "
351 "handling information for %s.", signal_name
);
352 sig_act
.sa_handler
= SIG_DFL
;
353 sig_act
.sa_flags
= 0;
354 if (sigaction(signal_number
, &sig_act
, NULL
))
355 TTCN_error("System call sigaction() failed when restoring the "
356 "default signal handling settings for %s.", signal_name
);
359 void TTCN_Runtime::ignore_signal(int signal_number
, const char *signal_name
)
361 struct sigaction sig_act
;
362 if (sigaction(signal_number
, NULL
, &sig_act
))
363 TTCN_error("System call sigaction() failed when getting signal "
364 "handling information for %s.", signal_name
);
365 sig_act
.sa_handler
= SIG_IGN
;
366 sig_act
.sa_flags
= 0;
367 if (sigaction(signal_number
, &sig_act
, NULL
))
368 TTCN_error("System call sigaction() failed when disabling signal "
372 void TTCN_Runtime::enable_interrupt_handler()
374 set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
377 void TTCN_Runtime::disable_interrupt_handler()
379 ignore_signal(SIGINT
, "SIGINT");
382 void TTCN_Runtime::install_signal_handlers()
384 if (is_single()) set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
385 ignore_signal(SIGPIPE
, "SIGPIPE");
388 void TTCN_Runtime::restore_signal_handlers()
390 if (is_single()) restore_default_handler(SIGINT
, "SIGINT");
391 restore_default_handler(SIGPIPE
, "SIGPIPE");
394 int TTCN_Runtime::hc_main(const char *local_addr
, const char *MC_addr
,
395 unsigned short MC_port
)
397 int ret_val
= EXIT_SUCCESS
;
398 executor_state
= HC_INITIAL
;
399 TTCN_Logger::log_HC_start(get_host_name());
400 TTCN_Logger::write_logger_settings();
401 TTCN_Snapshot::check_fd_setsize();
403 if (local_addr
!= NULL
)
404 TTCN_Communication::set_local_address(local_addr
);
405 TTCN_Communication::set_mc_address(MC_addr
, MC_port
);
406 TTCN_Communication::connect_mc();
407 Module_List::send_versions();
408 executor_state
= HC_IDLE
;
409 TTCN_Communication::send_version();
410 initialize_component_process_tables();
412 TTCN_Snapshot::take_new(TRUE
);
413 TTCN_Communication::process_all_messages_hc();
414 } while (executor_state
>= HC_IDLE
&& executor_state
< HC_EXIT
);
415 if (executor_state
== HC_EXIT
) {
416 // called only on the HC
417 TTCN_Communication::disconnect_mc();
420 } catch (const TC_Error
& tc_error
) {
421 ret_val
= EXIT_FAILURE
;
424 // called on the newly created MTC and PTCs as well because
425 // the hashtables are inherited with fork()
426 clear_component_process_tables();
429 TTCN_Logger::log_executor_runtime(
430 API::ExecutorRuntime_reason::host__controller__finished
);
435 int TTCN_Runtime::mtc_main()
437 int ret_val
= EXIT_SUCCESS
;
438 TTCN_Runtime::load_logger_plugins();
439 TTCN_Runtime::set_logger_parameters();
440 TTCN_Logger::open_file();
441 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__started
);
442 TTCN_Logger::write_logger_settings();
444 TTCN_Communication::connect_mc();
445 executor_state
= MTC_IDLE
;
446 TTCN_Communication::send_mtc_created();
448 TTCN_Snapshot::take_new(TRUE
);
449 TTCN_Communication::process_all_messages_tc();
450 } while (executor_state
!= MTC_EXIT
);
451 TTCN_Logger::close_file();
452 TTCN_Communication::disconnect_mc();
454 } catch (const TC_Error
& tc_error
) {
455 ret_val
= EXIT_FAILURE
;
457 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__finished
);
461 int TTCN_Runtime::ptc_main()
463 int ret_val
= EXIT_SUCCESS
;
464 TTCN_Runtime::load_logger_plugins();
465 TTCN_Runtime::set_logger_parameters();
466 TTCN_Logger::open_file();
467 TTCN_Logger::begin_event(TTCN_Logger::EXECUTOR_COMPONENT
);
468 TTCN_Logger::log_event("TTCN-3 Parallel Test Component started on %s. "
469 "Component reference: ", get_host_name());
471 TTCN_Logger::log_event(", component type: %s.%s",
472 component_type
.module_name
, component_type
.definition_name
);
473 if (component_name
!= NULL
)
474 TTCN_Logger::log_event(", component name: %s", component_name
);
475 TTCN_Logger::log_event_str(". Version: " PRODUCT_NUMBER
".");
476 TTCN_Logger::end_event();
477 TTCN_Logger::write_logger_settings();
479 TTCN_Communication::connect_mc();
480 executor_state
= PTC_IDLE
;
481 TTCN_Communication::send_ptc_created((component
)self
);
483 initialize_component_type();
484 } catch (const TC_Error
& tc_error
) {
485 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::component__init__fail
);
486 ret_val
= EXIT_FAILURE
;
488 if (ret_val
== EXIT_SUCCESS
) {
491 TTCN_Snapshot::take_new(TRUE
);
492 TTCN_Communication::process_all_messages_tc();
493 } while (executor_state
!= PTC_EXIT
);
494 } catch (const TC_Error
& tc_error
) {
495 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::error__idle__ptc
);
496 ret_val
= EXIT_FAILURE
;
499 if (ret_val
!= EXIT_SUCCESS
) {
500 // ignore errors in subsequent operations
502 terminate_component_type();
503 } catch (const TC_Error
& tc_error
) { }
505 TTCN_Communication::send_killed(local_verdict
, (const char *)verdict_reason
);
506 } catch (const TC_Error
& tc_error
) { }
507 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
508 local_verdict
, (const char *)verdict_reason
);
509 executor_state
= PTC_EXIT
;
511 TTCN_Communication::disconnect_mc();
512 clear_component_status_table();
514 } catch (const TC_Error
& tc_error
) {
515 ret_val
= EXIT_FAILURE
;
517 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::ptc__finished
);
521 component
TTCN_Runtime::create_component(
522 const char *created_component_type_module
,
523 const char *created_component_type_name
, const char *created_component_name
,
524 const char *created_component_location
, boolean created_component_alive
)
526 if (in_controlpart())
527 TTCN_error("Create operation cannot be performed in the control part.");
528 else if (is_single())
529 TTCN_error("Create operation cannot be performed in single mode.");
531 if (created_component_name
!= NULL
&&
532 created_component_name
[0] == '\0') {
533 TTCN_warning("Empty charstring value was ignored as component name "
534 "in create operation.");
535 created_component_name
= NULL
;
537 if (created_component_location
!= NULL
&&
538 created_component_location
[0] == '\0') {
539 TTCN_warning("Empty charstring value was ignored as component location "
540 "in create operation.");
541 created_component_location
= NULL
;
544 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
545 TTCN_Logger::log_event("Creating new %sPTC with component type %s.%s",
546 created_component_alive
? "alive ": "", created_component_type_module
,
547 created_component_type_name
);
548 if (created_component_name
!= NULL
)
549 TTCN_Logger::log_event(", component name: %s", created_component_name
);
550 if (created_component_location
!= NULL
)
551 TTCN_Logger::log_event(", location: %s", created_component_location
);
552 TTCN_Logger::log_char('.');
553 TTCN_Logger::end_event();
555 switch (executor_state
) {
557 executor_state
= MTC_CREATE
;
560 executor_state
= PTC_CREATE
;
563 TTCN_error("Internal error: Executing create operation in invalid "
566 TTCN_Communication::send_create_req(created_component_type_module
,
567 created_component_type_name
, created_component_name
,
568 created_component_location
, created_component_alive
);
570 // updating the component status flags
571 // 'any component.done' and 'any component.killed' might be successful
572 // from now since the PTC can terminate by itself
573 if (any_component_done_status
== ALT_NO
)
574 any_component_done_status
= ALT_UNCHECKED
;
575 if (any_component_killed_status
== ALT_NO
)
576 any_component_killed_status
= ALT_UNCHECKED
;
577 // 'all component.killed' must be re-evaluated later
578 all_component_killed_status
= ALT_UNCHECKED
;
580 wait_for_state_change();
582 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created
,
583 created_component_type_module
, created_component_type_name
,
584 create_done_killed_compref
, created_component_name
,
585 created_component_location
, created_component_alive
);
587 COMPONENT::register_component_name(create_done_killed_compref
,
588 created_component_name
);
589 return create_done_killed_compref
;
592 void TTCN_Runtime::prepare_start_component(const COMPONENT
& component_reference
,
593 const char *module_name
, const char *function_name
, Text_Buf
& text_buf
)
595 if (in_controlpart()) TTCN_error("Start test component operation cannot "
596 "be performed in the control part.");
597 else if (is_single()) TTCN_error("Start test component operation cannot "
598 "be performed in single mode.");
599 if (!component_reference
.is_bound()) TTCN_error("Performing a start "
600 "operation on an unbound component reference.");
601 component compref
= (component
)component_reference
;
604 TTCN_error("Start operation cannot be performed on the null "
605 "component reference.");
607 TTCN_error("Start operation cannot be performed on the component "
608 "reference of MTC.");
610 TTCN_error("Start operation cannot be performed on the component "
611 "reference of system.");
613 TTCN_error("Internal error: 'any component' cannot be started.");
615 TTCN_error("Internal error: 'all component' cannot be started.");
619 if (self
== compref
) TTCN_error("Start operation cannot be performed on "
620 "the own component reference of the initiating component (i.e. "
621 "'self.start' is not allowed).");
622 if (in_component_status_table(compref
)) {
623 if (get_killed_status(compref
) == ALT_YES
) {
624 TTCN_error("PTC with component reference %d is not alive anymore. "
625 "Start operation cannot be performed on it.", compref
);
627 // the done status of the PTC shall be invalidated
628 cancel_component_done(compref
);
630 TTCN_Communication::prepare_start_req(text_buf
, compref
, module_name
,
634 void TTCN_Runtime::send_start_component(Text_Buf
& text_buf
)
636 switch (executor_state
) {
638 executor_state
= MTC_START
;
641 executor_state
= PTC_START
;
644 TTCN_error("Internal error: Executing component start operation "
645 "in invalid state.");
647 // text_buf already contains a complete START_REQ message.
648 TTCN_Communication::send_message(text_buf
);
650 // updating the component status flags
651 // 'all component.done' must be re-evaluated later
652 all_component_done_status
= ALT_UNCHECKED
;
654 wait_for_state_change();
655 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__started
);
658 void TTCN_Runtime::start_function(const char *module_name
,
659 const char *function_name
, Text_Buf
& text_buf
)
661 switch (executor_state
) {
666 // the START message must be dropped here because normally it is
667 // dropped in function_started()
668 text_buf
.cut_message();
669 TTCN_error("Internal error: Message START arrived in invalid state.");
672 Module_List::start_function(module_name
, function_name
, text_buf
);
673 // do nothing: the function terminated normally
674 // the message STOPPED or STOPPED_KILLED is already sent out
675 // and the state variable is updated
677 } catch (const TC_End
& TC_end
) {
678 // executor_state is already set by stop_execution or kill_execution
679 switch (executor_state
) {
681 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
682 "Function %s was stopped. PTC remains alive and is waiting for next start.",
684 // send a STOPPED message without return value
685 TTCN_Communication::send_stopped();
686 // return and do nothing else
689 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__stopped
, NULL
,
693 TTCN_error("Internal error: PTC was stopped in invalid state.");
695 } catch (const TC_Error
& TC_error
) {
696 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__error
, NULL
,
698 executor_state
= PTC_EXIT
;
700 // the control reaches this code if the PTC has to be terminated
702 // first terminate all ports and timers
703 // this may affect the final verdict
704 terminate_component_type();
705 // send a STOPPED_KILLED message without return value
706 TTCN_Communication::send_stopped_killed(local_verdict
, verdict_reason
);
707 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
708 local_verdict
, (const char *)verdict_reason
);
711 void TTCN_Runtime::function_started(Text_Buf
& text_buf
)
713 // The buffer still contains the incoming START message.
714 text_buf
.cut_message();
715 executor_state
= PTC_FUNCTION
;
716 // The remaining messages must be processed now.
717 TTCN_Communication::process_all_messages_tc();
720 void TTCN_Runtime::prepare_function_finished(const char *return_type
,
723 if (executor_state
!= PTC_FUNCTION
)
724 TTCN_error("Internal error: PTC behaviour function finished in invalid "
727 // Prepare a STOPPED message with the possible return value.
728 TTCN_Communication::prepare_stopped(text_buf
, return_type
);
730 // First the ports and timers must be stopped and deactivated. The
731 // user_unmap and user_stop functions of Test Ports may detect errors
732 // that must be considered in the final verdict of the PTC.
733 terminate_component_type();
734 // Prepare a STOPPED_KILLED message with the final verdict and the
735 // possible return value.
736 TTCN_Communication::prepare_stopped_killed(text_buf
, local_verdict
,
737 return_type
, verdict_reason
);
741 void TTCN_Runtime::send_function_finished(Text_Buf
& text_buf
)
743 // send out the STOPPED or STOPPED_KILLED message, which is already
744 // complete and contains the return value
745 TTCN_Communication::send_message(text_buf
);
746 // log the final verdict if necessary and update the state variable
747 if (is_alive
) executor_state
= PTC_STOPPED
;
749 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
750 local_verdict
, (const char *)verdict_reason
);
751 executor_state
= PTC_EXIT
;
755 void TTCN_Runtime::function_finished(const char *function_name
)
757 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__finished
, NULL
,
758 function_name
, 0, NULL
, NULL
, is_alive
);
760 prepare_function_finished(NULL
, text_buf
);
761 send_function_finished(text_buf
);
764 alt_status
TTCN_Runtime::component_done(component component_reference
)
766 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
767 "in the control part.");
768 switch (component_reference
) {
770 TTCN_error("Done operation cannot be performed on the null "
771 "component reference.");
773 TTCN_error("Done operation cannot be performed on the component "
774 "reference of MTC.");
776 TTCN_error("Done operation cannot be performed on the component "
777 "reference of system.");
779 return any_component_done();
781 return all_component_done();
783 return ptc_done(component_reference
);
787 alt_status
TTCN_Runtime::component_done(component component_reference
,
788 const char *return_type
, Text_Buf
*& text_buf
)
790 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
791 "in the control part.");
792 switch (component_reference
) {
794 TTCN_error("Done operation cannot be performed on the null "
795 "component reference.");
797 TTCN_error("Done operation cannot be performed on the component "
798 "reference of MTC.");
800 TTCN_error("Done operation cannot be performed on the component "
801 "reference of system.");
803 TTCN_error("Done operation with return value cannot be performed on "
806 TTCN_error("Done operation with return value cannot be performed on "
809 // the argument refers to a PTC
812 if (is_single()) TTCN_error("Done operation on a component reference "
813 "cannot be performed in single mode.");
814 if (self
== component_reference
) {
815 TTCN_warning("Done operation on the component reference of self "
816 "will never succeed.");
819 int index
= get_component_status_table_index(component_reference
);
820 // we cannot use the killed status because we need the return value
821 switch (component_status_table
[index
].done_status
) {
823 switch (executor_state
) {
825 executor_state
= MTC_DONE
;
828 executor_state
= PTC_DONE
;
831 TTCN_error("Internal error: Executing done operation in "
834 TTCN_Communication::send_done_req(component_reference
);
835 component_status_table
[index
].done_status
= ALT_MAYBE
;
836 create_done_killed_compref
= component_reference
;
838 wait_for_state_change();
839 // always re-evaluate the current alternative using a new snapshot
842 if (component_status_table
[index
].return_type
!= NULL
) {
843 if (!strcmp(component_status_table
[index
].return_type
,
845 component_status_table
[index
].return_value
->rewind();
846 text_buf
= component_status_table
[index
].return_value
;
849 TTCN_Logger::log_matching_done(return_type
, component_reference
,
850 component_status_table
[index
].return_type
,
851 API::MatchingDoneType_reason::done__failed__wrong__return__type
);
855 TTCN_Logger::log_matching_done(return_type
, component_reference
, NULL
,
856 API::MatchingDoneType_reason::done__failed__no__return
);
865 alt_status
TTCN_Runtime::component_killed(component component_reference
)
867 if (in_controlpart()) TTCN_error("Killed operation cannot be performed "
868 "in the control part.");
869 switch (component_reference
) {
871 TTCN_error("Killed operation cannot be performed on the null "
872 "component reference.");
874 TTCN_error("Killed operation cannot be performed on the component "
875 "reference of MTC.");
877 TTCN_error("Killed operation cannot be performed on the component "
878 "reference of system.");
880 return any_component_killed();
882 return all_component_killed();
884 return ptc_killed(component_reference
);
888 boolean
TTCN_Runtime::component_running(component component_reference
)
890 if (in_controlpart()) TTCN_error("Component running operation "
891 "cannot be performed in the control part.");
892 switch (component_reference
) {
894 TTCN_error("Running operation cannot be performed on the null "
895 "component reference.");
897 TTCN_error("Running operation cannot be performed on the component "
898 "reference of MTC.");
900 TTCN_error("Running operation cannot be performed on the component "
901 "reference of system.");
903 return any_component_running();
905 return all_component_running();
907 return ptc_running(component_reference
);
911 boolean
TTCN_Runtime::component_alive(component component_reference
)
913 if (in_controlpart()) TTCN_error("Alive operation cannot be performed "
914 "in the control part.");
915 switch (component_reference
) {
917 TTCN_error("Alive operation cannot be performed on the null "
918 "component reference.");
920 TTCN_error("Alive operation cannot be performed on the component "
921 "reference of MTC.");
923 TTCN_error("Alive operation cannot be performed on the component "
924 "reference of system.");
926 return any_component_alive();
928 return all_component_alive();
930 return ptc_alive(component_reference
);
934 void TTCN_Runtime::stop_component(component component_reference
)
936 if (in_controlpart()) TTCN_error("Component stop operation cannot be "
937 "performed in the control part.");
939 if (self
== component_reference
) stop_execution();
940 switch (component_reference
) {
942 TTCN_error("Stop operation cannot be performed on the null component "
948 TTCN_error("Stop operation cannot be performed on the component "
949 "reference of system.");
951 TTCN_error("Internal error: 'any component' cannot be stopped.");
953 stop_all_component();
956 stop_ptc(component_reference
);
960 void TTCN_Runtime::stop_execution()
962 if (in_controlpart()) {
963 TTCN_Logger::log_executor_runtime(
964 API::ExecutorRuntime_reason::stopping__control__part__execution
);
966 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
967 "Stopping test component execution.");
969 // the state variable indicates whether the component remains alive
970 // after termination or not
971 if (is_alive
) executor_state
= PTC_STOPPED
;
972 else executor_state
= PTC_EXIT
;
978 void TTCN_Runtime::kill_component(component component_reference
)
980 if (in_controlpart()) TTCN_error("Kill operation cannot be performed in "
981 "the control part.");
983 if (self
== component_reference
) kill_execution();
984 switch (component_reference
) {
986 TTCN_error("Kill operation cannot be performed on the null component "
989 // 'mtc.kill' means exactly the same as 'mtc.stop'
993 TTCN_error("Kill operation cannot be performed on the component "
994 "reference of system.");
996 TTCN_error("Internal error: 'any component' cannot be killed.");
998 kill_all_component();
1001 kill_ptc(component_reference
);
1005 void TTCN_Runtime::kill_execution()
1007 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1008 "Terminating test component execution.");
1009 if (is_ptc()) executor_state
= PTC_EXIT
;
1013 alt_status
TTCN_Runtime::ptc_done(component component_reference
)
1015 if (is_single()) TTCN_error("Done operation on a component reference "
1016 "cannot be performed in single mode.");
1017 if (self
== component_reference
) {
1018 TTCN_warning("Done operation on the component reference of self "
1019 "will never succeed.");
1022 int index
= get_component_status_table_index(component_reference
);
1023 // a successful killed operation on the component reference implies done
1024 if (component_status_table
[index
].killed_status
== ALT_YES
)
1026 switch (component_status_table
[index
].done_status
) {
1028 switch (executor_state
) {
1030 executor_state
= MTC_DONE
;
1033 executor_state
= PTC_DONE
;
1036 TTCN_error("Internal error: Executing done operation in "
1039 TTCN_Communication::send_done_req(component_reference
);
1040 component_status_table
[index
].done_status
= ALT_MAYBE
;
1041 create_done_killed_compref
= component_reference
;
1042 // wait for DONE_ACK
1043 wait_for_state_change();
1044 // always re-evaluate the current alternative using a new snapshot
1052 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__done
,
1053 NULL
, NULL
, component_reference
);
1057 alt_status
TTCN_Runtime::any_component_done()
1059 // the operation is never successful in single mode
1060 if (is_single()) goto failure
;
1061 if (!is_mtc()) TTCN_error("Operation 'any component.done' can only be "
1062 "performed on the MTC.");
1063 // the operation is successful if there is a component reference with a
1064 // successful done or killed operation
1065 for (int i
= 0; i
< component_status_table_size
; i
++) {
1066 if (component_status_table
[i
].done_status
== ALT_YES
||
1067 component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1069 // a successful 'any component.killed' implies 'any component.done'
1070 if (any_component_killed_status
== ALT_YES
) goto success
;
1071 switch (any_component_done_status
) {
1073 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1074 "Executing 'any component.done' in invalid state.");
1075 executor_state
= MTC_DONE
;
1076 TTCN_Communication::send_done_req(ANY_COMPREF
);
1077 any_component_done_status
= ALT_MAYBE
;
1078 create_done_killed_compref
= ANY_COMPREF
;
1079 // wait for DONE_ACK
1080 wait_for_state_change();
1081 // always re-evaluate the current alternative using a new snapshot
1091 TTCN_Logger::log_matching_done(0, 0, 0,
1092 API::MatchingDoneType_reason::any__component__done__successful
);
1095 TTCN_Logger::log_matching_done(0, 0, 0,
1096 API::MatchingDoneType_reason::any__component__done__failed
);
1100 alt_status
TTCN_Runtime::all_component_done()
1102 // the operation is always successful in single mode
1103 if (is_single()) goto success
;
1104 if (!is_mtc()) TTCN_error("Operation 'all component.done' can only be "
1105 "performed on the MTC.");
1106 // a successful 'all component.killed' implies 'all component.done'
1107 if (all_component_killed_status
== ALT_YES
) goto success
;
1108 switch (all_component_done_status
) {
1110 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1111 "Executing 'all component.done' in invalid state.");
1112 executor_state
= MTC_DONE
;
1113 TTCN_Communication::send_done_req(ALL_COMPREF
);
1114 all_component_done_status
= ALT_MAYBE
;
1115 create_done_killed_compref
= ALL_COMPREF
;
1116 // wait for DONE_ACK
1117 wait_for_state_change();
1118 // always re-evaluate the current alternative using a new snapshot
1126 TTCN_Logger::log_matching_done(0, 0, 0,
1127 API::MatchingDoneType_reason::all__component__done__successful
);
1131 alt_status
TTCN_Runtime::ptc_killed(component component_reference
)
1133 if (is_single()) TTCN_error("Killed operation on a component reference "
1134 "cannot be performed in single mode.");
1135 if (self
== component_reference
) {
1136 TTCN_warning("Killed operation on the component reference of self "
1137 "will never succeed.");
1140 int index
= get_component_status_table_index(component_reference
);
1141 switch (component_status_table
[index
].killed_status
) {
1143 switch (executor_state
) {
1145 executor_state
= MTC_KILLED
;
1148 executor_state
= PTC_KILLED
;
1151 TTCN_error("Internal error: Executing killed operation in "
1154 TTCN_Communication::send_killed_req(component_reference
);
1155 component_status_table
[index
].killed_status
= ALT_MAYBE
;
1156 create_done_killed_compref
= component_reference
;
1157 // wait for KILLED_ACK
1158 wait_for_state_change();
1159 // always re-evaluate the current alternative using a new snapshot
1167 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
,
1168 NULL
, NULL
, component_reference
);
1172 alt_status
TTCN_Runtime::any_component_killed()
1174 // the operation is never successful in single mode
1175 if (is_single()) goto failure
;
1176 if (!is_mtc()) TTCN_error("Operation 'any component.killed' can only be "
1177 "performed on the MTC.");
1178 // the operation is successful if there is a component reference with a
1179 // successful killed operation
1180 for (int i
= 0; i
< component_status_table_size
; i
++) {
1181 if (component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1183 switch (any_component_killed_status
) {
1185 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1186 "Executing 'any component.killed' in invalid state.");
1187 executor_state
= MTC_KILLED
;
1188 TTCN_Communication::send_killed_req(ANY_COMPREF
);
1189 any_component_killed_status
= ALT_MAYBE
;
1190 create_done_killed_compref
= ANY_COMPREF
;
1191 // wait for KILLED_ACK
1192 wait_for_state_change();
1193 // always re-evaluate the current alternative using a new snapshot
1203 TTCN_Logger::log_matching_done(0, 0, 0,
1204 API::MatchingDoneType_reason::any__component__killed__successful
);
1207 TTCN_Logger::log_matching_done(0, 0, 0,
1208 API::MatchingDoneType_reason::any__component__killed__failed
);
1212 alt_status
TTCN_Runtime::all_component_killed()
1214 // the operation is always successful in single mode
1215 if (is_single()) goto success
;
1216 if (!is_mtc()) TTCN_error("Operation 'all component.killed' can only be "
1217 "performed on the MTC.");
1218 switch (all_component_killed_status
) {
1220 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1221 "Executing 'all component.killed' in invalid state.");
1222 executor_state
= MTC_KILLED
;
1223 TTCN_Communication::send_killed_req(ALL_COMPREF
);
1224 all_component_killed_status
= ALT_MAYBE
;
1225 create_done_killed_compref
= ALL_COMPREF
;
1226 // wait for KILLED_ACK
1227 wait_for_state_change();
1228 // always re-evaluate the current alternative using a new snapshot
1236 TTCN_Logger::log_matching_done(0, 0, 0,
1237 API::MatchingDoneType_reason::all__component__killed__successful
);
1241 boolean
TTCN_Runtime::ptc_running(component component_reference
)
1243 if (is_single()) TTCN_error("Running operation on a component reference "
1244 "cannot be performed in single mode.");
1245 // the answer is always true if the operation refers to self
1246 if (self
== component_reference
) {
1247 TTCN_warning("Running operation on the component reference of self "
1248 "always returns true.");
1251 // look into the component status tables
1252 if (in_component_status_table(component_reference
)) {
1253 int index
= get_component_status_table_index(component_reference
);
1254 // the answer is false if a successful done or killed operation was
1255 // performed on the component reference
1256 if (component_status_table
[index
].done_status
== ALT_YES
||
1257 component_status_table
[index
].killed_status
== ALT_YES
)
1260 // status flags all_component_done or all_component_killed cannot be used
1261 // because the component reference might be invalid (e.g. stale)
1263 // the decision cannot be made locally, MC must be asked
1264 switch (executor_state
) {
1266 executor_state
= MTC_RUNNING
;
1269 executor_state
= PTC_RUNNING
;
1272 TTCN_error("Internal error: Executing component running operation "
1273 "in invalid state.");
1275 TTCN_Communication::send_is_running(component_reference
);
1277 wait_for_state_change();
1278 return running_alive_result
;
1281 boolean
TTCN_Runtime::any_component_running()
1283 // the answer is always false in single mode
1284 if (is_single()) return FALSE
;
1285 if (!is_mtc()) TTCN_error("Operation 'any component.running' can only be "
1286 "performed on the MTC.");
1287 // the answer is false if 'all component.done' or 'all component.killed'
1288 // operation was successful
1289 if (all_component_done_status
== ALT_YES
||
1290 all_component_killed_status
== ALT_YES
) return FALSE
;
1291 // the decision cannot be made locally, MC must be asked
1292 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1293 "Executing 'any component.running' in invalid state.");
1294 TTCN_Communication::send_is_running(ANY_COMPREF
);
1295 executor_state
= MTC_RUNNING
;
1297 wait_for_state_change();
1298 // update the status of 'all component.done' in case of negative answer
1299 if (!running_alive_result
) all_component_done_status
= ALT_YES
;
1300 return running_alive_result
;
1303 boolean
TTCN_Runtime::all_component_running()
1305 // the answer is always true in single mode
1306 if (is_single()) return TRUE
;
1307 if (!is_mtc()) TTCN_error("Operation 'all component.running' can only be "
1308 "performed on the MTC.");
1309 // return true if no PTCs exist
1310 if (any_component_done_status
== ALT_NO
) return TRUE
;
1311 // the done and killed status flags cannot be used since the components
1312 // that were explicitly stopped or killed must be ignored
1314 // the decision cannot be made locally, MC must be asked
1315 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1316 "Executing 'all component.running' in invalid state.");
1317 TTCN_Communication::send_is_running(ALL_COMPREF
);
1318 executor_state
= MTC_RUNNING
;
1320 wait_for_state_change();
1321 return running_alive_result
;
1324 boolean
TTCN_Runtime::ptc_alive(component component_reference
)
1326 if (is_single()) TTCN_error("Alive operation on a component reference "
1327 "cannot be performed in single mode.");
1328 // the answer is always true if the operation refers to self
1329 if (self
== component_reference
) {
1330 TTCN_warning("Alive operation on the component reference of self "
1331 "always returns true.");
1334 // the answer is false if a successful killed operation was performed
1335 // on the component reference
1336 if (in_component_status_table(component_reference
) &&
1337 get_killed_status(component_reference
) == ALT_YES
) return FALSE
;
1338 // status flag of 'all component.killed' cannot be used because the
1339 // component reference might be invalid (e.g. stale)
1341 // the decision cannot be made locally, MC must be asked
1342 switch (executor_state
) {
1344 executor_state
= MTC_ALIVE
;
1347 executor_state
= PTC_ALIVE
;
1350 TTCN_error("Internal error: Executing component running operation "
1351 "in invalid state.");
1353 TTCN_Communication::send_is_alive(component_reference
);
1355 wait_for_state_change();
1356 return running_alive_result
;
1359 boolean
TTCN_Runtime::any_component_alive()
1361 // the answer is always false in single mode
1362 if (is_single()) return FALSE
;
1363 if (!is_mtc()) TTCN_error("Operation 'any component.alive' can only be "
1364 "performed on the MTC.");
1365 // the answer is false if 'all component.killed' operation was successful
1366 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1367 // the decision cannot be made locally, MC must be asked
1368 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1369 "Executing 'any component.alive' in invalid state.");
1370 TTCN_Communication::send_is_alive(ANY_COMPREF
);
1371 executor_state
= MTC_ALIVE
;
1373 wait_for_state_change();
1374 // update the status of 'all component.killed' in case of negative answer
1375 if (!running_alive_result
) all_component_killed_status
= ALT_YES
;
1376 return running_alive_result
;
1379 boolean
TTCN_Runtime::all_component_alive()
1381 // the answer is always true in single mode
1382 if (is_single()) return TRUE
;
1383 if (!is_mtc()) TTCN_error("Operation 'all component.alive' can only be "
1384 "performed on the MTC.");
1385 // return true if no PTCs exist
1386 if (any_component_killed_status
== ALT_NO
) return TRUE
;
1387 // return false if at least one PTC has been created and
1388 // 'all component.killed' was successful after the create operation
1389 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1390 // the operation is successful if there is a component reference with a
1391 // successful killed operation
1392 for (int i
= 0; i
< component_status_table_size
; i
++) {
1393 if (component_status_table
[i
].killed_status
== ALT_YES
) return FALSE
;
1396 // the decision cannot be made locally, MC must be asked
1397 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1398 "Executing 'all component.alive' in invalid state.");
1399 TTCN_Communication::send_is_alive(ALL_COMPREF
);
1400 executor_state
= MTC_ALIVE
;
1402 wait_for_state_change();
1403 return running_alive_result
;
1406 void TTCN_Runtime::stop_mtc()
1408 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::stopping__mtc
);
1409 TTCN_Communication::send_stop_req(MTC_COMPREF
);
1413 void TTCN_Runtime::stop_ptc(component component_reference
)
1415 if (is_single()) TTCN_error("Stop operation on a component reference "
1416 "cannot be performed in single mode.");
1417 // do nothing if a successful done or killed operation was performed on
1418 // the component reference
1419 if (in_component_status_table(component_reference
)) {
1420 int index
= get_component_status_table_index(component_reference
);
1421 if (component_status_table
[index
].done_status
== ALT_YES
||
1422 component_status_table
[index
].killed_status
== ALT_YES
)
1425 // status flags all_component_done or all_component_killed cannot be used
1426 // because the component reference might be invalid (e.g. stale)
1428 // MC must be asked to stop the PTC
1429 switch (executor_state
) {
1431 executor_state
= MTC_STOP
;
1434 executor_state
= PTC_STOP
;
1437 TTCN_error("Internal error: Executing component stop operation "
1438 "in invalid state.");
1440 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1441 "Stopping PTC with component reference %d.", component_reference
);
1442 TTCN_Communication::send_stop_req(component_reference
);
1443 // wait for STOP_ACK
1444 wait_for_state_change();
1445 // done status of the PTC cannot be updated because its return type and
1446 // return value is unknown
1447 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__stopped
,
1448 NULL
, NULL
, component_reference
);
1451 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1452 "PTC with component reference %d is not running. "
1453 "Stop operation had no effect.", component_reference
);
1456 void TTCN_Runtime::stop_all_component()
1458 // do nothing in single mode
1459 if (is_single()) goto ignore
;
1460 if (!is_mtc()) TTCN_error("Operation 'all component.stop' can only be "
1461 "performed on the MTC.");
1462 // do nothing if 'all component.done' or 'all component.killed'
1464 if (all_component_done_status
== ALT_YES
||
1465 all_component_killed_status
== ALT_YES
) goto ignore
;
1466 // a request must be sent to MC
1467 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1468 "Executing 'all component.stop' in invalid state.");
1469 executor_state
= MTC_STOP
;
1470 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Stopping all components.");
1471 TTCN_Communication::send_stop_req(ALL_COMPREF
);
1472 // wait for STOP_ACK
1473 wait_for_state_change();
1474 // 'all component.done' will be successful later
1475 all_component_done_status
= ALT_YES
;
1476 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__stopped
);
1479 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "No PTCs are running. "
1480 "Operation 'all component.stop' had no effect.");
1483 void TTCN_Runtime::kill_ptc(component component_reference
)
1485 if (is_single()) TTCN_error("Kill operation on a component reference "
1486 "cannot be performed in single mode.");
1487 // do nothing if a successful killed operation was performed on
1488 // the component reference
1489 if (in_component_status_table(component_reference
) &&
1490 get_killed_status(component_reference
) == ALT_YES
) goto ignore
;
1491 // status flags all_component_killed cannot be used because the component
1492 // reference might be invalid (e.g. stale)
1494 // MC must be asked to kill the PTC
1495 switch (executor_state
) {
1497 executor_state
= MTC_KILL
;
1500 executor_state
= PTC_KILL
;
1503 TTCN_error("Internal error: Executing kill operation in invalid "
1506 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1507 "Killing PTC with component reference %d.", component_reference
);
1508 TTCN_Communication::send_kill_req(component_reference
);
1509 // wait for KILL_ACK
1510 wait_for_state_change();
1511 // updating the killed status of the PTC
1513 int index
= get_component_status_table_index(component_reference
);
1514 component_status_table
[index
].killed_status
= ALT_YES
;
1516 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
, NULL
, NULL
,
1517 component_reference
);
1520 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1521 "PTC with component reference %d is not alive anymore. "
1522 "Kill operation had no effect.", component_reference
);
1525 void TTCN_Runtime::kill_all_component()
1527 // do nothing in single mode
1528 if (is_single()) goto ignore
;
1529 if (!is_mtc()) TTCN_error("Operation 'all component.kill' can only be "
1530 "performed on the MTC.");
1531 // do nothing if 'all component.killed' was successful
1532 if (all_component_killed_status
== ALT_YES
) goto ignore
;
1533 // a request must be sent to MC
1534 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1535 "Executing 'all component.kill' in invalid state.");
1536 executor_state
= MTC_KILL
;
1537 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Killing all components.");
1538 TTCN_Communication::send_kill_req(ALL_COMPREF
);
1539 // wait for KILL_ACK
1540 wait_for_state_change();
1541 // 'all component.done' and 'all component.killed' will be successful later
1542 all_component_done_status
= ALT_YES
;
1543 all_component_killed_status
= ALT_YES
;
1544 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__killed
);
1547 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1548 "There are no alive PTCs. Operation 'all component.kill' had no effect.");
1551 void TTCN_Runtime::check_port_name(const char *port_name
,
1552 const char *operation_name
, const char *which_argument
)
1554 if (port_name
== NULL
)
1555 TTCN_error("Internal error: The port name in the %s argument of %s "
1556 "operation is a NULL pointer.", which_argument
, operation_name
);
1557 if (port_name
[0] == '\0')
1558 TTCN_error("Internal error: The %s argument of %s operation contains "
1559 "an empty string as port name.", which_argument
, operation_name
);
1560 /** \todo check whether port_name contains a valid TTCN-3 identifier
1561 * (and array index) */
1564 void TTCN_Runtime::connect_port(
1565 const COMPONENT
& src_compref
, const char *src_port
,
1566 const COMPONENT
& dst_compref
, const char *dst_port
)
1568 check_port_name(src_port
, "connect", "first");
1569 check_port_name(dst_port
, "connect", "second");
1571 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1572 TTCN_Logger::log_event_str("Connecting ports ");
1573 COMPONENT::log_component_reference(src_compref
);
1574 TTCN_Logger::log_event(":%s and ", src_port
);
1575 COMPONENT::log_component_reference(dst_compref
);
1576 TTCN_Logger::log_event(":%s.", dst_port
);
1577 TTCN_Logger::end_event();
1579 if (!src_compref
.is_bound()) TTCN_error("The first argument of connect "
1580 "operation contains an unbound component reference.");
1581 component src_component
= src_compref
;
1582 switch (src_component
) {
1584 TTCN_error("The first argument of connect operation contains the "
1585 "null component reference.");
1586 case SYSTEM_COMPREF
:
1587 TTCN_error("The first argument of connect operation refers to a "
1592 if (!dst_compref
.is_bound()) TTCN_error("The second argument of connect "
1593 "operation contains an unbound component reference.");
1594 component dst_component
= dst_compref
;
1595 switch (dst_component
) {
1597 TTCN_error("The second argument of connect operation contains the "
1598 "null component reference.");
1599 case SYSTEM_COMPREF
:
1600 TTCN_error("The second argument of connect operation refers to a "
1606 switch (executor_state
) {
1607 case SINGLE_TESTCASE
:
1608 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1609 TTCN_error("Both endpoints of connect operation must refer to "
1610 "ports of mtc in single mode.");
1611 PORT::make_local_connection(src_port
, dst_port
);
1614 TTCN_Communication::send_connect_req(src_component
, src_port
,
1615 dst_component
, dst_port
);
1616 executor_state
= MTC_CONNECT
;
1617 wait_for_state_change();
1620 TTCN_Communication::send_connect_req(src_component
, src_port
,
1621 dst_component
, dst_port
);
1622 executor_state
= PTC_CONNECT
;
1623 wait_for_state_change();
1626 if (in_controlpart()) {
1627 TTCN_error("Connect operation cannot be performed in the "
1630 TTCN_error("Internal error: Executing connect operation "
1631 "in invalid state.");
1635 TTCN_Logger::log_portconnmap(API::ParPort_operation::connect__
,
1636 src_compref
, src_port
, dst_compref
, dst_port
);
1639 void TTCN_Runtime::disconnect_port(
1640 const COMPONENT
& src_compref
, const char *src_port
,
1641 const COMPONENT
& dst_compref
, const char *dst_port
)
1643 check_port_name(src_port
, "disconnect", "first");
1644 check_port_name(dst_port
, "disconnect", "second");
1646 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1647 TTCN_Logger::log_event_str("Disconnecting ports ");
1648 COMPONENT::log_component_reference(src_compref
);
1649 TTCN_Logger::log_event(":%s and ", src_port
);
1650 COMPONENT::log_component_reference(dst_compref
);
1651 TTCN_Logger::log_event(":%s.", dst_port
);
1652 TTCN_Logger::end_event();
1654 if (!src_compref
.is_bound()) TTCN_error("The first argument of disconnect "
1655 "operation contains an unbound component reference.");
1656 component src_component
= src_compref
;
1657 switch (src_component
) {
1659 TTCN_error("The first argument of disconnect operation contains the "
1660 "null component reference.");
1661 case SYSTEM_COMPREF
:
1662 TTCN_error("The first argument of disconnect operation refers to a "
1667 if (!dst_compref
.is_bound()) TTCN_error("The second argument of disconnect "
1668 "operation contains an unbound component reference.");
1669 component dst_component
= dst_compref
;
1670 switch (dst_component
) {
1672 TTCN_error("The second argument of disconnect operation contains the "
1673 "null component reference.");
1674 case SYSTEM_COMPREF
:
1675 TTCN_error("The second argument of disconnect operation refers to a "
1681 switch (executor_state
) {
1682 case SINGLE_TESTCASE
:
1683 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1684 TTCN_error("Both endpoints of disconnect operation must refer to "
1685 "ports of mtc in single mode.");
1686 PORT::terminate_local_connection(src_port
, dst_port
);
1689 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1690 dst_component
, dst_port
);
1691 executor_state
= MTC_DISCONNECT
;
1692 wait_for_state_change();
1695 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1696 dst_component
, dst_port
);
1697 executor_state
= PTC_DISCONNECT
;
1698 wait_for_state_change();
1701 if (in_controlpart()) {
1702 TTCN_error("Disonnect operation cannot be performed in the "
1705 TTCN_error("Internal error: Executing disconnect operation "
1706 "in invalid state.");
1710 TTCN_Logger::log_portconnmap(API::ParPort_operation::disconnect__
,
1711 src_compref
, src_port
, dst_compref
, dst_port
);
1714 void TTCN_Runtime::map_port(
1715 const COMPONENT
& src_compref
, const char *src_port
,
1716 const COMPONENT
& dst_compref
, const char *dst_port
)
1718 check_port_name(src_port
, "map", "first");
1719 check_port_name(dst_port
, "map", "second");
1721 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1722 TTCN_Logger::log_event_str("Mapping port ");
1723 COMPONENT::log_component_reference(src_compref
);
1724 TTCN_Logger::log_event(":%s to ", src_port
);
1725 COMPONENT::log_component_reference(dst_compref
);
1726 TTCN_Logger::log_event(":%s.", dst_port
);
1727 TTCN_Logger::end_event();
1729 if (!src_compref
.is_bound()) TTCN_error("The first argument of map "
1730 "operation contains an unbound component reference.");
1731 component src_component
= src_compref
;
1732 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1733 "map operation contains the null component reference.");
1734 if (!dst_compref
.is_bound()) TTCN_error("The second argument of map "
1735 "operation contains an unbound component reference.");
1736 component dst_component
= dst_compref
;
1737 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1738 "map operation contains the null component reference.");
1740 component comp_reference
;
1741 const char *comp_port
, *system_port
;
1743 if (src_component
== SYSTEM_COMPREF
) {
1744 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1745 "map operation refer to system ports.");
1746 comp_reference
= dst_component
;
1747 comp_port
= dst_port
;
1748 system_port
= src_port
;
1749 } else if (dst_component
== SYSTEM_COMPREF
) {
1750 comp_reference
= src_component
;
1751 comp_port
= src_port
;
1752 system_port
= dst_port
;
1754 TTCN_error("Both arguments of map operation refer to test component "
1756 // to avoid warnings
1760 switch (executor_state
) {
1761 case SINGLE_TESTCASE
:
1762 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1763 "can be mapped in single mode.");
1764 PORT::map_port(comp_port
, system_port
);
1767 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1769 executor_state
= MTC_MAP
;
1770 wait_for_state_change();
1773 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1775 executor_state
= PTC_MAP
;
1776 wait_for_state_change();
1779 if (in_controlpart()) {
1780 TTCN_error("Map operation cannot be performed in the "
1783 TTCN_error("Internal error: Executing map operation "
1784 "in invalid state.");
1788 TTCN_Logger::log_portconnmap(API::ParPort_operation::map__
,
1789 src_compref
, src_port
, dst_compref
, dst_port
);
1792 void TTCN_Runtime::unmap_port(
1793 const COMPONENT
& src_compref
, const char *src_port
,
1794 const COMPONENT
& dst_compref
, const char *dst_port
)
1796 check_port_name(src_port
, "unmap", "first");
1797 check_port_name(dst_port
, "unmap", "second");
1799 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1800 TTCN_Logger::log_event_str("Unmapping port ");
1801 COMPONENT::log_component_reference(src_compref
);
1802 TTCN_Logger::log_event(":%s from ", src_port
);
1803 COMPONENT::log_component_reference(dst_compref
);
1804 TTCN_Logger::log_event(":%s.", dst_port
);
1805 TTCN_Logger::end_event();
1807 if (!src_compref
.is_bound()) TTCN_error("The first argument of unmap "
1808 "operation contains an unbound component reference.");
1809 component src_component
= src_compref
;
1810 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1811 "unmap operation contains the null component reference.");
1812 if (!dst_compref
.is_bound()) TTCN_error("The second argument of unmap "
1813 "operation contains an unbound component reference.");
1814 component dst_component
= dst_compref
;
1815 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1816 "unmap operation contains the null component reference.");
1818 component comp_reference
;
1819 const char *comp_port
, *system_port
;
1821 if (src_component
== SYSTEM_COMPREF
) {
1822 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1823 "unmap operation refer to system ports.");
1824 comp_reference
= dst_component
;
1825 comp_port
= dst_port
;
1826 system_port
= src_port
;
1827 } else if (dst_component
== SYSTEM_COMPREF
) {
1828 comp_reference
= src_component
;
1829 comp_port
= src_port
;
1830 system_port
= dst_port
;
1832 TTCN_error("Both arguments of unmap operation refer to test component "
1834 // to avoid warnings
1838 switch (executor_state
) {
1839 case SINGLE_TESTCASE
:
1840 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1841 "can be unmapped in single mode.");
1842 PORT::unmap_port(comp_port
, system_port
);
1845 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1847 executor_state
= MTC_UNMAP
;
1848 wait_for_state_change();
1851 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1853 executor_state
= PTC_UNMAP
;
1854 wait_for_state_change();
1857 if (in_controlpart()) {
1858 TTCN_error("Unmap operation cannot be performed in the "
1861 TTCN_error("Internal error: Executing unmap operation "
1862 "in invalid state.");
1866 TTCN_Logger::log_portconnmap(API::ParPort_operation::unmap__
,
1867 src_compref
, src_port
, dst_compref
, dst_port
);
1870 void TTCN_Runtime::begin_controlpart(const char *module_name
)
1872 control_module_name
= module_name
;
1873 execute_command(begin_controlpart_command
, module_name
);
1874 TTCN_Logger::log_controlpart_start_stop(module_name
, 0);
1877 void TTCN_Runtime::end_controlpart()
1879 TTCN_Default::deactivate_all();
1880 TTCN_Default::reset_counter();
1882 TTCN_Logger::log_controlpart_start_stop(control_module_name
, 1);
1883 execute_command(end_controlpart_command
, control_module_name
);
1884 control_module_name
= NULL
;
1887 void TTCN_Runtime::check_begin_testcase(boolean has_timer
, double timer_value
)
1889 if (!in_controlpart()) {
1890 if (is_single() || is_mtc()) TTCN_error("Test case cannot be executed "
1891 "while another one (%s.%s) is running.", testcase_name
.module_name
,
1892 testcase_name
.definition_name
);
1893 else if (is_ptc()) TTCN_error("Test case cannot be executed on a PTC.");
1894 else TTCN_error("Internal error: Executing a test case in an invalid "
1897 if (has_timer
&& timer_value
< 0.0) TTCN_error("The test case supervisor "
1898 "timer has negative duration (%g s).", timer_value
);
1901 void TTCN_Runtime::begin_testcase(
1902 const char *par_module_name
, const char *par_testcase_name
,
1903 const char *mtc_comptype_module
, const char *mtc_comptype_name
,
1904 const char *system_comptype_module
, const char *system_comptype_name
,
1905 boolean has_timer
, double timer_value
)
1907 switch (executor_state
) {
1908 case SINGLE_CONTROLPART
:
1909 executor_state
= SINGLE_TESTCASE
;
1911 case MTC_CONTROLPART
:
1912 TTCN_Communication::send_testcase_started(par_module_name
,
1913 par_testcase_name
, mtc_comptype_module
, mtc_comptype_name
,
1914 system_comptype_module
, system_comptype_name
);
1915 executor_state
= MTC_TESTCASE
;
1918 TTCN_error("Internal error: Executing a test case in an invalid "
1921 TIMER::save_control_timers();
1922 TTCN_Default::save_control_defaults();
1923 set_testcase_name(par_module_name
, par_testcase_name
);
1924 char *command_arguments
= mprintf("%s.%s", testcase_name
.module_name
,
1925 testcase_name
.definition_name
);
1926 execute_command(begin_testcase_command
, command_arguments
);
1927 Free(command_arguments
);
1928 TTCN_Logger::log_testcase_started(testcase_name
);
1929 if (has_timer
) testcase_timer
.start(timer_value
);
1930 set_component_type(mtc_comptype_module
, mtc_comptype_name
);
1931 initialize_component_type();
1932 // at the beginning of the testcase no PTCs exist
1933 any_component_done_status
= ALT_NO
;
1934 all_component_done_status
= ALT_YES
;
1935 any_component_killed_status
= ALT_NO
;
1936 all_component_killed_status
= ALT_YES
;
1939 verdicttype
TTCN_Runtime::end_testcase()
1941 switch (executor_state
) {
1951 case MTC_DISCONNECT
:
1954 executor_state
= MTC_TESTCASE
;
1957 case SINGLE_TESTCASE
:
1958 disable_interrupt_handler();
1961 TTCN_error("Internal error: Ending a testcase in an invalid state.");
1963 testcase_timer
.stop();
1964 terminate_component_type();
1965 if (executor_state
== MTC_TESTCASE
) {
1966 TTCN_Logger::log_executor_runtime(
1967 API::ExecutorRuntime_reason::waiting__for__ptcs__to__finish
);
1968 TTCN_Communication::send_testcase_finished(local_verdict
, verdict_reason
);
1969 executor_state
= MTC_TERMINATING_TESTCASE
;
1970 wait_for_state_change();
1971 } else if (executor_state
== SINGLE_TESTCASE
) {
1972 executor_state
= SINGLE_CONTROLPART
;
1973 enable_interrupt_handler();
1975 TTCN_Logger::log_testcase_finished(testcase_name
, local_verdict
,
1977 verdict_count
[local_verdict
]++;
1978 // testcase name should come first for backward compatibility
1979 char *command_arguments
= mprintf("%s.%s %s",
1980 testcase_name
.module_name
, testcase_name
.definition_name
,
1981 verdict_name
[local_verdict
]);
1982 execute_command(end_testcase_command
, command_arguments
);
1983 Free(command_arguments
);
1984 clear_qualified_name(testcase_name
);
1985 // clean up component status caches
1986 clear_component_status_table();
1987 any_component_done_status
= ALT_UNCHECKED
;
1988 all_component_done_status
= ALT_UNCHECKED
;
1989 any_component_killed_status
= ALT_UNCHECKED
;
1990 all_component_killed_status
= ALT_UNCHECKED
;
1991 // restore the control part timers and defaults
1992 TTCN_Default::restore_control_defaults();
1993 TIMER::restore_control_timers();
1994 if (executor_state
== MTC_PAUSED
) {
1995 TTCN_Logger::log_executor_runtime(
1996 API::ExecutorRuntime_reason::user__paused__waiting__to__resume
);
1997 wait_for_state_change();
1998 if (executor_state
!= MTC_TERMINATING_EXECUTION
)
1999 TTCN_Logger::log_executor_runtime(
2000 API::ExecutorRuntime_reason::resuming__execution
);
2002 if (executor_state
== MTC_TERMINATING_EXECUTION
) {
2003 executor_state
= MTC_CONTROLPART
;
2004 TTCN_Logger::log_executor_runtime(
2005 API::ExecutorRuntime_reason::terminating__execution
);
2008 return local_verdict
;
2011 void TTCN_Runtime::log_verdict_statistics()
2013 unsigned int total_testcases
= verdict_count
[NONE
] + verdict_count
[PASS
] +
2014 verdict_count
[INCONC
] + verdict_count
[FAIL
] + verdict_count
[ERROR
];
2016 verdicttype overall_verdict
;
2017 if (control_error_count
> 0 || verdict_count
[ERROR
] > 0)
2018 overall_verdict
= ERROR
;
2019 else if (verdict_count
[FAIL
] > 0) overall_verdict
= FAIL
;
2020 else if (verdict_count
[INCONC
] > 0) overall_verdict
= INCONC
;
2021 else if (verdict_count
[PASS
] > 0) overall_verdict
= PASS
;
2022 else overall_verdict
= NONE
;
2024 if (total_testcases
> 0) {
2025 TTCN_Logger::log_verdict_statistics(verdict_count
[NONE
], (100.0 * verdict_count
[NONE
]) / total_testcases
,
2026 verdict_count
[PASS
], (100.0 * verdict_count
[PASS
]) / total_testcases
,
2027 verdict_count
[INCONC
], (100.0 * verdict_count
[INCONC
]) / total_testcases
,
2028 verdict_count
[FAIL
], (100.0 * verdict_count
[FAIL
]) / total_testcases
,
2029 verdict_count
[ERROR
], (100.0 * verdict_count
[ERROR
]) / total_testcases
);
2031 TTCN_Logger::log_verdict_statistics(0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0);
2034 if (control_error_count
> 0) {
2035 TTCN_Logger::log_controlpart_errors(control_error_count
);
2038 TTCN_Logger::log(TTCN_Logger::STATISTICS_VERDICT
, "Test execution summary: "
2039 "%u test case%s executed. Overall verdict: %s", total_testcases
,
2040 total_testcases
> 1 ? "s were" : " was", verdict_name
[overall_verdict
]);
2042 verdict_count
[NONE
] = 0;
2043 verdict_count
[PASS
] = 0;
2044 verdict_count
[INCONC
] = 0;
2045 verdict_count
[FAIL
] = 0;
2046 verdict_count
[ERROR
] = 0;
2047 control_error_count
= 0;
2050 void TTCN_Runtime::begin_action()
2052 TTCN_Logger::begin_event(TTCN_Logger::ACTION_UNQUALIFIED
);
2053 TTCN_Logger::log_event_str("Action: ");
2056 void TTCN_Runtime::end_action()
2058 TTCN_Logger::end_event();
2061 void TTCN_Runtime::setverdict(verdicttype new_value
, const char* reason
)
2063 if (verdict_enabled()) {
2064 if (new_value
== ERROR
)
2065 TTCN_error("Error verdict cannot be set explicitly.");
2066 setverdict_internal(new_value
, reason
);
2067 } else if (in_controlpart()) {
2068 TTCN_error("Verdict cannot be set in the control part.");
2070 TTCN_error("Internal error: Setting the verdict in invalid state.");
2074 void TTCN_Runtime::setverdict(const VERDICTTYPE
& new_value
, const char* reason
)
2076 if (!new_value
.is_bound()) TTCN_error("The argument of setverdict "
2077 "operation is an unbound verdict value.");
2078 setverdict((verdicttype
)new_value
, reason
);
2081 void TTCN_Runtime::set_error_verdict()
2083 if (verdict_enabled()) setverdict_internal(ERROR
);
2084 else if (is_single() || is_mtc()) control_error_count
++;
2087 verdicttype
TTCN_Runtime::getverdict()
2089 if (verdict_enabled())
2090 TTCN_Logger::log_getverdict(local_verdict
);
2091 else if (in_controlpart()) TTCN_error("Getverdict operation cannot be "
2092 "performed in the control part.");
2093 else TTCN_error("Internal error: Performing getverdict operation in "
2095 return local_verdict
;
2098 void TTCN_Runtime::setverdict_internal(verdicttype new_value
,
2101 if (new_value
< NONE
|| new_value
> ERROR
)
2102 TTCN_error("Internal error: setting an invalid verdict value (%d).",
2104 verdicttype old_verdict
= local_verdict
;
2105 if (local_verdict
< new_value
) {
2106 verdict_reason
= reason
;
2107 local_verdict
= new_value
;
2108 if (reason
== NULL
|| reason
[0] == '\0')
2109 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2110 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2111 } else if (local_verdict
== new_value
) {
2112 if (reason
== NULL
|| reason
[0] == '\0')
2113 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2114 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2118 void TTCN_Runtime::set_begin_controlpart_command(const char *new_command
)
2120 Free(begin_controlpart_command
);
2121 begin_controlpart_command
= shell_escape(new_command
);
2124 void TTCN_Runtime::set_end_controlpart_command(const char *new_command
)
2126 Free(end_controlpart_command
);
2127 end_controlpart_command
= shell_escape(new_command
);
2130 void TTCN_Runtime::set_begin_testcase_command(const char *new_command
)
2132 Free(begin_testcase_command
);
2133 begin_testcase_command
= shell_escape(new_command
);
2136 void TTCN_Runtime::set_end_testcase_command(const char *new_command
)
2138 Free(end_testcase_command
);
2139 end_testcase_command
= shell_escape(new_command
);
2142 void TTCN_Runtime::clear_external_commands()
2144 Free(begin_controlpart_command
);
2145 begin_controlpart_command
= NULL
;
2146 Free(end_controlpart_command
);
2147 end_controlpart_command
= NULL
;
2148 Free(begin_testcase_command
);
2149 begin_testcase_command
= NULL
;
2150 Free(end_testcase_command
);
2151 end_testcase_command
= NULL
;
2154 char *TTCN_Runtime::shell_escape(const char *command_str
)
2156 if (command_str
== NULL
|| command_str
[0] == '\0') return NULL
;
2157 boolean has_special_char
= FALSE
;
2158 for (int i
= 0; !has_special_char
&& command_str
[i
] != '\0'; i
++) {
2159 switch (command_str
[i
]) {
2181 // special characters interpreted by the shell except '
2182 has_special_char
= TRUE
;
2185 // non-printable characters also need special handling
2186 if (!isprint(command_str
[i
])) has_special_char
= TRUE
;
2189 char *ret_val
= memptystr();
2190 // indicates whether we are in an unclosed ' string
2191 boolean in_apostrophes
= FALSE
;
2192 for (int i
= 0; command_str
[i
] != '\0'; i
++) {
2193 if (command_str
[i
] == '\'') {
2194 if (in_apostrophes
) {
2195 // close the open literal
2196 ret_val
= mputc(ret_val
, '\'');
2197 in_apostrophes
= FALSE
;
2199 // substitute with \'
2200 ret_val
= mputstr(ret_val
, "\\'");
2202 if (has_special_char
&& !in_apostrophes
) {
2204 ret_val
= mputc(ret_val
, '\'');
2205 in_apostrophes
= TRUE
;
2207 // append the single character
2208 ret_val
= mputc(ret_val
, command_str
[i
]);
2211 // close the open literal
2212 if (in_apostrophes
) ret_val
= mputc(ret_val
, '\'');
2216 void TTCN_Runtime::execute_command(const char *command_name
,
2217 const char *argument_string
)
2219 if (command_name
!= NULL
) {
2220 char *command_string
= mprintf("%s %s", command_name
, argument_string
);
2222 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_START
, command_string
);
2223 int return_status
= system(command_string
);
2224 if (return_status
== -1) TTCN_error("Execution of external "
2225 "command `%s' failed.", command_string
);
2226 else if (WIFEXITED(return_status
)) {
2227 int exit_status
= WEXITSTATUS(return_status
);
2228 if (exit_status
== EXIT_SUCCESS
)
2229 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_SUCCESS
, command_string
);
2230 else TTCN_warning("External command `%s' returned "
2231 "unsuccessful exit status (%d).", command_string
,
2233 } else if (WIFSIGNALED(return_status
)) {
2234 int signal_number
= WTERMSIG(return_status
);
2235 TTCN_warning("External command `%s' was terminated by signal "
2236 "%d (%s).", command_string
, signal_number
,
2237 get_signal_name(signal_number
));
2239 TTCN_warning("External command `%s' was terminated by an "
2240 "unknown reason (return status: %d).", command_string
,
2244 // to prevent from memory leaks
2245 Free(command_string
);
2248 Free(command_string
);
2252 void TTCN_Runtime::process_create_mtc()
2254 switch (executor_state
) {
2259 TTCN_Communication::send_error("Message CREATE_MTC arrived in invalid "
2264 // let the HC's TTCN-3 Profiler know of the MTC
2265 ttcn3_prof
.add_component(MTC_COMPREF
);
2267 // clean Emergency log buffer before fork, to avoid duplication
2268 TTCN_Logger::ring_buffer_dump(false);
2270 pid_t mtc_pid
= fork();
2273 TTCN_Communication::send_create_nak(MTC_COMPREF
, "system call fork() "
2274 "failed (%s)", strerror(errno
));
2275 failed_process_creation();
2276 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2277 TTCN_Logger::log_event_str("System call fork() failed when creating "
2279 TTCN_Logger::OS_error();
2280 TTCN_Logger::end_event();
2281 } else if (mtc_pid
> 0) {
2282 // fork() was successful, this code runs on the parent process (HC)
2283 TTCN_Logger::log_mtc_created(mtc_pid
);
2284 add_component(MTC_COMPREF
, mtc_pid
);
2285 successful_process_creation();
2287 // fork() was successful, this code runs on the child process (MTC)
2288 // The inherited epoll fd has to be closed first, and then the mc fd
2289 // (The inherited epoll fd shares its database with the parent process.)
2290 Fd_And_Timeout_User::reopenEpollFd();
2291 TTCN_Communication::close_mc_connection();
2293 executor_state
= MTC_INITIAL
;
2297 void TTCN_Runtime::process_create_ptc(component component_reference
,
2298 const char *component_type_module
, const char *component_type_name
,
2299 const char *par_component_name
, boolean par_is_alive
,
2300 const char *current_testcase_module
, const char *current_testcase_name
)
2302 switch (executor_state
) {
2307 TTCN_Communication::send_error("Message CREATE_PTC arrived in invalid "
2312 // let the HC's TTCN-3 Profiler know of this new PTC
2313 ttcn3_prof
.add_component(component_reference
);
2315 // clean Emergency log buffer before fork, to avoid duplication
2316 TTCN_Logger::ring_buffer_dump(false);
2318 pid_t ptc_pid
= fork();
2321 TTCN_Communication::send_create_nak(component_reference
, "system call "
2322 "fork() failed (%s)", strerror(errno
));
2323 failed_process_creation();
2324 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2325 TTCN_Logger::log_event("System call fork() failed when creating PTC "
2326 "with component reference %d.", component_reference
);
2327 TTCN_Logger::OS_error();
2328 TTCN_Logger::end_event();
2329 } else if (ptc_pid
> 0) {
2330 // fork() was successful, this code runs on the parent process (HC)
2331 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created__pid
,
2332 component_type_module
, component_type_name
, component_reference
,
2333 par_component_name
, current_testcase_name
, ptc_pid
);
2334 add_component(component_reference
, ptc_pid
);
2335 COMPONENT::register_component_name(component_reference
,
2336 par_component_name
);
2337 successful_process_creation();
2339 // fork() was successful, this code runs on the child process (PTC)
2340 // The inherited epoll fd has to be closed first, and then the mc fd
2341 // (The inherited epoll fd shares its database with the parent process.)
2342 Fd_And_Timeout_User::reopenEpollFd();
2343 TTCN_Communication::close_mc_connection();
2344 self
= component_reference
;
2345 set_component_type(component_type_module
, component_type_name
);
2346 set_component_name(par_component_name
);
2347 is_alive
= par_is_alive
;
2348 set_testcase_name(current_testcase_module
, current_testcase_name
);
2349 executor_state
= PTC_INITIAL
;
2353 void TTCN_Runtime::process_create_ack(component new_component
)
2355 switch (executor_state
) {
2357 executor_state
= MTC_TESTCASE
;
2358 case MTC_TERMINATING_TESTCASE
:
2361 executor_state
= PTC_FUNCTION
;
2364 TTCN_error("Internal error: Message CREATE_ACK arrived in invalid "
2367 create_done_killed_compref
= new_component
;
2370 void TTCN_Runtime::process_running(boolean result_value
)
2372 switch (executor_state
) {
2374 executor_state
= MTC_TESTCASE
;
2375 case MTC_TERMINATING_TESTCASE
:
2378 executor_state
= PTC_FUNCTION
;
2381 TTCN_error("Internal error: Message RUNNING arrived in invalid state.");
2383 running_alive_result
= result_value
;
2386 void TTCN_Runtime::process_alive(boolean result_value
)
2388 switch (executor_state
) {
2390 executor_state
= MTC_TESTCASE
;
2391 case MTC_TERMINATING_TESTCASE
:
2394 executor_state
= PTC_FUNCTION
;
2397 TTCN_error("Internal error: Message ALIVE arrived in invalid state.");
2399 running_alive_result
= result_value
;
2402 void TTCN_Runtime::process_done_ack(boolean done_status
,
2403 const char *return_type
, int return_value_len
, const void *return_value
)
2405 switch (executor_state
) {
2407 executor_state
= MTC_TESTCASE
;
2408 case MTC_TERMINATING_TESTCASE
:
2411 executor_state
= PTC_FUNCTION
;
2414 TTCN_error("Internal error: Message DONE_ACK arrived in invalid "
2417 if (done_status
) set_component_done(create_done_killed_compref
,
2418 return_type
, return_value_len
, return_value
);
2419 create_done_killed_compref
= NULL_COMPREF
;
2422 void TTCN_Runtime::process_killed_ack(boolean killed_status
)
2424 switch (executor_state
) {
2426 executor_state
= MTC_TESTCASE
;
2427 case MTC_TERMINATING_TESTCASE
:
2430 executor_state
= PTC_FUNCTION
;
2433 TTCN_error("Internal error: Message KILLED_ACK arrived in invalid "
2436 if (killed_status
) set_component_killed(create_done_killed_compref
);
2437 create_done_killed_compref
= NULL_COMPREF
;
2440 void TTCN_Runtime::process_ptc_verdict(Text_Buf
& text_buf
)
2442 if (executor_state
!= MTC_TERMINATING_TESTCASE
)
2443 TTCN_error("Internal error: Message PTC_VERDICT arrived in invalid state.");
2445 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2446 local_verdict
, (const char *)verdict_reason
,
2447 TitanLoggerApi::FinalVerdictType_choice_notification::setting__final__verdict__of__the__test__case
);
2448 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2449 local_verdict
, (const char *)verdict_reason
);
2450 int n_ptcs
= text_buf
.pull_int().get_val();
2452 for (int i
= 0; i
< n_ptcs
; i
++) {
2453 component ptc_compref
= text_buf
.pull_int().get_val();
2454 char *ptc_name
= text_buf
.pull_string();
2455 verdicttype ptc_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
2456 char *ptc_verdict_reason
= text_buf
.pull_string();
2457 if (ptc_verdict
< NONE
|| ptc_verdict
> ERROR
) {
2459 TTCN_error("Internal error: Invalid PTC verdict was "
2460 "received from MC: %d.", ptc_verdict
);
2462 verdicttype new_verdict
= local_verdict
;
2463 if (ptc_verdict
> local_verdict
) {
2464 new_verdict
= ptc_verdict
;
2465 verdict_reason
= CHARSTRING(ptc_verdict_reason
);
2467 TTCN_Logger::log_final_verdict(true, ptc_verdict
, local_verdict
,
2468 new_verdict
, ptc_verdict_reason
, -1, ptc_compref
, ptc_name
);
2470 delete [] ptc_verdict_reason
;
2471 local_verdict
= new_verdict
;
2474 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2475 local_verdict
, (const char *)verdict_reason
,
2476 TitanLoggerApi::FinalVerdictType_choice_notification::no__ptcs__were__created
);
2479 boolean continue_execution
= (boolean
)text_buf
.pull_int().get_val();
2480 if (continue_execution
) executor_state
= MTC_CONTROLPART
;
2481 else executor_state
= MTC_PAUSED
;
2484 void TTCN_Runtime::process_kill()
2487 TTCN_error("Internal error: Message KILL arrived in invalid state.");
2488 switch (executor_state
) {
2491 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::kill__request__frm__mc
);
2492 // This may affect the final verdict.
2493 terminate_component_type();
2494 // Send a KILLED message so that the value returned by previous behaviour
2495 // function remains active.
2496 TTCN_Communication::send_killed(local_verdict
);
2497 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
2498 local_verdict
, (const char *)verdict_reason
);
2499 executor_state
= PTC_EXIT
;
2503 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2504 "Kill was requested from MC.");
2509 void TTCN_Runtime::process_kill_process(component component_reference
)
2511 if (!is_hc()) TTCN_error("Internal error: Message KILL_PROCESS arrived "
2512 "in invalid state.");
2513 component_process_struct
*comp
=
2514 get_component_by_compref(component_reference
);
2516 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2517 "Killing component with component reference %d, process id: %ld.",
2518 component_reference
, (long)comp
->process_id
);
2519 if (comp
->process_killed
) TTCN_warning("Process with process id %ld "
2520 "has been already killed. Killing it again.",
2521 (long)comp
->process_id
);
2522 if (kill(comp
->process_id
, SIGKILL
)) {
2523 if (errno
== ESRCH
) {
2525 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2526 "Process with process id %ld has already terminated.", (long)comp
->process_id
);
2527 } else TTCN_error("kill() system call failed on process id %ld.",
2528 (long)comp
->process_id
);
2530 comp
->process_killed
= TRUE
;
2532 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2533 "Component with component reference %d does not exist. "
2534 "Request for killing was ignored.", component_reference
);
2538 void TTCN_Runtime::set_component_done(component component_reference
,
2539 const char *return_type
, int return_value_len
,
2540 const void *return_value
)
2542 switch (component_reference
) {
2544 if (is_mtc()) any_component_done_status
= ALT_YES
;
2545 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2546 "ANY_COMPREF): can be used only on MTC.");
2549 if (is_mtc()) all_component_done_status
= ALT_YES
;
2550 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2551 "ALL_COMPREF): can be used only on MTC.");
2555 case SYSTEM_COMPREF
:
2556 TTCN_error("Internal error: TTCN_Runtime::set_component_done: "
2557 "invalid component reference: %d.", component_reference
);
2560 int index
= get_component_status_table_index(component_reference
);
2561 component_status_table
[index
].done_status
= ALT_YES
;
2562 Free(component_status_table
[index
].return_type
);
2563 delete component_status_table
[index
].return_value
;
2564 if (return_type
!= NULL
&& return_type
[0] != '\0') {
2565 component_status_table
[index
].return_type
= mcopystr(return_type
);
2566 component_status_table
[index
].return_value
= new Text_Buf
;
2567 component_status_table
[index
].return_value
->push_raw(
2568 return_value_len
, return_value
);
2570 component_status_table
[index
].return_type
= NULL
;
2571 component_status_table
[index
].return_value
= NULL
;
2577 void TTCN_Runtime::set_component_killed(component component_reference
)
2579 switch (component_reference
) {
2581 if (is_mtc()) any_component_killed_status
= ALT_YES
;
2582 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2583 "ANY_COMPREF): can be used only on MTC.");
2586 if (is_mtc()) all_component_killed_status
= ALT_YES
;
2587 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2588 "ALL_COMPREF): can be used only on MTC.");
2592 case SYSTEM_COMPREF
:
2593 TTCN_error("Internal error: TTCN_Runtime::set_component_killed: "
2594 "invalid component reference: %d.", component_reference
);
2596 component_status_table
[get_component_status_table_index(
2597 component_reference
)].killed_status
= ALT_YES
;
2601 void TTCN_Runtime::cancel_component_done(component component_reference
)
2603 switch (component_reference
) {
2605 if (is_mtc()) any_component_done_status
= ALT_UNCHECKED
;
2606 else TTCN_error("Internal error: TTCN_Runtime::cancel_component_done("
2607 "ANY_COMPREF): can be used only on MTC.");
2612 case SYSTEM_COMPREF
:
2613 TTCN_error("Internal error: TTCN_Runtime::cancel_component_done: "
2614 "invalid component reference: %d.", component_reference
);
2616 if (in_component_status_table(component_reference
)) {
2617 int index
= get_component_status_table_index(component_reference
);
2618 component_status_table
[index
].done_status
= ALT_UNCHECKED
;
2619 Free(component_status_table
[index
].return_type
);
2620 component_status_table
[index
].return_type
= NULL
;
2621 delete component_status_table
[index
].return_value
;
2622 component_status_table
[index
].return_value
= NULL
;
2627 int TTCN_Runtime::get_component_status_table_index(
2628 component component_reference
)
2630 if (component_reference
< FIRST_PTC_COMPREF
) {
2631 TTCN_error("Internal error: TTCN_Runtime::"
2632 "get_component_status_table_index: invalid component reference: "
2633 "%d.", component_reference
);
2635 if (component_status_table_size
== 0) {
2636 // the table is empty
2637 // this will be the first entry
2638 component_status_table
= (component_status_table_struct
*)
2639 Malloc(sizeof(*component_status_table
));
2640 component_status_table
[0].done_status
= ALT_UNCHECKED
;
2641 component_status_table
[0].killed_status
= ALT_UNCHECKED
;
2642 component_status_table
[0].return_type
= NULL
;
2643 component_status_table
[0].return_value
= NULL
;
2644 component_status_table_size
= 1;
2645 component_status_table_offset
= component_reference
;
2647 } else if (component_reference
>= component_status_table_offset
) {
2648 // the table contains at least one entry that is smaller than
2649 // component_reference
2650 int component_index
=
2651 component_reference
- component_status_table_offset
;
2652 if (component_index
>= component_status_table_size
) {
2653 // component_reference is still not in the table
2654 // the table has to be extended at the end
2655 component_status_table
= (component_status_table_struct
*)
2656 Realloc(component_status_table
,
2657 (component_index
+ 1) * sizeof(*component_status_table
));
2658 // initializing the new table entries at the end
2659 for (int i
= component_status_table_size
;
2660 i
<= component_index
; i
++) {
2661 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2662 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2663 component_status_table
[i
].return_type
= NULL
;
2664 component_status_table
[i
].return_value
= NULL
;
2666 component_status_table_size
= component_index
+ 1;
2668 return component_index
;
2670 // component_reference has to be inserted before the existing table
2671 int offset_diff
= component_status_table_offset
- component_reference
;
2672 // offset_diff indicates how many new elements have to be inserted
2673 // before the existing table
2674 int new_size
= component_status_table_size
+ offset_diff
;
2675 component_status_table
= (component_status_table_struct
*)
2676 Realloc(component_status_table
,
2677 new_size
* sizeof(*component_status_table
));
2678 // moving forward the existing table
2679 memmove(component_status_table
+ offset_diff
, component_status_table
,
2680 component_status_table_size
* sizeof(*component_status_table
));
2681 // initializing the first table entries
2682 for (int i
= 0; i
< offset_diff
; i
++) {
2683 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2684 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2685 component_status_table
[i
].return_type
= NULL
;
2686 component_status_table
[i
].return_value
= NULL
;
2688 component_status_table_size
= new_size
;
2689 component_status_table_offset
= component_reference
;
2694 alt_status
TTCN_Runtime::get_killed_status(component component_reference
)
2696 return component_status_table
2697 [get_component_status_table_index(component_reference
)].killed_status
;
2700 boolean
TTCN_Runtime::in_component_status_table(component component_reference
)
2702 return component_reference
>= component_status_table_offset
&&
2703 component_reference
<
2704 component_status_table_size
+ component_status_table_offset
;
2707 void TTCN_Runtime::clear_component_status_table()
2709 for (component i
= 0; i
< component_status_table_size
; i
++) {
2710 Free(component_status_table
[i
].return_type
);
2711 delete component_status_table
[i
].return_value
;
2713 Free(component_status_table
);
2714 component_status_table
= NULL
;
2715 component_status_table_size
= 0;
2716 component_status_table_offset
= FIRST_PTC_COMPREF
;
2719 #define HASHTABLE_SIZE 97
2721 void TTCN_Runtime::initialize_component_process_tables()
2723 components_by_compref
= new component_process_struct
*[HASHTABLE_SIZE
];
2724 components_by_pid
= new component_process_struct
*[HASHTABLE_SIZE
];
2725 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2726 components_by_compref
[i
] = NULL
;
2727 components_by_pid
[i
] = NULL
;
2731 void TTCN_Runtime::add_component(component component_reference
,
2734 if (component_reference
!= MTC_COMPREF
&&
2735 get_component_by_compref(component_reference
) != NULL
)
2736 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2737 "duplicated component reference (%d)", component_reference
);
2738 if (get_component_by_pid(process_id
) != NULL
)
2739 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2740 "duplicated pid (%ld)", (long)process_id
);
2742 component_process_struct
*new_comp
= new component_process_struct
;
2743 new_comp
->component_reference
= component_reference
;
2744 new_comp
->process_id
= process_id
;
2745 new_comp
->process_killed
= FALSE
;
2747 new_comp
->prev_by_compref
= NULL
;
2748 component_process_struct
*& head_by_compref
=
2749 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2750 new_comp
->next_by_compref
= head_by_compref
;
2751 if (head_by_compref
!= NULL
) head_by_compref
->prev_by_compref
= new_comp
;
2752 head_by_compref
= new_comp
;
2754 new_comp
->prev_by_pid
= NULL
;
2755 component_process_struct
*& head_by_pid
=
2756 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2757 new_comp
->next_by_pid
= head_by_pid
;
2758 if (head_by_pid
!= NULL
) head_by_pid
->prev_by_pid
= new_comp
;
2759 head_by_pid
= new_comp
;
2762 void TTCN_Runtime::remove_component(component_process_struct
*comp
)
2764 if (comp
->next_by_compref
!= NULL
)
2765 comp
->next_by_compref
->prev_by_compref
= comp
->prev_by_compref
;
2766 if (comp
->prev_by_compref
!= NULL
)
2767 comp
->prev_by_compref
->next_by_compref
= comp
->next_by_compref
;
2768 else components_by_compref
[comp
->component_reference
% HASHTABLE_SIZE
] =
2769 comp
->next_by_compref
;
2770 if (comp
->next_by_pid
!= NULL
)
2771 comp
->next_by_pid
->prev_by_pid
= comp
->prev_by_pid
;
2772 if (comp
->prev_by_pid
!= NULL
)
2773 comp
->prev_by_pid
->next_by_pid
= comp
->next_by_pid
;
2774 else components_by_pid
[comp
->process_id
% HASHTABLE_SIZE
] =
2779 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_compref(
2780 component component_reference
)
2782 component_process_struct
*iter
=
2783 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2784 while (iter
!= NULL
) {
2785 if (iter
->component_reference
== component_reference
) break;
2786 iter
= iter
->next_by_compref
;
2791 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_pid(
2794 component_process_struct
*iter
=
2795 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2796 while (iter
!= NULL
) {
2797 if (iter
->process_id
== process_id
) break;
2798 iter
= iter
->next_by_pid
;
2803 void TTCN_Runtime::clear_component_process_tables()
2805 if (components_by_compref
== NULL
) return;
2806 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2807 while (components_by_compref
[i
] != NULL
)
2808 remove_component(components_by_compref
[i
]);
2809 while (components_by_pid
[i
] != NULL
)
2810 remove_component(components_by_pid
[i
]);
2812 delete [] components_by_compref
;
2813 components_by_compref
= NULL
;
2814 delete [] components_by_pid
;
2815 components_by_pid
= NULL
;
2818 void TTCN_Runtime::successful_process_creation()
2820 if (is_overloaded()) {
2821 TTCN_Communication::send_hc_ready();
2822 TTCN_Communication::disable_periodic_call();
2823 executor_state
= HC_ACTIVE
;
2827 void TTCN_Runtime::failed_process_creation()
2829 if (executor_state
== HC_ACTIVE
) {
2830 TTCN_Communication::enable_periodic_call();
2831 executor_state
= HC_OVERLOADED
;
2835 void TTCN_Runtime::wait_terminated_processes()
2837 // this function might be called from TCs too while returning from
2838 // TTCN_Communication::process_all_messages_hc() after fork()
2839 if (!is_hc()) return;
2843 struct rusage r_usage
= {{0,0},{0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2845 pid_t child_pid
= waitpid(-1, &statuscode
, WNOHANG
);
2846 getrusage(RUSAGE_CHILDREN
, &r_usage
);
2848 pid_t child_pid
= wait3(&statuscode
, WNOHANG
, &r_usage
);
2850 if (child_pid
<= 0) {
2858 TTCN_error("System call wait3() failed when waiting for "
2859 "terminated test component processes.");
2862 component_process_struct
*comp
= get_component_by_pid(child_pid
);
2865 const char *comp_name
= NULL
;
2866 if (comp
->component_reference
== MTC_COMPREF
) {
2867 reason
= API::ParallelPTC_reason::mtc__finished
;
2870 reason
= API::ParallelPTC_reason::ptc__finished
;
2871 comp_name
= COMPONENT::get_component_name(comp
->component_reference
);
2873 char *rusage
= NULL
;
2875 "user time: %ld.%06ld s, system time: %ld.%06ld s, "
2876 "maximum resident set size: %ld, "
2877 "integral resident set size: %ld, "
2878 "page faults not requiring physical I/O: %ld, "
2879 "page faults requiring physical I/O: %ld, "
2881 "block input operations: %ld, block output operations: %ld, "
2882 "messages sent: %ld, messages received: %ld, "
2883 "signals received: %ld, "
2884 "voluntary context switches: %ld, "
2885 "involuntary context switches: %ld }",
2886 (long)r_usage
.ru_utime
.tv_sec
, r_usage
.ru_utime
.tv_usec
,
2887 (long)r_usage
.ru_stime
.tv_sec
, r_usage
.ru_stime
.tv_usec
,
2888 r_usage
.ru_maxrss
, r_usage
.ru_idrss
,
2889 r_usage
.ru_minflt
, r_usage
.ru_majflt
, r_usage
.ru_nswap
,
2890 r_usage
.ru_inblock
, r_usage
.ru_oublock
,
2891 r_usage
.ru_msgsnd
, r_usage
.ru_msgrcv
, r_usage
.ru_nsignals
,
2892 r_usage
.ru_nvcsw
, r_usage
.ru_nivcsw
);
2893 // There are too many different integer types in the rusage structure.
2894 // Just format them into a string and and pass that to the logger.
2895 TTCN_Logger::log_par_ptc(reason
, NULL
, NULL
,
2896 comp
->component_reference
, comp_name
, rusage
, child_pid
, statuscode
);
2898 remove_component(comp
);
2900 TTCN_warning("wait3() system call returned unknown process id %ld.",
2906 void TTCN_Runtime::check_overload()
2908 if (!is_hc()) TTCN_error("Internal error: TTCN_Runtime::check_overload() "
2909 "can be used on HCs only.");
2910 if (!is_overloaded()) return;
2911 TTCN_Logger::log_executor_runtime(
2912 API::ExecutorRuntime_reason::overload__check
);
2913 pid_t child_pid
= fork();
2914 if (child_pid
< 0) {
2915 // fork failed, the host is still overloaded
2916 TTCN_Logger::log_executor_runtime(
2917 API::ExecutorRuntime_reason::overload__check__fail
);
2918 //TODO TTCN_Logger::OS_error();
2919 if (executor_state
== HC_OVERLOADED_TIMEOUT
) {
2920 // increase the call interval if the function was called because of
2922 TTCN_Communication::increase_call_interval();
2923 executor_state
= HC_OVERLOADED
;
2925 } else if (child_pid
> 0) {
2926 // fork was successful, this code runs on the parent process (HC)
2928 // wait until the dummy child terminates
2929 pid_t result_pid
= waitpid(child_pid
, &statuscode
, 0);
2930 if (result_pid
!= child_pid
) TTCN_error("System call waitpid() "
2931 "returned unexpected status code %ld when waiting for the dummy "
2932 "child process with PID %ld.", (long)result_pid
, (long)child_pid
);
2933 successful_process_creation();
2934 TTCN_Logger::log_executor_runtime(
2935 API::ExecutorRuntime_reason::overloaded__no__more
);
2936 // FIXME pid is not logged; it would need a separate function
2938 // analyze the status code and issue a warning if something strange
2940 if (WIFEXITED(statuscode
)) {
2941 int exitstatus
= WEXITSTATUS(statuscode
);
2942 if (exitstatus
!= EXIT_SUCCESS
) TTCN_warning("Dummy child process "
2943 "with PID %ld returned unsuccessful exit status (%d).",
2944 (long)child_pid
, exitstatus
);
2945 } else if (WIFSIGNALED(statuscode
)) {
2946 int signum
= WTERMSIG(statuscode
);
2947 TTCN_warning("Dummy child process with PID %ld was terminated by "
2948 "signal %d (%s).", (long)child_pid
, signum
,
2949 get_signal_name(signum
));
2951 TTCN_warning("Dummy child process with PID %ld was terminated by "
2952 "an unknown reason (return status: %d).", (long)child_pid
,
2955 // try to clean up some more zombies if possible
2956 wait_terminated_processes();
2958 // fork was successful, this code runs on the dummy child process
2959 // the dummy child process shall exit immediately