1 /******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
20 * Szabo, Janos Zoltan – initial implementation
21 * Zalanyi, Balazs Andor
24 ******************************************************************************/
25 #if defined(LINUX) && ! defined(_GNU_SOURCE)
26 // in order to get the prototype of non-standard strsignal()
36 #include <sys/types.h>
39 #include <sys/resource.h>
42 #include <sys/utsname.h>
45 #include "../common/memory.h"
46 #include "../common/version_internal.h"
48 #include "Communication.hh"
51 #include "Snapshot.hh"
54 #include "Module_list.hh"
55 #include "Component.hh"
57 #include "Verdicttype.hh"
58 #include "Charstring.hh"
59 #include "Fd_And_Timeout_User.hh"
60 #include <TitanLoggerApi.hh>
61 #include "Profiler.hh"
63 namespace API
= TitanLoggerApi
;
65 #ifndef MAXHOSTNAMELEN
66 # define MAXHOSTNAMELEN 256
69 #include "../common/dbgnew.hh"
71 TTCN_Runtime::executor_state_enum
72 TTCN_Runtime::executor_state
= UNDEFINED_STATE
;
74 qualified_name
TTCN_Runtime::component_type
= { NULL
, NULL
};
75 char *TTCN_Runtime::component_name
= NULL
;
76 boolean
TTCN_Runtime::is_alive
= FALSE
;
78 const char *TTCN_Runtime::control_module_name
= NULL
;
79 qualified_name
TTCN_Runtime::testcase_name
= { NULL
, NULL
};
81 char *TTCN_Runtime::host_name
= NULL
;
83 verdicttype
TTCN_Runtime::local_verdict
= NONE
;
84 unsigned int TTCN_Runtime::verdict_count
[5] = { 0, 0, 0, 0, 0 },
85 TTCN_Runtime::control_error_count
= 0;
86 CHARSTRING
TTCN_Runtime::verdict_reason(0, ""); // empty string
88 boolean
TTCN_Runtime::in_ttcn_try_block
= FALSE
;
90 char *TTCN_Runtime::begin_controlpart_command
= NULL
,
91 *TTCN_Runtime::end_controlpart_command
= NULL
,
92 *TTCN_Runtime::begin_testcase_command
= NULL
,
93 *TTCN_Runtime::end_testcase_command
= NULL
;
95 component
TTCN_Runtime::create_done_killed_compref
= NULL_COMPREF
;
96 boolean
TTCN_Runtime::running_alive_result
= FALSE
;
98 alt_status
TTCN_Runtime::any_component_done_status
= ALT_UNCHECKED
,
99 TTCN_Runtime::all_component_done_status
= ALT_UNCHECKED
,
100 TTCN_Runtime::any_component_killed_status
= ALT_UNCHECKED
,
101 TTCN_Runtime::all_component_killed_status
= ALT_UNCHECKED
;
102 int TTCN_Runtime::component_status_table_size
= 0;
103 component
TTCN_Runtime::component_status_table_offset
= FIRST_PTC_COMPREF
;
104 struct TTCN_Runtime::component_status_table_struct
{
105 alt_status done_status
, killed_status
;
107 Text_Buf
*return_value
;
108 } *TTCN_Runtime::component_status_table
= NULL
;
110 struct TTCN_Runtime::component_process_struct
{
111 component component_reference
;
113 boolean process_killed
;
114 struct component_process_struct
*prev_by_compref
, *next_by_compref
;
115 struct component_process_struct
*prev_by_pid
, *next_by_pid
;
116 } **TTCN_Runtime::components_by_compref
= NULL
,
117 **TTCN_Runtime::components_by_pid
= NULL
;
119 boolean
TTCN_Runtime::is_idle()
121 switch (executor_state
) {
134 boolean
TTCN_Runtime::verdict_enabled()
136 return executor_state
== SINGLE_TESTCASE
||
137 (executor_state
>= MTC_TESTCASE
&& executor_state
<= MTC_EXIT
) ||
138 (executor_state
>= PTC_INITIAL
&& executor_state
<= PTC_EXIT
);
141 void TTCN_Runtime::wait_for_state_change()
143 executor_state_enum old_state
= executor_state
;
145 TTCN_Snapshot::take_new(TRUE
);
146 } while (old_state
== executor_state
);
149 void TTCN_Runtime::clear_qualified_name(qualified_name
& q_name
)
151 Free(q_name
.module_name
);
152 q_name
.module_name
= NULL
;
153 Free(q_name
.definition_name
);
154 q_name
.definition_name
= NULL
;
157 void TTCN_Runtime::clean_up()
159 clear_qualified_name(component_type
);
160 Free(component_name
);
161 component_name
= NULL
;
162 control_module_name
= NULL
;
163 clear_qualified_name(testcase_name
);
166 clear_external_commands();
169 void TTCN_Runtime::initialize_component_type()
171 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__start
,
172 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
173 TTCN_Runtime::get_testcase_name());
175 Module_List::initialize_component(component_type
.module_name
,
176 component_type
.definition_name
, TRUE
);
177 PORT::set_parameters((component
)self
, component_name
);
180 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__finish
,
181 component_type
.module_name
, component_type
.definition_name
);
183 local_verdict
= NONE
;
187 void TTCN_Runtime::terminate_component_type()
189 if (component_type
.module_name
!= NULL
&&
190 component_type
.definition_name
!= NULL
) {
191 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::terminating__component
,
192 component_type
.module_name
, component_type
.definition_name
);
194 TTCN_Default::deactivate_all();
196 PORT::deactivate_all();
198 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::component__shut__down
,
199 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
200 TTCN_Runtime::get_testcase_name());
202 clear_qualified_name(component_type
);
203 Free(component_name
);
204 component_name
= NULL
;
208 void TTCN_Runtime::set_component_type(const char *component_type_module
,
209 const char *component_type_name
)
211 if (component_type_module
== NULL
|| component_type_module
[0] == '\0' ||
212 component_type_name
== NULL
|| component_type_name
[0] == '\0')
213 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
214 "Trying to set an invalid component type.");
215 if (component_type
.module_name
!= NULL
||
216 component_type
.definition_name
!= NULL
)
217 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
218 "Trying to set component type %s.%s while another one is active.",
219 component_type_module
, component_type_name
);
221 component_type
.module_name
= mcopystr(component_type_module
);
222 component_type
.definition_name
= mcopystr(component_type_name
);
225 void TTCN_Runtime::set_component_name(const char *new_component_name
)
227 Free(component_name
);
228 if (new_component_name
!= NULL
&& new_component_name
[0] != '\0')
229 component_name
= mcopystr(new_component_name
);
230 else component_name
= NULL
;
233 void TTCN_Runtime::set_testcase_name(const char *par_module_name
,
234 const char *par_testcase_name
)
236 if (par_module_name
== NULL
|| par_module_name
[0] == '\0' ||
237 par_testcase_name
== NULL
|| par_testcase_name
[0] == '\0')
238 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
239 "Trying to set an invalid testcase name.");
240 if (testcase_name
.module_name
!= NULL
||
241 testcase_name
.definition_name
!= NULL
)
242 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
243 "Trying to set testcase name %s.%s while another one is active.",
244 par_module_name
, par_testcase_name
);
246 testcase_name
.module_name
= mcopystr(par_module_name
);
247 testcase_name
.definition_name
= mcopystr(par_testcase_name
);
250 const char *TTCN_Runtime::get_host_name()
252 if (host_name
== NULL
) {
253 #if defined(SOLARIS8)
254 // Workaround for Solaris10 (lumped under SOLARIS8) + dynamic linking.
255 // "g++ -shared" seems to produce a very strange kind of symbol
256 // for gethostname in the .so, and linking fails with the infamous
257 // "ld: libttcn3-dynamic.so: gethostname: invalid version 3 (max 0)"
258 // The workaround is to use uname instead of gethostname.
260 if (uname(&uts
) < 0) {
261 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
262 TTCN_Logger::log_event_str("System call uname() failed.");
263 TTCN_Logger::OS_error();
264 TTCN_Logger::end_event();
265 host_name
= mcopystr("unknown");
267 host_name
= mcopystr(uts
.nodename
);
270 char tmp_str
[MAXHOSTNAMELEN
+ 1];
271 if (gethostname(tmp_str
, MAXHOSTNAMELEN
)) {
272 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
273 TTCN_Logger::log_event_str("System call gethostname() failed.");
274 TTCN_Logger::OS_error();
275 TTCN_Logger::end_event();
277 } else tmp_str
[MAXHOSTNAMELEN
] = '\0';
278 if (tmp_str
[0] != '\0') host_name
= mcopystr(tmp_str
);
279 else host_name
= mcopystr("unknown");
285 CHARSTRING
TTCN_Runtime::get_host_address(const CHARSTRING
& type
)
287 if (type
!= "Ipv4orIpv6" && type
!= "Ipv4" && type
!= "Ipv6") {
288 TTCN_error("The argument of hostid function must be Ipv4orIpv6 or Ipv4"
289 "or Ipv6. %s is not a valid argument.", (const char*)type
);
292 // Return empty if no host address could be retrieved
293 if (!TTCN_Communication::has_local_address()) {
294 return CHARSTRING("");
296 const IPAddress
*address
= TTCN_Communication::get_local_address();
298 // Return empty if the type is not matching the address type
299 if (type
== "Ipv4") {
300 const IPv4Address
* ipv4
= dynamic_cast<const IPv4Address
*>(address
);
302 return CHARSTRING("");
305 if (type
== "Ipv6") {
306 #if defined(LINUX) || defined(CYGWIN17)
307 const IPv6Address
* ipv6
= dynamic_cast<const IPv6Address
*>(address
);
309 #endif // LINUX || CYGWIN17
310 return CHARSTRING("");
312 // Return the string representation of the address
313 return CHARSTRING(address
->get_addr_str());
316 CHARSTRING
TTCN_Runtime::get_testcase_id_macro()
318 if (in_controlpart()) TTCN_error("Macro %%testcaseId cannot be used from "
319 "the control part outside test cases.");
320 if (testcase_name
.definition_name
== NULL
||
321 testcase_name
.definition_name
[0] == '\0')
322 TTCN_error("Internal error: Evaluating macro %%testcaseId, but the "
323 "name of the current testcase is not set.");
324 return CHARSTRING(testcase_name
.definition_name
);
327 CHARSTRING
TTCN_Runtime::get_testcasename()
329 if (in_controlpart() || is_hc()) return CHARSTRING(""); // No error here.
331 if (!testcase_name
.definition_name
|| testcase_name
.definition_name
[0] == 0)
332 TTCN_error("Internal error: Evaluating predefined function testcasename()"
333 ", but the name of the current testcase is not set.");
335 return CHARSTRING(testcase_name
.definition_name
);
338 void TTCN_Runtime::load_logger_plugins()
340 TTCN_Logger::load_plugins((component
)self
, component_name
);
343 void TTCN_Runtime::set_logger_parameters()
345 TTCN_Logger::set_plugin_parameters((component
)self
, component_name
);
348 const char *TTCN_Runtime::get_signal_name(int signal_number
)
350 const char *signal_name
= strsignal(signal_number
);
351 if (signal_name
!= NULL
) return signal_name
;
352 else return "Unknown signal";
355 static void sigint_handler(int signum
)
357 if (signum
!= SIGINT
) {
358 TTCN_warning("Unexpected signal %d (%s) was caught by the handler of "
359 "SIGINT.", signum
, TTCN_Runtime::get_signal_name(signum
));
362 if (TTCN_Runtime::is_single()) {
363 TTCN_Logger::log_str(TTCN_Logger::WARNING_UNQUALIFIED
,
364 "Execution was interrupted by the user.");
365 if (TTCN_Runtime::get_state() == TTCN_Runtime::SINGLE_TESTCASE
) {
366 TTCN_Logger::log_executor_runtime(
367 API::ExecutorRuntime_reason::stopping__current__testcase
);
368 TTCN_Runtime::end_testcase();
372 TTCN_Logger::log_executor_runtime(
373 API::ExecutorRuntime_reason::exiting
);
379 void TTCN_Runtime::set_signal_handler(int signal_number
,
380 const char *signal_name
, signal_handler_type signal_handler
)
382 struct sigaction sig_act
;
383 if (sigaction(signal_number
, NULL
, &sig_act
))
384 TTCN_error("System call sigaction() failed when getting signal "
385 "handling information for %s.", signal_name
);
386 sig_act
.sa_handler
= signal_handler
;
387 sig_act
.sa_flags
= 0;
388 if (sigaction(signal_number
, &sig_act
, NULL
))
389 TTCN_error("System call sigaction() failed when changing the signal "
390 "handling settings for %s.", signal_name
);
393 void TTCN_Runtime::restore_default_handler(int signal_number
,
394 const char *signal_name
)
396 struct sigaction sig_act
;
397 if (sigaction(signal_number
, NULL
, &sig_act
))
398 TTCN_error("System call sigaction() failed when getting signal "
399 "handling information for %s.", signal_name
);
400 sig_act
.sa_handler
= SIG_DFL
;
401 sig_act
.sa_flags
= 0;
402 if (sigaction(signal_number
, &sig_act
, NULL
))
403 TTCN_error("System call sigaction() failed when restoring the "
404 "default signal handling settings for %s.", signal_name
);
407 void TTCN_Runtime::ignore_signal(int signal_number
, const char *signal_name
)
409 struct sigaction sig_act
;
410 if (sigaction(signal_number
, NULL
, &sig_act
))
411 TTCN_error("System call sigaction() failed when getting signal "
412 "handling information for %s.", signal_name
);
413 sig_act
.sa_handler
= SIG_IGN
;
414 sig_act
.sa_flags
= 0;
415 if (sigaction(signal_number
, &sig_act
, NULL
))
416 TTCN_error("System call sigaction() failed when disabling signal "
420 void TTCN_Runtime::enable_interrupt_handler()
422 set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
425 void TTCN_Runtime::disable_interrupt_handler()
427 ignore_signal(SIGINT
, "SIGINT");
430 void TTCN_Runtime::install_signal_handlers()
432 if (is_single()) set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
433 ignore_signal(SIGPIPE
, "SIGPIPE");
436 void TTCN_Runtime::restore_signal_handlers()
438 if (is_single()) restore_default_handler(SIGINT
, "SIGINT");
439 restore_default_handler(SIGPIPE
, "SIGPIPE");
442 int TTCN_Runtime::hc_main(const char *local_addr
, const char *MC_addr
,
443 unsigned short MC_port
)
445 int ret_val
= EXIT_SUCCESS
;
446 executor_state
= HC_INITIAL
;
447 TTCN_Logger::log_HC_start(get_host_name());
448 TTCN_Logger::write_logger_settings();
449 TTCN_Snapshot::check_fd_setsize();
451 if (local_addr
!= NULL
)
452 TTCN_Communication::set_local_address(local_addr
);
453 TTCN_Communication::set_mc_address(MC_addr
, MC_port
);
454 TTCN_Communication::connect_mc();
455 Module_List::send_versions();
456 executor_state
= HC_IDLE
;
457 TTCN_Communication::send_version();
458 initialize_component_process_tables();
460 TTCN_Snapshot::take_new(TRUE
);
461 TTCN_Communication::process_all_messages_hc();
462 } while (executor_state
>= HC_IDLE
&& executor_state
< HC_EXIT
);
463 if (executor_state
== HC_EXIT
) {
464 // called only on the HC
465 TTCN_Communication::disconnect_mc();
468 } catch (const TC_Error
& tc_error
) {
469 ret_val
= EXIT_FAILURE
;
472 // called on the newly created MTC and PTCs as well because
473 // the hashtables are inherited with fork()
474 clear_component_process_tables();
477 TTCN_Logger::log_executor_runtime(
478 API::ExecutorRuntime_reason::host__controller__finished
);
483 int TTCN_Runtime::mtc_main()
485 int ret_val
= EXIT_SUCCESS
;
486 TTCN_Runtime::load_logger_plugins();
487 TTCN_Runtime::set_logger_parameters();
488 TTCN_Logger::open_file();
489 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__started
);
490 TTCN_Logger::write_logger_settings();
492 TTCN_Communication::connect_mc();
493 executor_state
= MTC_IDLE
;
494 TTCN_Communication::send_mtc_created();
496 TTCN_Snapshot::take_new(TRUE
);
497 TTCN_Communication::process_all_messages_tc();
498 } while (executor_state
!= MTC_EXIT
);
499 TTCN_Logger::close_file();
500 TTCN_Communication::disconnect_mc();
502 } catch (const TC_Error
& tc_error
) {
503 ret_val
= EXIT_FAILURE
;
505 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__finished
);
509 int TTCN_Runtime::ptc_main()
511 int ret_val
= EXIT_SUCCESS
;
512 TTCN_Runtime::load_logger_plugins();
513 TTCN_Runtime::set_logger_parameters();
514 TTCN_Logger::open_file();
515 TTCN_Logger::begin_event(TTCN_Logger::EXECUTOR_COMPONENT
);
516 TTCN_Logger::log_event("TTCN-3 Parallel Test Component started on %s. "
517 "Component reference: ", get_host_name());
519 TTCN_Logger::log_event(", component type: %s.%s",
520 component_type
.module_name
, component_type
.definition_name
);
521 if (component_name
!= NULL
)
522 TTCN_Logger::log_event(", component name: %s", component_name
);
523 TTCN_Logger::log_event_str(". Version: " PRODUCT_NUMBER
".");
524 TTCN_Logger::end_event();
525 TTCN_Logger::write_logger_settings();
527 TTCN_Communication::connect_mc();
528 executor_state
= PTC_IDLE
;
529 TTCN_Communication::send_ptc_created((component
)self
);
531 initialize_component_type();
532 } catch (const TC_Error
& tc_error
) {
533 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::component__init__fail
);
534 ret_val
= EXIT_FAILURE
;
536 if (ret_val
== EXIT_SUCCESS
) {
537 if (ttcn3_debugger
.is_activated()) {
538 ttcn3_debugger
.open_output_file();
542 TTCN_Snapshot::take_new(TRUE
);
543 TTCN_Communication::process_all_messages_tc();
544 } while (executor_state
!= PTC_EXIT
);
545 } catch (const TC_Error
& tc_error
) {
546 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::error__idle__ptc
);
547 ret_val
= EXIT_FAILURE
;
550 if (ret_val
!= EXIT_SUCCESS
) {
551 // ignore errors in subsequent operations
553 terminate_component_type();
554 } catch (const TC_Error
& tc_error
) { }
556 TTCN_Communication::send_killed(local_verdict
, (const char *)verdict_reason
);
557 } catch (const TC_Error
& tc_error
) { }
558 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
559 local_verdict
, (const char *)verdict_reason
);
560 executor_state
= PTC_EXIT
;
562 TTCN_Communication::disconnect_mc();
563 clear_component_status_table();
565 } catch (const TC_Error
& tc_error
) {
566 ret_val
= EXIT_FAILURE
;
568 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::ptc__finished
);
572 component
TTCN_Runtime::create_component(
573 const char *created_component_type_module
,
574 const char *created_component_type_name
, const char *created_component_name
,
575 const char *created_component_location
, boolean created_component_alive
)
577 if (in_controlpart())
578 TTCN_error("Create operation cannot be performed in the control part.");
579 else if (is_single())
580 TTCN_error("Create operation cannot be performed in single mode.");
582 if (created_component_name
!= NULL
&&
583 created_component_name
[0] == '\0') {
584 TTCN_warning("Empty charstring value was ignored as component name "
585 "in create operation.");
586 created_component_name
= NULL
;
588 if (created_component_location
!= NULL
&&
589 created_component_location
[0] == '\0') {
590 TTCN_warning("Empty charstring value was ignored as component location "
591 "in create operation.");
592 created_component_location
= NULL
;
595 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
596 TTCN_Logger::log_event("Creating new %sPTC with component type %s.%s",
597 created_component_alive
? "alive ": "", created_component_type_module
,
598 created_component_type_name
);
599 if (created_component_name
!= NULL
)
600 TTCN_Logger::log_event(", component name: %s", created_component_name
);
601 if (created_component_location
!= NULL
)
602 TTCN_Logger::log_event(", location: %s", created_component_location
);
603 TTCN_Logger::log_char('.');
604 TTCN_Logger::end_event();
606 switch (executor_state
) {
608 executor_state
= MTC_CREATE
;
611 executor_state
= PTC_CREATE
;
614 TTCN_error("Internal error: Executing create operation in invalid "
617 TTCN_Communication::send_create_req(created_component_type_module
,
618 created_component_type_name
, created_component_name
,
619 created_component_location
, created_component_alive
);
621 // updating the component status flags
622 // 'any component.done' and 'any component.killed' might be successful
623 // from now since the PTC can terminate by itself
624 if (any_component_done_status
== ALT_NO
)
625 any_component_done_status
= ALT_UNCHECKED
;
626 if (any_component_killed_status
== ALT_NO
)
627 any_component_killed_status
= ALT_UNCHECKED
;
628 // 'all component.killed' must be re-evaluated later
629 all_component_killed_status
= ALT_UNCHECKED
;
631 wait_for_state_change();
633 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created
,
634 created_component_type_module
, created_component_type_name
,
635 create_done_killed_compref
, created_component_name
,
636 created_component_location
, created_component_alive
);
638 COMPONENT::register_component_name(create_done_killed_compref
,
639 created_component_name
);
640 return create_done_killed_compref
;
643 void TTCN_Runtime::prepare_start_component(const COMPONENT
& component_reference
,
644 const char *module_name
, const char *function_name
, Text_Buf
& text_buf
)
646 if (in_controlpart()) TTCN_error("Start test component operation cannot "
647 "be performed in the control part.");
648 else if (is_single()) TTCN_error("Start test component operation cannot "
649 "be performed in single mode.");
650 if (!component_reference
.is_bound()) TTCN_error("Performing a start "
651 "operation on an unbound component reference.");
652 component compref
= (component
)component_reference
;
655 TTCN_error("Start operation cannot be performed on the null "
656 "component reference.");
658 TTCN_error("Start operation cannot be performed on the component "
659 "reference of MTC.");
661 TTCN_error("Start operation cannot be performed on the component "
662 "reference of system.");
664 TTCN_error("Internal error: 'any component' cannot be started.");
666 TTCN_error("Internal error: 'all component' cannot be started.");
670 if (self
== compref
) TTCN_error("Start operation cannot be performed on "
671 "the own component reference of the initiating component (i.e. "
672 "'self.start' is not allowed).");
673 if (in_component_status_table(compref
)) {
674 if (get_killed_status(compref
) == ALT_YES
) {
675 TTCN_error("PTC with component reference %d is not alive anymore. "
676 "Start operation cannot be performed on it.", compref
);
678 // the done status of the PTC shall be invalidated
679 cancel_component_done(compref
);
681 TTCN_Communication::prepare_start_req(text_buf
, compref
, module_name
,
685 void TTCN_Runtime::send_start_component(Text_Buf
& text_buf
)
687 switch (executor_state
) {
689 executor_state
= MTC_START
;
692 executor_state
= PTC_START
;
695 TTCN_error("Internal error: Executing component start operation "
696 "in invalid state.");
698 // text_buf already contains a complete START_REQ message.
699 TTCN_Communication::send_message(text_buf
);
701 // updating the component status flags
702 // 'all component.done' must be re-evaluated later
703 all_component_done_status
= ALT_UNCHECKED
;
705 wait_for_state_change();
706 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__started
);
709 void TTCN_Runtime::start_function(const char *module_name
,
710 const char *function_name
, Text_Buf
& text_buf
)
712 switch (executor_state
) {
717 // the START message must be dropped here because normally it is
718 // dropped in function_started()
719 text_buf
.cut_message();
720 TTCN_error("Internal error: Message START arrived in invalid state.");
723 Module_List::start_function(module_name
, function_name
, text_buf
);
724 // do nothing: the function terminated normally
725 // the message STOPPED or STOPPED_KILLED is already sent out
726 // and the state variable is updated
728 } catch (const TC_End
& TC_end
) {
729 // executor_state is already set by stop_execution or kill_execution
730 switch (executor_state
) {
732 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
733 "Function %s was stopped. PTC remains alive and is waiting for next start.",
735 // send a STOPPED message without return value
736 TTCN_Communication::send_stopped();
737 // return and do nothing else
740 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__stopped
, NULL
,
744 TTCN_error("Internal error: PTC was stopped in invalid state.");
746 } catch (const TC_Error
& TC_error
) {
747 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__error
, NULL
,
749 executor_state
= PTC_EXIT
;
751 // the control reaches this code if the PTC has to be terminated
753 // first terminate all ports and timers
754 // this may affect the final verdict
755 terminate_component_type();
756 // send a STOPPED_KILLED message without return value
757 TTCN_Communication::send_stopped_killed(local_verdict
, verdict_reason
);
758 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
759 local_verdict
, (const char *)verdict_reason
);
762 void TTCN_Runtime::function_started(Text_Buf
& text_buf
)
764 // The buffer still contains the incoming START message.
765 text_buf
.cut_message();
766 executor_state
= PTC_FUNCTION
;
767 // The remaining messages must be processed now.
768 TTCN_Communication::process_all_messages_tc();
771 void TTCN_Runtime::prepare_function_finished(const char *return_type
,
774 if (executor_state
!= PTC_FUNCTION
)
775 TTCN_error("Internal error: PTC behaviour function finished in invalid "
778 // Prepare a STOPPED message with the possible return value.
779 TTCN_Communication::prepare_stopped(text_buf
, return_type
);
781 // First the ports and timers must be stopped and deactivated. The
782 // user_unmap and user_stop functions of Test Ports may detect errors
783 // that must be considered in the final verdict of the PTC.
784 terminate_component_type();
785 // Prepare a STOPPED_KILLED message with the final verdict and the
786 // possible return value.
787 TTCN_Communication::prepare_stopped_killed(text_buf
, local_verdict
,
788 return_type
, verdict_reason
);
792 void TTCN_Runtime::send_function_finished(Text_Buf
& text_buf
)
794 // send out the STOPPED or STOPPED_KILLED message, which is already
795 // complete and contains the return value
796 TTCN_Communication::send_message(text_buf
);
797 // log the final verdict if necessary and update the state variable
798 if (is_alive
) executor_state
= PTC_STOPPED
;
800 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
801 local_verdict
, (const char *)verdict_reason
);
802 executor_state
= PTC_EXIT
;
806 void TTCN_Runtime::function_finished(const char *function_name
)
808 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__finished
, NULL
,
809 function_name
, 0, NULL
, NULL
, is_alive
);
811 prepare_function_finished(NULL
, text_buf
);
812 send_function_finished(text_buf
);
815 alt_status
TTCN_Runtime::component_done(component component_reference
)
817 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
818 "in the control part.");
819 switch (component_reference
) {
821 TTCN_error("Done operation cannot be performed on the null "
822 "component reference.");
824 TTCN_error("Done operation cannot be performed on the component "
825 "reference of MTC.");
827 TTCN_error("Done operation cannot be performed on the component "
828 "reference of system.");
830 return any_component_done();
832 return all_component_done();
834 return ptc_done(component_reference
);
838 alt_status
TTCN_Runtime::component_done(component component_reference
,
839 const char *return_type
, Text_Buf
*& text_buf
)
841 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
842 "in the control part.");
843 switch (component_reference
) {
845 TTCN_error("Done operation cannot be performed on the null "
846 "component reference.");
848 TTCN_error("Done operation cannot be performed on the component "
849 "reference of MTC.");
851 TTCN_error("Done operation cannot be performed on the component "
852 "reference of system.");
854 TTCN_error("Done operation with return value cannot be performed on "
857 TTCN_error("Done operation with return value cannot be performed on "
860 // the argument refers to a PTC
863 if (is_single()) TTCN_error("Done operation on a component reference "
864 "cannot be performed in single mode.");
865 if (self
== component_reference
) {
866 TTCN_warning("Done operation on the component reference of self "
867 "will never succeed.");
870 int index
= get_component_status_table_index(component_reference
);
871 // we cannot use the killed status because we need the return value
872 switch (component_status_table
[index
].done_status
) {
874 switch (executor_state
) {
876 executor_state
= MTC_DONE
;
879 executor_state
= PTC_DONE
;
882 TTCN_error("Internal error: Executing done operation in "
885 TTCN_Communication::send_done_req(component_reference
);
886 component_status_table
[index
].done_status
= ALT_MAYBE
;
887 create_done_killed_compref
= component_reference
;
889 wait_for_state_change();
890 // always re-evaluate the current alternative using a new snapshot
893 if (component_status_table
[index
].return_type
!= NULL
) {
894 if (!strcmp(component_status_table
[index
].return_type
,
896 component_status_table
[index
].return_value
->rewind();
897 text_buf
= component_status_table
[index
].return_value
;
900 TTCN_Logger::log_matching_done(return_type
, component_reference
,
901 component_status_table
[index
].return_type
,
902 API::MatchingDoneType_reason::done__failed__wrong__return__type
);
906 TTCN_Logger::log_matching_done(return_type
, component_reference
, NULL
,
907 API::MatchingDoneType_reason::done__failed__no__return
);
916 alt_status
TTCN_Runtime::component_killed(component component_reference
)
918 if (in_controlpart()) TTCN_error("Killed operation cannot be performed "
919 "in the control part.");
920 switch (component_reference
) {
922 TTCN_error("Killed operation cannot be performed on the null "
923 "component reference.");
925 TTCN_error("Killed operation cannot be performed on the component "
926 "reference of MTC.");
928 TTCN_error("Killed operation cannot be performed on the component "
929 "reference of system.");
931 return any_component_killed();
933 return all_component_killed();
935 return ptc_killed(component_reference
);
939 boolean
TTCN_Runtime::component_running(component component_reference
)
941 if (in_controlpart()) TTCN_error("Component running operation "
942 "cannot be performed in the control part.");
943 switch (component_reference
) {
945 TTCN_error("Running operation cannot be performed on the null "
946 "component reference.");
948 TTCN_error("Running operation cannot be performed on the component "
949 "reference of MTC.");
951 TTCN_error("Running operation cannot be performed on the component "
952 "reference of system.");
954 return any_component_running();
956 return all_component_running();
958 return ptc_running(component_reference
);
962 boolean
TTCN_Runtime::component_alive(component component_reference
)
964 if (in_controlpart()) TTCN_error("Alive operation cannot be performed "
965 "in the control part.");
966 switch (component_reference
) {
968 TTCN_error("Alive operation cannot be performed on the null "
969 "component reference.");
971 TTCN_error("Alive operation cannot be performed on the component "
972 "reference of MTC.");
974 TTCN_error("Alive operation cannot be performed on the component "
975 "reference of system.");
977 return any_component_alive();
979 return all_component_alive();
981 return ptc_alive(component_reference
);
985 void TTCN_Runtime::stop_component(component component_reference
)
987 if (in_controlpart()) TTCN_error("Component stop operation cannot be "
988 "performed in the control part.");
990 if (self
== component_reference
) stop_execution();
991 switch (component_reference
) {
993 TTCN_error("Stop operation cannot be performed on the null component "
999 TTCN_error("Stop operation cannot be performed on the component "
1000 "reference of system.");
1002 TTCN_error("Internal error: 'any component' cannot be stopped.");
1004 stop_all_component();
1007 stop_ptc(component_reference
);
1011 void TTCN_Runtime::stop_execution()
1013 if (in_controlpart()) {
1014 TTCN_Logger::log_executor_runtime(
1015 API::ExecutorRuntime_reason::stopping__control__part__execution
);
1017 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1018 "Stopping test component execution.");
1020 // the state variable indicates whether the component remains alive
1021 // after termination or not
1022 if (is_alive
) executor_state
= PTC_STOPPED
;
1023 else executor_state
= PTC_EXIT
;
1029 void TTCN_Runtime::kill_component(component component_reference
)
1031 if (in_controlpart()) TTCN_error("Kill operation cannot be performed in "
1032 "the control part.");
1034 if (self
== component_reference
) kill_execution();
1035 switch (component_reference
) {
1037 TTCN_error("Kill operation cannot be performed on the null component "
1040 // 'mtc.kill' means exactly the same as 'mtc.stop'
1043 case SYSTEM_COMPREF
:
1044 TTCN_error("Kill operation cannot be performed on the component "
1045 "reference of system.");
1047 TTCN_error("Internal error: 'any component' cannot be killed.");
1049 kill_all_component();
1052 kill_ptc(component_reference
);
1056 void TTCN_Runtime::kill_execution()
1058 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1059 "Terminating test component execution.");
1060 if (is_ptc()) executor_state
= PTC_EXIT
;
1064 alt_status
TTCN_Runtime::ptc_done(component component_reference
)
1066 if (is_single()) TTCN_error("Done operation on a component reference "
1067 "cannot be performed in single mode.");
1068 if (self
== component_reference
) {
1069 TTCN_warning("Done operation on the component reference of self "
1070 "will never succeed.");
1073 int index
= get_component_status_table_index(component_reference
);
1074 // a successful killed operation on the component reference implies done
1075 if (component_status_table
[index
].killed_status
== ALT_YES
)
1077 switch (component_status_table
[index
].done_status
) {
1079 switch (executor_state
) {
1081 executor_state
= MTC_DONE
;
1084 executor_state
= PTC_DONE
;
1087 TTCN_error("Internal error: Executing done operation in "
1090 TTCN_Communication::send_done_req(component_reference
);
1091 component_status_table
[index
].done_status
= ALT_MAYBE
;
1092 create_done_killed_compref
= component_reference
;
1093 // wait for DONE_ACK
1094 wait_for_state_change();
1095 // always re-evaluate the current alternative using a new snapshot
1103 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__done
,
1104 NULL
, NULL
, component_reference
);
1108 alt_status
TTCN_Runtime::any_component_done()
1110 // the operation is never successful in single mode
1111 if (is_single()) goto failure
;
1112 if (!is_mtc()) TTCN_error("Operation 'any component.done' can only be "
1113 "performed on the MTC.");
1114 // the operation is successful if there is a component reference with a
1115 // successful done or killed operation
1116 for (int i
= 0; i
< component_status_table_size
; i
++) {
1117 if (component_status_table
[i
].done_status
== ALT_YES
||
1118 component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1120 // a successful 'any component.killed' implies 'any component.done'
1121 if (any_component_killed_status
== ALT_YES
) goto success
;
1122 switch (any_component_done_status
) {
1124 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1125 "Executing 'any component.done' in invalid state.");
1126 executor_state
= MTC_DONE
;
1127 TTCN_Communication::send_done_req(ANY_COMPREF
);
1128 any_component_done_status
= ALT_MAYBE
;
1129 create_done_killed_compref
= ANY_COMPREF
;
1130 // wait for DONE_ACK
1131 wait_for_state_change();
1132 // always re-evaluate the current alternative using a new snapshot
1142 TTCN_Logger::log_matching_done(0, 0, 0,
1143 API::MatchingDoneType_reason::any__component__done__successful
);
1146 TTCN_Logger::log_matching_done(0, 0, 0,
1147 API::MatchingDoneType_reason::any__component__done__failed
);
1151 alt_status
TTCN_Runtime::all_component_done()
1153 // the operation is always successful in single mode
1154 if (is_single()) goto success
;
1155 if (!is_mtc()) TTCN_error("Operation 'all component.done' can only be "
1156 "performed on the MTC.");
1157 // a successful 'all component.killed' implies 'all component.done'
1158 if (all_component_killed_status
== ALT_YES
) goto success
;
1159 switch (all_component_done_status
) {
1161 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1162 "Executing 'all component.done' in invalid state.");
1163 executor_state
= MTC_DONE
;
1164 TTCN_Communication::send_done_req(ALL_COMPREF
);
1165 all_component_done_status
= ALT_MAYBE
;
1166 create_done_killed_compref
= ALL_COMPREF
;
1167 // wait for DONE_ACK
1168 wait_for_state_change();
1169 // always re-evaluate the current alternative using a new snapshot
1177 TTCN_Logger::log_matching_done(0, 0, 0,
1178 API::MatchingDoneType_reason::all__component__done__successful
);
1182 alt_status
TTCN_Runtime::ptc_killed(component component_reference
)
1184 if (is_single()) TTCN_error("Killed operation on a component reference "
1185 "cannot be performed in single mode.");
1186 if (self
== component_reference
) {
1187 TTCN_warning("Killed operation on the component reference of self "
1188 "will never succeed.");
1191 int index
= get_component_status_table_index(component_reference
);
1192 switch (component_status_table
[index
].killed_status
) {
1194 switch (executor_state
) {
1196 executor_state
= MTC_KILLED
;
1199 executor_state
= PTC_KILLED
;
1202 TTCN_error("Internal error: Executing killed operation in "
1205 TTCN_Communication::send_killed_req(component_reference
);
1206 component_status_table
[index
].killed_status
= ALT_MAYBE
;
1207 create_done_killed_compref
= component_reference
;
1208 // wait for KILLED_ACK
1209 wait_for_state_change();
1210 // always re-evaluate the current alternative using a new snapshot
1218 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
,
1219 NULL
, NULL
, component_reference
);
1223 alt_status
TTCN_Runtime::any_component_killed()
1225 // the operation is never successful in single mode
1226 if (is_single()) goto failure
;
1227 if (!is_mtc()) TTCN_error("Operation 'any component.killed' can only be "
1228 "performed on the MTC.");
1229 // the operation is successful if there is a component reference with a
1230 // successful killed operation
1231 for (int i
= 0; i
< component_status_table_size
; i
++) {
1232 if (component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1234 switch (any_component_killed_status
) {
1236 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1237 "Executing 'any component.killed' in invalid state.");
1238 executor_state
= MTC_KILLED
;
1239 TTCN_Communication::send_killed_req(ANY_COMPREF
);
1240 any_component_killed_status
= ALT_MAYBE
;
1241 create_done_killed_compref
= ANY_COMPREF
;
1242 // wait for KILLED_ACK
1243 wait_for_state_change();
1244 // always re-evaluate the current alternative using a new snapshot
1254 TTCN_Logger::log_matching_done(0, 0, 0,
1255 API::MatchingDoneType_reason::any__component__killed__successful
);
1258 TTCN_Logger::log_matching_done(0, 0, 0,
1259 API::MatchingDoneType_reason::any__component__killed__failed
);
1263 alt_status
TTCN_Runtime::all_component_killed()
1265 // the operation is always successful in single mode
1266 if (is_single()) goto success
;
1267 if (!is_mtc()) TTCN_error("Operation 'all component.killed' can only be "
1268 "performed on the MTC.");
1269 switch (all_component_killed_status
) {
1271 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1272 "Executing 'all component.killed' in invalid state.");
1273 executor_state
= MTC_KILLED
;
1274 TTCN_Communication::send_killed_req(ALL_COMPREF
);
1275 all_component_killed_status
= ALT_MAYBE
;
1276 create_done_killed_compref
= ALL_COMPREF
;
1277 // wait for KILLED_ACK
1278 wait_for_state_change();
1279 // always re-evaluate the current alternative using a new snapshot
1287 TTCN_Logger::log_matching_done(0, 0, 0,
1288 API::MatchingDoneType_reason::all__component__killed__successful
);
1292 boolean
TTCN_Runtime::ptc_running(component component_reference
)
1294 if (is_single()) TTCN_error("Running operation on a component reference "
1295 "cannot be performed in single mode.");
1296 // the answer is always true if the operation refers to self
1297 if (self
== component_reference
) {
1298 TTCN_warning("Running operation on the component reference of self "
1299 "always returns true.");
1302 // look into the component status tables
1303 if (in_component_status_table(component_reference
)) {
1304 int index
= get_component_status_table_index(component_reference
);
1305 // the answer is false if a successful done or killed operation was
1306 // performed on the component reference
1307 if (component_status_table
[index
].done_status
== ALT_YES
||
1308 component_status_table
[index
].killed_status
== ALT_YES
)
1311 // status flags all_component_done or all_component_killed cannot be used
1312 // because the component reference might be invalid (e.g. stale)
1314 // the decision cannot be made locally, MC must be asked
1315 switch (executor_state
) {
1317 executor_state
= MTC_RUNNING
;
1320 executor_state
= PTC_RUNNING
;
1323 TTCN_error("Internal error: Executing component running operation "
1324 "in invalid state.");
1326 TTCN_Communication::send_is_running(component_reference
);
1328 wait_for_state_change();
1329 return running_alive_result
;
1332 boolean
TTCN_Runtime::any_component_running()
1334 // the answer is always false in single mode
1335 if (is_single()) return FALSE
;
1336 if (!is_mtc()) TTCN_error("Operation 'any component.running' can only be "
1337 "performed on the MTC.");
1338 // the answer is false if 'all component.done' or 'all component.killed'
1339 // operation was successful
1340 if (all_component_done_status
== ALT_YES
||
1341 all_component_killed_status
== ALT_YES
) return FALSE
;
1342 // the decision cannot be made locally, MC must be asked
1343 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1344 "Executing 'any component.running' in invalid state.");
1345 TTCN_Communication::send_is_running(ANY_COMPREF
);
1346 executor_state
= MTC_RUNNING
;
1348 wait_for_state_change();
1349 // update the status of 'all component.done' in case of negative answer
1350 if (!running_alive_result
) all_component_done_status
= ALT_YES
;
1351 return running_alive_result
;
1354 boolean
TTCN_Runtime::all_component_running()
1356 // the answer is always true in single mode
1357 if (is_single()) return TRUE
;
1358 if (!is_mtc()) TTCN_error("Operation 'all component.running' can only be "
1359 "performed on the MTC.");
1360 // return true if no PTCs exist
1361 if (any_component_done_status
== ALT_NO
) return TRUE
;
1362 // the done and killed status flags cannot be used since the components
1363 // that were explicitly stopped or killed must be ignored
1365 // the decision cannot be made locally, MC must be asked
1366 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1367 "Executing 'all component.running' in invalid state.");
1368 TTCN_Communication::send_is_running(ALL_COMPREF
);
1369 executor_state
= MTC_RUNNING
;
1371 wait_for_state_change();
1372 return running_alive_result
;
1375 boolean
TTCN_Runtime::ptc_alive(component component_reference
)
1377 if (is_single()) TTCN_error("Alive operation on a component reference "
1378 "cannot be performed in single mode.");
1379 // the answer is always true if the operation refers to self
1380 if (self
== component_reference
) {
1381 TTCN_warning("Alive operation on the component reference of self "
1382 "always returns true.");
1385 // the answer is false if a successful killed operation was performed
1386 // on the component reference
1387 if (in_component_status_table(component_reference
) &&
1388 get_killed_status(component_reference
) == ALT_YES
) return FALSE
;
1389 // status flag of 'all component.killed' cannot be used because the
1390 // component reference might be invalid (e.g. stale)
1392 // the decision cannot be made locally, MC must be asked
1393 switch (executor_state
) {
1395 executor_state
= MTC_ALIVE
;
1398 executor_state
= PTC_ALIVE
;
1401 TTCN_error("Internal error: Executing component running operation "
1402 "in invalid state.");
1404 TTCN_Communication::send_is_alive(component_reference
);
1406 wait_for_state_change();
1407 return running_alive_result
;
1410 boolean
TTCN_Runtime::any_component_alive()
1412 // the answer is always false in single mode
1413 if (is_single()) return FALSE
;
1414 if (!is_mtc()) TTCN_error("Operation 'any component.alive' can only be "
1415 "performed on the MTC.");
1416 // the answer is false if 'all component.killed' operation was successful
1417 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1418 // the decision cannot be made locally, MC must be asked
1419 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1420 "Executing 'any component.alive' in invalid state.");
1421 TTCN_Communication::send_is_alive(ANY_COMPREF
);
1422 executor_state
= MTC_ALIVE
;
1424 wait_for_state_change();
1425 // update the status of 'all component.killed' in case of negative answer
1426 if (!running_alive_result
) all_component_killed_status
= ALT_YES
;
1427 return running_alive_result
;
1430 boolean
TTCN_Runtime::all_component_alive()
1432 // the answer is always true in single mode
1433 if (is_single()) return TRUE
;
1434 if (!is_mtc()) TTCN_error("Operation 'all component.alive' can only be "
1435 "performed on the MTC.");
1436 // return true if no PTCs exist
1437 if (any_component_killed_status
== ALT_NO
) return TRUE
;
1438 // return false if at least one PTC has been created and
1439 // 'all component.killed' was successful after the create operation
1440 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1441 // the operation is successful if there is a component reference with a
1442 // successful killed operation
1443 for (int i
= 0; i
< component_status_table_size
; i
++) {
1444 if (component_status_table
[i
].killed_status
== ALT_YES
) return FALSE
;
1447 // the decision cannot be made locally, MC must be asked
1448 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1449 "Executing 'all component.alive' in invalid state.");
1450 TTCN_Communication::send_is_alive(ALL_COMPREF
);
1451 executor_state
= MTC_ALIVE
;
1453 wait_for_state_change();
1454 return running_alive_result
;
1457 void TTCN_Runtime::stop_mtc()
1459 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::stopping__mtc
);
1460 TTCN_Communication::send_stop_req(MTC_COMPREF
);
1464 void TTCN_Runtime::stop_ptc(component component_reference
)
1466 if (is_single()) TTCN_error("Stop operation on a component reference "
1467 "cannot be performed in single mode.");
1468 // do nothing if a successful done or killed operation was performed on
1469 // the component reference
1470 if (in_component_status_table(component_reference
)) {
1471 int index
= get_component_status_table_index(component_reference
);
1472 if (component_status_table
[index
].done_status
== ALT_YES
||
1473 component_status_table
[index
].killed_status
== ALT_YES
)
1476 // status flags all_component_done or all_component_killed cannot be used
1477 // because the component reference might be invalid (e.g. stale)
1479 // MC must be asked to stop the PTC
1480 switch (executor_state
) {
1482 executor_state
= MTC_STOP
;
1485 executor_state
= PTC_STOP
;
1488 TTCN_error("Internal error: Executing component stop operation "
1489 "in invalid state.");
1491 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1492 "Stopping PTC with component reference %d.", component_reference
);
1493 TTCN_Communication::send_stop_req(component_reference
);
1494 // wait for STOP_ACK
1495 wait_for_state_change();
1496 // done status of the PTC cannot be updated because its return type and
1497 // return value is unknown
1498 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__stopped
,
1499 NULL
, NULL
, component_reference
);
1502 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1503 "PTC with component reference %d is not running. "
1504 "Stop operation had no effect.", component_reference
);
1507 void TTCN_Runtime::stop_all_component()
1509 // do nothing in single mode
1510 if (is_single()) goto ignore
;
1511 if (!is_mtc()) TTCN_error("Operation 'all component.stop' can only be "
1512 "performed on the MTC.");
1513 // do nothing if 'all component.done' or 'all component.killed'
1515 if (all_component_done_status
== ALT_YES
||
1516 all_component_killed_status
== ALT_YES
) goto ignore
;
1517 // a request must be sent to MC
1518 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1519 "Executing 'all component.stop' in invalid state.");
1520 executor_state
= MTC_STOP
;
1521 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Stopping all components.");
1522 TTCN_Communication::send_stop_req(ALL_COMPREF
);
1523 // wait for STOP_ACK
1524 wait_for_state_change();
1525 // 'all component.done' will be successful later
1526 all_component_done_status
= ALT_YES
;
1527 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__stopped
);
1530 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "No PTCs are running. "
1531 "Operation 'all component.stop' had no effect.");
1534 void TTCN_Runtime::kill_ptc(component component_reference
)
1536 if (is_single()) TTCN_error("Kill operation on a component reference "
1537 "cannot be performed in single mode.");
1538 // do nothing if a successful killed operation was performed on
1539 // the component reference
1540 if (in_component_status_table(component_reference
) &&
1541 get_killed_status(component_reference
) == ALT_YES
) goto ignore
;
1542 // status flags all_component_killed cannot be used because the component
1543 // reference might be invalid (e.g. stale)
1545 // MC must be asked to kill the PTC
1546 switch (executor_state
) {
1548 executor_state
= MTC_KILL
;
1551 executor_state
= PTC_KILL
;
1554 TTCN_error("Internal error: Executing kill operation in invalid "
1557 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1558 "Killing PTC with component reference %d.", component_reference
);
1559 TTCN_Communication::send_kill_req(component_reference
);
1560 // wait for KILL_ACK
1561 wait_for_state_change();
1562 // updating the killed status of the PTC
1564 int index
= get_component_status_table_index(component_reference
);
1565 component_status_table
[index
].killed_status
= ALT_YES
;
1567 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
, NULL
, NULL
,
1568 component_reference
);
1571 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1572 "PTC with component reference %d is not alive anymore. "
1573 "Kill operation had no effect.", component_reference
);
1576 void TTCN_Runtime::kill_all_component()
1578 // do nothing in single mode
1579 if (is_single()) goto ignore
;
1580 if (!is_mtc()) TTCN_error("Operation 'all component.kill' can only be "
1581 "performed on the MTC.");
1582 // do nothing if 'all component.killed' was successful
1583 if (all_component_killed_status
== ALT_YES
) goto ignore
;
1584 // a request must be sent to MC
1585 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1586 "Executing 'all component.kill' in invalid state.");
1587 executor_state
= MTC_KILL
;
1588 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Killing all components.");
1589 TTCN_Communication::send_kill_req(ALL_COMPREF
);
1590 // wait for KILL_ACK
1591 wait_for_state_change();
1592 // 'all component.done' and 'all component.killed' will be successful later
1593 all_component_done_status
= ALT_YES
;
1594 all_component_killed_status
= ALT_YES
;
1595 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__killed
);
1598 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1599 "There are no alive PTCs. Operation 'all component.kill' had no effect.");
1602 void TTCN_Runtime::check_port_name(const char *port_name
,
1603 const char *operation_name
, const char *which_argument
)
1605 if (port_name
== NULL
)
1606 TTCN_error("Internal error: The port name in the %s argument of %s "
1607 "operation is a NULL pointer.", which_argument
, operation_name
);
1608 if (port_name
[0] == '\0')
1609 TTCN_error("Internal error: The %s argument of %s operation contains "
1610 "an empty string as port name.", which_argument
, operation_name
);
1611 /** \todo check whether port_name contains a valid TTCN-3 identifier
1612 * (and array index) */
1615 void TTCN_Runtime::connect_port(
1616 const COMPONENT
& src_compref
, const char *src_port
,
1617 const COMPONENT
& dst_compref
, const char *dst_port
)
1619 check_port_name(src_port
, "connect", "first");
1620 check_port_name(dst_port
, "connect", "second");
1622 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1623 TTCN_Logger::log_event_str("Connecting ports ");
1624 COMPONENT::log_component_reference(src_compref
);
1625 TTCN_Logger::log_event(":%s and ", src_port
);
1626 COMPONENT::log_component_reference(dst_compref
);
1627 TTCN_Logger::log_event(":%s.", dst_port
);
1628 TTCN_Logger::end_event();
1630 if (!src_compref
.is_bound()) TTCN_error("The first argument of connect "
1631 "operation contains an unbound component reference.");
1632 component src_component
= src_compref
;
1633 switch (src_component
) {
1635 TTCN_error("The first argument of connect operation contains the "
1636 "null component reference.");
1637 case SYSTEM_COMPREF
:
1638 TTCN_error("The first argument of connect operation refers to a "
1643 if (!dst_compref
.is_bound()) TTCN_error("The second argument of connect "
1644 "operation contains an unbound component reference.");
1645 component dst_component
= dst_compref
;
1646 switch (dst_component
) {
1648 TTCN_error("The second argument of connect operation contains the "
1649 "null component reference.");
1650 case SYSTEM_COMPREF
:
1651 TTCN_error("The second argument of connect operation refers to a "
1657 switch (executor_state
) {
1658 case SINGLE_TESTCASE
:
1659 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1660 TTCN_error("Both endpoints of connect operation must refer to "
1661 "ports of mtc in single mode.");
1662 PORT::make_local_connection(src_port
, dst_port
);
1665 TTCN_Communication::send_connect_req(src_component
, src_port
,
1666 dst_component
, dst_port
);
1667 executor_state
= MTC_CONNECT
;
1668 wait_for_state_change();
1671 TTCN_Communication::send_connect_req(src_component
, src_port
,
1672 dst_component
, dst_port
);
1673 executor_state
= PTC_CONNECT
;
1674 wait_for_state_change();
1677 if (in_controlpart()) {
1678 TTCN_error("Connect operation cannot be performed in the "
1681 TTCN_error("Internal error: Executing connect operation "
1682 "in invalid state.");
1686 TTCN_Logger::log_portconnmap(API::ParPort_operation::connect__
,
1687 src_compref
, src_port
, dst_compref
, dst_port
);
1690 void TTCN_Runtime::disconnect_port(
1691 const COMPONENT
& src_compref
, const char *src_port
,
1692 const COMPONENT
& dst_compref
, const char *dst_port
)
1694 check_port_name(src_port
, "disconnect", "first");
1695 check_port_name(dst_port
, "disconnect", "second");
1697 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1698 TTCN_Logger::log_event_str("Disconnecting ports ");
1699 COMPONENT::log_component_reference(src_compref
);
1700 TTCN_Logger::log_event(":%s and ", src_port
);
1701 COMPONENT::log_component_reference(dst_compref
);
1702 TTCN_Logger::log_event(":%s.", dst_port
);
1703 TTCN_Logger::end_event();
1705 if (!src_compref
.is_bound()) TTCN_error("The first argument of disconnect "
1706 "operation contains an unbound component reference.");
1707 component src_component
= src_compref
;
1708 switch (src_component
) {
1710 TTCN_error("The first argument of disconnect operation contains the "
1711 "null component reference.");
1712 case SYSTEM_COMPREF
:
1713 TTCN_error("The first argument of disconnect operation refers to a "
1718 if (!dst_compref
.is_bound()) TTCN_error("The second argument of disconnect "
1719 "operation contains an unbound component reference.");
1720 component dst_component
= dst_compref
;
1721 switch (dst_component
) {
1723 TTCN_error("The second argument of disconnect operation contains the "
1724 "null component reference.");
1725 case SYSTEM_COMPREF
:
1726 TTCN_error("The second argument of disconnect operation refers to a "
1732 switch (executor_state
) {
1733 case SINGLE_TESTCASE
:
1734 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1735 TTCN_error("Both endpoints of disconnect operation must refer to "
1736 "ports of mtc in single mode.");
1737 PORT::terminate_local_connection(src_port
, dst_port
);
1740 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1741 dst_component
, dst_port
);
1742 executor_state
= MTC_DISCONNECT
;
1743 wait_for_state_change();
1746 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1747 dst_component
, dst_port
);
1748 executor_state
= PTC_DISCONNECT
;
1749 wait_for_state_change();
1752 if (in_controlpart()) {
1753 TTCN_error("Disonnect operation cannot be performed in the "
1756 TTCN_error("Internal error: Executing disconnect operation "
1757 "in invalid state.");
1761 TTCN_Logger::log_portconnmap(API::ParPort_operation::disconnect__
,
1762 src_compref
, src_port
, dst_compref
, dst_port
);
1765 void TTCN_Runtime::map_port(
1766 const COMPONENT
& src_compref
, const char *src_port
,
1767 const COMPONENT
& dst_compref
, const char *dst_port
)
1769 check_port_name(src_port
, "map", "first");
1770 check_port_name(dst_port
, "map", "second");
1772 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1773 TTCN_Logger::log_event_str("Mapping port ");
1774 COMPONENT::log_component_reference(src_compref
);
1775 TTCN_Logger::log_event(":%s to ", src_port
);
1776 COMPONENT::log_component_reference(dst_compref
);
1777 TTCN_Logger::log_event(":%s.", dst_port
);
1778 TTCN_Logger::end_event();
1780 if (!src_compref
.is_bound()) TTCN_error("The first argument of map "
1781 "operation contains an unbound component reference.");
1782 component src_component
= src_compref
;
1783 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1784 "map operation contains the null component reference.");
1785 if (!dst_compref
.is_bound()) TTCN_error("The second argument of map "
1786 "operation contains an unbound component reference.");
1787 component dst_component
= dst_compref
;
1788 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1789 "map operation contains the null component reference.");
1791 component comp_reference
;
1792 const char *comp_port
, *system_port
;
1794 if (src_component
== SYSTEM_COMPREF
) {
1795 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1796 "map operation refer to system ports.");
1797 comp_reference
= dst_component
;
1798 comp_port
= dst_port
;
1799 system_port
= src_port
;
1800 } else if (dst_component
== SYSTEM_COMPREF
) {
1801 comp_reference
= src_component
;
1802 comp_port
= src_port
;
1803 system_port
= dst_port
;
1805 TTCN_error("Both arguments of map operation refer to test component "
1807 // to avoid warnings
1811 switch (executor_state
) {
1812 case SINGLE_TESTCASE
:
1813 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1814 "can be mapped in single mode.");
1815 PORT::map_port(comp_port
, system_port
);
1818 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1820 executor_state
= MTC_MAP
;
1821 wait_for_state_change();
1824 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1826 executor_state
= PTC_MAP
;
1827 wait_for_state_change();
1830 if (in_controlpart()) {
1831 TTCN_error("Map operation cannot be performed in the "
1834 TTCN_error("Internal error: Executing map operation "
1835 "in invalid state.");
1839 TTCN_Logger::log_portconnmap(API::ParPort_operation::map__
,
1840 src_compref
, src_port
, dst_compref
, dst_port
);
1843 void TTCN_Runtime::unmap_port(
1844 const COMPONENT
& src_compref
, const char *src_port
,
1845 const COMPONENT
& dst_compref
, const char *dst_port
)
1847 check_port_name(src_port
, "unmap", "first");
1848 check_port_name(dst_port
, "unmap", "second");
1850 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1851 TTCN_Logger::log_event_str("Unmapping port ");
1852 COMPONENT::log_component_reference(src_compref
);
1853 TTCN_Logger::log_event(":%s from ", src_port
);
1854 COMPONENT::log_component_reference(dst_compref
);
1855 TTCN_Logger::log_event(":%s.", dst_port
);
1856 TTCN_Logger::end_event();
1858 if (!src_compref
.is_bound()) TTCN_error("The first argument of unmap "
1859 "operation contains an unbound component reference.");
1860 component src_component
= src_compref
;
1861 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1862 "unmap operation contains the null component reference.");
1863 if (!dst_compref
.is_bound()) TTCN_error("The second argument of unmap "
1864 "operation contains an unbound component reference.");
1865 component dst_component
= dst_compref
;
1866 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1867 "unmap operation contains the null component reference.");
1869 component comp_reference
;
1870 const char *comp_port
, *system_port
;
1872 if (src_component
== SYSTEM_COMPREF
) {
1873 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1874 "unmap operation refer to system ports.");
1875 comp_reference
= dst_component
;
1876 comp_port
= dst_port
;
1877 system_port
= src_port
;
1878 } else if (dst_component
== SYSTEM_COMPREF
) {
1879 comp_reference
= src_component
;
1880 comp_port
= src_port
;
1881 system_port
= dst_port
;
1883 TTCN_error("Both arguments of unmap operation refer to test component "
1885 // to avoid warnings
1889 switch (executor_state
) {
1890 case SINGLE_TESTCASE
:
1891 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1892 "can be unmapped in single mode.");
1893 PORT::unmap_port(comp_port
, system_port
);
1896 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1898 executor_state
= MTC_UNMAP
;
1899 wait_for_state_change();
1902 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1904 executor_state
= PTC_UNMAP
;
1905 wait_for_state_change();
1908 if (in_controlpart()) {
1909 TTCN_error("Unmap operation cannot be performed in the "
1912 TTCN_error("Internal error: Executing unmap operation "
1913 "in invalid state.");
1917 TTCN_Logger::log_portconnmap(API::ParPort_operation::unmap__
,
1918 src_compref
, src_port
, dst_compref
, dst_port
);
1921 void TTCN_Runtime::begin_controlpart(const char *module_name
)
1923 control_module_name
= module_name
;
1924 execute_command(begin_controlpart_command
, module_name
);
1925 TTCN_Logger::log_controlpart_start_stop(module_name
, 0);
1928 void TTCN_Runtime::end_controlpart()
1930 TTCN_Default::deactivate_all();
1931 TTCN_Default::reset_counter();
1933 TTCN_Logger::log_controlpart_start_stop(control_module_name
, 1);
1934 execute_command(end_controlpart_command
, control_module_name
);
1935 control_module_name
= NULL
;
1938 void TTCN_Runtime::check_begin_testcase(boolean has_timer
, double timer_value
)
1940 if (!in_controlpart()) {
1941 if (is_single() || is_mtc()) TTCN_error("Test case cannot be executed "
1942 "while another one (%s.%s) is running.", testcase_name
.module_name
,
1943 testcase_name
.definition_name
);
1944 else if (is_ptc()) TTCN_error("Test case cannot be executed on a PTC.");
1945 else TTCN_error("Internal error: Executing a test case in an invalid "
1948 if (has_timer
&& timer_value
< 0.0) TTCN_error("The test case supervisor "
1949 "timer has negative duration (%g s).", timer_value
);
1952 void TTCN_Runtime::begin_testcase(
1953 const char *par_module_name
, const char *par_testcase_name
,
1954 const char *mtc_comptype_module
, const char *mtc_comptype_name
,
1955 const char *system_comptype_module
, const char *system_comptype_name
,
1956 boolean has_timer
, double timer_value
)
1958 switch (executor_state
) {
1959 case SINGLE_CONTROLPART
:
1960 executor_state
= SINGLE_TESTCASE
;
1962 case MTC_CONTROLPART
:
1963 TTCN_Communication::send_testcase_started(par_module_name
,
1964 par_testcase_name
, mtc_comptype_module
, mtc_comptype_name
,
1965 system_comptype_module
, system_comptype_name
);
1966 executor_state
= MTC_TESTCASE
;
1969 TTCN_error("Internal error: Executing a test case in an invalid "
1972 TIMER::save_control_timers();
1973 TTCN_Default::save_control_defaults();
1974 set_testcase_name(par_module_name
, par_testcase_name
);
1975 char *command_arguments
= mprintf("%s.%s", testcase_name
.module_name
,
1976 testcase_name
.definition_name
);
1977 execute_command(begin_testcase_command
, command_arguments
);
1978 Free(command_arguments
);
1979 TTCN_Logger::log_testcase_started(testcase_name
);
1980 if (has_timer
) testcase_timer
.start(timer_value
);
1981 set_component_type(mtc_comptype_module
, mtc_comptype_name
);
1982 initialize_component_type();
1983 // at the beginning of the testcase no PTCs exist
1984 any_component_done_status
= ALT_NO
;
1985 all_component_done_status
= ALT_YES
;
1986 any_component_killed_status
= ALT_NO
;
1987 all_component_killed_status
= ALT_YES
;
1990 verdicttype
TTCN_Runtime::end_testcase()
1992 switch (executor_state
) {
2002 case MTC_DISCONNECT
:
2005 executor_state
= MTC_TESTCASE
;
2008 case SINGLE_TESTCASE
:
2009 disable_interrupt_handler();
2012 TTCN_error("Internal error: Ending a testcase in an invalid state.");
2014 testcase_timer
.stop();
2015 terminate_component_type();
2016 if (executor_state
== MTC_TESTCASE
) {
2017 TTCN_Logger::log_executor_runtime(
2018 API::ExecutorRuntime_reason::waiting__for__ptcs__to__finish
);
2019 TTCN_Communication::send_testcase_finished(local_verdict
, verdict_reason
);
2020 executor_state
= MTC_TERMINATING_TESTCASE
;
2021 wait_for_state_change();
2022 } else if (executor_state
== SINGLE_TESTCASE
) {
2023 executor_state
= SINGLE_CONTROLPART
;
2024 enable_interrupt_handler();
2026 TTCN_Logger::log_testcase_finished(testcase_name
, local_verdict
,
2028 verdict_count
[local_verdict
]++;
2029 // testcase name should come first for backward compatibility
2030 char *command_arguments
= mprintf("%s.%s %s",
2031 testcase_name
.module_name
, testcase_name
.definition_name
,
2032 verdict_name
[local_verdict
]);
2033 execute_command(end_testcase_command
, command_arguments
);
2034 Free(command_arguments
);
2035 clear_qualified_name(testcase_name
);
2036 // clean up component status caches
2037 clear_component_status_table();
2038 any_component_done_status
= ALT_UNCHECKED
;
2039 all_component_done_status
= ALT_UNCHECKED
;
2040 any_component_killed_status
= ALT_UNCHECKED
;
2041 all_component_killed_status
= ALT_UNCHECKED
;
2042 // restore the control part timers and defaults
2043 TTCN_Default::restore_control_defaults();
2044 TIMER::restore_control_timers();
2045 if (executor_state
== MTC_PAUSED
) {
2046 TTCN_Logger::log_executor_runtime(
2047 API::ExecutorRuntime_reason::user__paused__waiting__to__resume
);
2048 wait_for_state_change();
2049 if (executor_state
!= MTC_TERMINATING_EXECUTION
)
2050 TTCN_Logger::log_executor_runtime(
2051 API::ExecutorRuntime_reason::resuming__execution
);
2053 if (executor_state
== MTC_TERMINATING_EXECUTION
) {
2054 executor_state
= MTC_CONTROLPART
;
2055 TTCN_Logger::log_executor_runtime(
2056 API::ExecutorRuntime_reason::terminating__execution
);
2059 return local_verdict
;
2062 void TTCN_Runtime::log_verdict_statistics()
2064 unsigned int total_testcases
= verdict_count
[NONE
] + verdict_count
[PASS
] +
2065 verdict_count
[INCONC
] + verdict_count
[FAIL
] + verdict_count
[ERROR
];
2067 verdicttype overall_verdict
;
2068 if (control_error_count
> 0 || verdict_count
[ERROR
] > 0)
2069 overall_verdict
= ERROR
;
2070 else if (verdict_count
[FAIL
] > 0) overall_verdict
= FAIL
;
2071 else if (verdict_count
[INCONC
] > 0) overall_verdict
= INCONC
;
2072 else if (verdict_count
[PASS
] > 0) overall_verdict
= PASS
;
2073 else overall_verdict
= NONE
;
2075 if (total_testcases
> 0) {
2076 TTCN_Logger::log_verdict_statistics(verdict_count
[NONE
], (100.0 * verdict_count
[NONE
]) / total_testcases
,
2077 verdict_count
[PASS
], (100.0 * verdict_count
[PASS
]) / total_testcases
,
2078 verdict_count
[INCONC
], (100.0 * verdict_count
[INCONC
]) / total_testcases
,
2079 verdict_count
[FAIL
], (100.0 * verdict_count
[FAIL
]) / total_testcases
,
2080 verdict_count
[ERROR
], (100.0 * verdict_count
[ERROR
]) / total_testcases
);
2082 TTCN_Logger::log_verdict_statistics(0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0);
2085 if (control_error_count
> 0) {
2086 TTCN_Logger::log_controlpart_errors(control_error_count
);
2089 TTCN_Logger::log(TTCN_Logger::STATISTICS_VERDICT
, "Test execution summary: "
2090 "%u test case%s executed. Overall verdict: %s", total_testcases
,
2091 total_testcases
> 1 ? "s were" : " was", verdict_name
[overall_verdict
]);
2093 verdict_count
[NONE
] = 0;
2094 verdict_count
[PASS
] = 0;
2095 verdict_count
[INCONC
] = 0;
2096 verdict_count
[FAIL
] = 0;
2097 verdict_count
[ERROR
] = 0;
2098 control_error_count
= 0;
2101 void TTCN_Runtime::begin_action()
2103 TTCN_Logger::begin_event(TTCN_Logger::ACTION_UNQUALIFIED
);
2104 TTCN_Logger::log_event_str("Action: ");
2107 void TTCN_Runtime::end_action()
2109 TTCN_Logger::end_event();
2112 void TTCN_Runtime::setverdict(verdicttype new_value
, const char* reason
)
2114 if (verdict_enabled()) {
2115 if (new_value
== ERROR
)
2116 TTCN_error("Error verdict cannot be set explicitly.");
2117 setverdict_internal(new_value
, reason
);
2118 } else if (in_controlpart()) {
2119 TTCN_error("Verdict cannot be set in the control part.");
2121 TTCN_error("Internal error: Setting the verdict in invalid state.");
2125 void TTCN_Runtime::setverdict(const VERDICTTYPE
& new_value
, const char* reason
)
2127 if (!new_value
.is_bound()) TTCN_error("The argument of setverdict "
2128 "operation is an unbound verdict value.");
2129 setverdict((verdicttype
)new_value
, reason
);
2132 void TTCN_Runtime::set_error_verdict()
2134 if (verdict_enabled()) setverdict_internal(ERROR
);
2135 else if (is_single() || is_mtc()) control_error_count
++;
2138 verdicttype
TTCN_Runtime::getverdict()
2140 if (verdict_enabled())
2141 TTCN_Logger::log_getverdict(local_verdict
);
2142 else if (in_controlpart()) TTCN_error("Getverdict operation cannot be "
2143 "performed in the control part.");
2144 else TTCN_error("Internal error: Performing getverdict operation in "
2146 return local_verdict
;
2149 void TTCN_Runtime::setverdict_internal(verdicttype new_value
,
2152 if (new_value
< NONE
|| new_value
> ERROR
)
2153 TTCN_error("Internal error: setting an invalid verdict value (%d).",
2155 verdicttype old_verdict
= local_verdict
;
2156 if (local_verdict
< new_value
) {
2157 verdict_reason
= reason
;
2158 local_verdict
= new_value
;
2159 if (reason
== NULL
|| reason
[0] == '\0')
2160 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2161 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2162 } else if (local_verdict
== new_value
) {
2163 if (reason
== NULL
|| reason
[0] == '\0')
2164 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2165 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2167 if (new_value
== FAIL
) {
2168 ttcn3_debugger
.breakpoint_entry(TTCN3_Debugger::SBP_FAIL_VERDICT
);
2170 else if (new_value
== ERROR
) {
2171 ttcn3_debugger
.breakpoint_entry(TTCN3_Debugger::SBP_ERROR_VERDICT
);
2175 void TTCN_Runtime::set_begin_controlpart_command(const char *new_command
)
2177 Free(begin_controlpart_command
);
2178 begin_controlpart_command
= shell_escape(new_command
);
2181 void TTCN_Runtime::set_end_controlpart_command(const char *new_command
)
2183 Free(end_controlpart_command
);
2184 end_controlpart_command
= shell_escape(new_command
);
2187 void TTCN_Runtime::set_begin_testcase_command(const char *new_command
)
2189 Free(begin_testcase_command
);
2190 begin_testcase_command
= shell_escape(new_command
);
2193 void TTCN_Runtime::set_end_testcase_command(const char *new_command
)
2195 Free(end_testcase_command
);
2196 end_testcase_command
= shell_escape(new_command
);
2199 void TTCN_Runtime::clear_external_commands()
2201 Free(begin_controlpart_command
);
2202 begin_controlpart_command
= NULL
;
2203 Free(end_controlpart_command
);
2204 end_controlpart_command
= NULL
;
2205 Free(begin_testcase_command
);
2206 begin_testcase_command
= NULL
;
2207 Free(end_testcase_command
);
2208 end_testcase_command
= NULL
;
2211 char *TTCN_Runtime::shell_escape(const char *command_str
)
2213 if (command_str
== NULL
|| command_str
[0] == '\0') return NULL
;
2214 boolean has_special_char
= FALSE
;
2215 for (int i
= 0; !has_special_char
&& command_str
[i
] != '\0'; i
++) {
2216 switch (command_str
[i
]) {
2238 // special characters interpreted by the shell except '
2239 has_special_char
= TRUE
;
2242 // non-printable characters also need special handling
2243 if (!isprint(command_str
[i
])) has_special_char
= TRUE
;
2246 char *ret_val
= memptystr();
2247 // indicates whether we are in an unclosed ' string
2248 boolean in_apostrophes
= FALSE
;
2249 for (int i
= 0; command_str
[i
] != '\0'; i
++) {
2250 if (command_str
[i
] == '\'') {
2251 if (in_apostrophes
) {
2252 // close the open literal
2253 ret_val
= mputc(ret_val
, '\'');
2254 in_apostrophes
= FALSE
;
2256 // substitute with \'
2257 ret_val
= mputstr(ret_val
, "\\'");
2259 if (has_special_char
&& !in_apostrophes
) {
2261 ret_val
= mputc(ret_val
, '\'');
2262 in_apostrophes
= TRUE
;
2264 // append the single character
2265 ret_val
= mputc(ret_val
, command_str
[i
]);
2268 // close the open literal
2269 if (in_apostrophes
) ret_val
= mputc(ret_val
, '\'');
2273 void TTCN_Runtime::execute_command(const char *command_name
,
2274 const char *argument_string
)
2276 if (command_name
!= NULL
) {
2277 char *command_string
= mprintf("%s %s", command_name
, argument_string
);
2279 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_START
, command_string
);
2280 int return_status
= system(command_string
);
2281 if (return_status
== -1) TTCN_error("Execution of external "
2282 "command `%s' failed.", command_string
);
2283 else if (WIFEXITED(return_status
)) {
2284 int exit_status
= WEXITSTATUS(return_status
);
2285 if (exit_status
== EXIT_SUCCESS
)
2286 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_SUCCESS
, command_string
);
2287 else TTCN_warning("External command `%s' returned "
2288 "unsuccessful exit status (%d).", command_string
,
2290 } else if (WIFSIGNALED(return_status
)) {
2291 int signal_number
= WTERMSIG(return_status
);
2292 TTCN_warning("External command `%s' was terminated by signal "
2293 "%d (%s).", command_string
, signal_number
,
2294 get_signal_name(signal_number
));
2296 TTCN_warning("External command `%s' was terminated by an "
2297 "unknown reason (return status: %d).", command_string
,
2301 // to prevent from memory leaks
2302 Free(command_string
);
2305 Free(command_string
);
2309 void TTCN_Runtime::process_create_mtc()
2311 switch (executor_state
) {
2316 TTCN_Communication::send_error("Message CREATE_MTC arrived in invalid "
2321 // clean Emergency log buffer before fork, to avoid duplication
2322 TTCN_Logger::ring_buffer_dump(false);
2324 pid_t mtc_pid
= fork();
2327 TTCN_Communication::send_create_nak(MTC_COMPREF
, "system call fork() "
2328 "failed (%s)", strerror(errno
));
2329 failed_process_creation();
2330 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2331 TTCN_Logger::log_event_str("System call fork() failed when creating "
2333 TTCN_Logger::OS_error();
2334 TTCN_Logger::end_event();
2335 } else if (mtc_pid
> 0) {
2336 // fork() was successful, this code runs on the parent process (HC)
2337 TTCN_Logger::log_mtc_created(mtc_pid
);
2338 add_component(MTC_COMPREF
, mtc_pid
);
2339 successful_process_creation();
2340 // let the HC's TTCN-3 Profiler know of the MTC
2341 ttcn3_prof
.add_child_process(mtc_pid
);
2343 // fork() was successful, this code runs on the child process (MTC)
2344 // The inherited epoll fd has to be closed first, and then the mc fd
2345 // (The inherited epoll fd shares its database with the parent process.)
2346 Fd_And_Timeout_User::reopenEpollFd();
2347 TTCN_Communication::close_mc_connection();
2349 executor_state
= MTC_INITIAL
;
2353 void TTCN_Runtime::process_create_ptc(component component_reference
,
2354 const char *component_type_module
, const char *component_type_name
,
2355 const char *par_component_name
, boolean par_is_alive
,
2356 const char *current_testcase_module
, const char *current_testcase_name
)
2358 switch (executor_state
) {
2363 TTCN_Communication::send_error("Message CREATE_PTC arrived in invalid "
2368 // clean Emergency log buffer before fork, to avoid duplication
2369 TTCN_Logger::ring_buffer_dump(false);
2371 pid_t ptc_pid
= fork();
2374 TTCN_Communication::send_create_nak(component_reference
, "system call "
2375 "fork() failed (%s)", strerror(errno
));
2376 failed_process_creation();
2377 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2378 TTCN_Logger::log_event("System call fork() failed when creating PTC "
2379 "with component reference %d.", component_reference
);
2380 TTCN_Logger::OS_error();
2381 TTCN_Logger::end_event();
2382 } else if (ptc_pid
> 0) {
2383 // fork() was successful, this code runs on the parent process (HC)
2384 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created__pid
,
2385 component_type_module
, component_type_name
, component_reference
,
2386 par_component_name
, current_testcase_name
, ptc_pid
);
2387 add_component(component_reference
, ptc_pid
);
2388 COMPONENT::register_component_name(component_reference
,
2389 par_component_name
);
2390 successful_process_creation();
2391 // let the HC's TTCN-3 Profiler know of this new PTC
2392 ttcn3_prof
.add_child_process(ptc_pid
);
2394 // fork() was successful, this code runs on the child process (PTC)
2395 // The inherited epoll fd has to be closed first, and then the mc fd
2396 // (The inherited epoll fd shares its database with the parent process.)
2397 Fd_And_Timeout_User::reopenEpollFd();
2398 TTCN_Communication::close_mc_connection();
2399 self
= component_reference
;
2400 set_component_type(component_type_module
, component_type_name
);
2401 set_component_name(par_component_name
);
2402 is_alive
= par_is_alive
;
2403 set_testcase_name(current_testcase_module
, current_testcase_name
);
2404 executor_state
= PTC_INITIAL
;
2408 void TTCN_Runtime::process_create_ack(component new_component
)
2410 switch (executor_state
) {
2412 executor_state
= MTC_TESTCASE
;
2413 case MTC_TERMINATING_TESTCASE
:
2416 executor_state
= PTC_FUNCTION
;
2419 TTCN_error("Internal error: Message CREATE_ACK arrived in invalid "
2422 create_done_killed_compref
= new_component
;
2425 void TTCN_Runtime::process_running(boolean result_value
)
2427 switch (executor_state
) {
2429 executor_state
= MTC_TESTCASE
;
2430 case MTC_TERMINATING_TESTCASE
:
2433 executor_state
= PTC_FUNCTION
;
2436 TTCN_error("Internal error: Message RUNNING arrived in invalid state.");
2438 running_alive_result
= result_value
;
2441 void TTCN_Runtime::process_alive(boolean result_value
)
2443 switch (executor_state
) {
2445 executor_state
= MTC_TESTCASE
;
2446 case MTC_TERMINATING_TESTCASE
:
2449 executor_state
= PTC_FUNCTION
;
2452 TTCN_error("Internal error: Message ALIVE arrived in invalid state.");
2454 running_alive_result
= result_value
;
2457 void TTCN_Runtime::process_done_ack(boolean done_status
,
2458 const char *return_type
, int return_value_len
, const void *return_value
)
2460 switch (executor_state
) {
2462 executor_state
= MTC_TESTCASE
;
2463 case MTC_TERMINATING_TESTCASE
:
2466 executor_state
= PTC_FUNCTION
;
2469 TTCN_error("Internal error: Message DONE_ACK arrived in invalid "
2472 if (done_status
) set_component_done(create_done_killed_compref
,
2473 return_type
, return_value_len
, return_value
);
2474 create_done_killed_compref
= NULL_COMPREF
;
2477 void TTCN_Runtime::process_killed_ack(boolean killed_status
)
2479 switch (executor_state
) {
2481 executor_state
= MTC_TESTCASE
;
2482 case MTC_TERMINATING_TESTCASE
:
2485 executor_state
= PTC_FUNCTION
;
2488 TTCN_error("Internal error: Message KILLED_ACK arrived in invalid "
2491 if (killed_status
) set_component_killed(create_done_killed_compref
);
2492 create_done_killed_compref
= NULL_COMPREF
;
2495 void TTCN_Runtime::process_ptc_verdict(Text_Buf
& text_buf
)
2497 if (executor_state
!= MTC_TERMINATING_TESTCASE
)
2498 TTCN_error("Internal error: Message PTC_VERDICT arrived in invalid state.");
2500 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2501 local_verdict
, (const char *)verdict_reason
,
2502 TitanLoggerApi::FinalVerdictType_choice_notification::setting__final__verdict__of__the__test__case
);
2503 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2504 local_verdict
, (const char *)verdict_reason
);
2505 int n_ptcs
= text_buf
.pull_int().get_val();
2507 for (int i
= 0; i
< n_ptcs
; i
++) {
2508 component ptc_compref
= text_buf
.pull_int().get_val();
2509 char *ptc_name
= text_buf
.pull_string();
2510 verdicttype ptc_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
2511 char *ptc_verdict_reason
= text_buf
.pull_string();
2512 if (ptc_verdict
< NONE
|| ptc_verdict
> ERROR
) {
2514 TTCN_error("Internal error: Invalid PTC verdict was "
2515 "received from MC: %d.", ptc_verdict
);
2517 verdicttype new_verdict
= local_verdict
;
2518 if (ptc_verdict
> local_verdict
) {
2519 new_verdict
= ptc_verdict
;
2520 verdict_reason
= CHARSTRING(ptc_verdict_reason
);
2522 TTCN_Logger::log_final_verdict(true, ptc_verdict
, local_verdict
,
2523 new_verdict
, ptc_verdict_reason
, -1, ptc_compref
, ptc_name
);
2525 delete [] ptc_verdict_reason
;
2526 local_verdict
= new_verdict
;
2529 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2530 local_verdict
, (const char *)verdict_reason
,
2531 TitanLoggerApi::FinalVerdictType_choice_notification::no__ptcs__were__created
);
2534 boolean continue_execution
= (boolean
)text_buf
.pull_int().get_val();
2535 if (continue_execution
) executor_state
= MTC_CONTROLPART
;
2536 else executor_state
= MTC_PAUSED
;
2539 void TTCN_Runtime::process_kill()
2542 TTCN_error("Internal error: Message KILL arrived in invalid state.");
2543 switch (executor_state
) {
2546 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::kill__request__frm__mc
);
2547 // This may affect the final verdict.
2548 terminate_component_type();
2549 // Send a KILLED message so that the value returned by previous behaviour
2550 // function remains active.
2551 TTCN_Communication::send_killed(local_verdict
);
2552 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
2553 local_verdict
, (const char *)verdict_reason
);
2554 executor_state
= PTC_EXIT
;
2558 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2559 "Kill was requested from MC.");
2564 void TTCN_Runtime::process_kill_process(component component_reference
)
2566 if (!is_hc()) TTCN_error("Internal error: Message KILL_PROCESS arrived "
2567 "in invalid state.");
2568 component_process_struct
*comp
=
2569 get_component_by_compref(component_reference
);
2571 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2572 "Killing component with component reference %d, process id: %ld.",
2573 component_reference
, (long)comp
->process_id
);
2574 if (comp
->process_killed
) TTCN_warning("Process with process id %ld "
2575 "has been already killed. Killing it again.",
2576 (long)comp
->process_id
);
2577 if (kill(comp
->process_id
, SIGKILL
)) {
2578 if (errno
== ESRCH
) {
2580 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2581 "Process with process id %ld has already terminated.", (long)comp
->process_id
);
2582 } else TTCN_error("kill() system call failed on process id %ld.",
2583 (long)comp
->process_id
);
2585 comp
->process_killed
= TRUE
;
2587 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2588 "Component with component reference %d does not exist. "
2589 "Request for killing was ignored.", component_reference
);
2593 void TTCN_Runtime::set_component_done(component component_reference
,
2594 const char *return_type
, int return_value_len
,
2595 const void *return_value
)
2597 switch (component_reference
) {
2599 if (is_mtc()) any_component_done_status
= ALT_YES
;
2600 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2601 "ANY_COMPREF): can be used only on MTC.");
2604 if (is_mtc()) all_component_done_status
= ALT_YES
;
2605 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2606 "ALL_COMPREF): can be used only on MTC.");
2610 case SYSTEM_COMPREF
:
2611 TTCN_error("Internal error: TTCN_Runtime::set_component_done: "
2612 "invalid component reference: %d.", component_reference
);
2615 int index
= get_component_status_table_index(component_reference
);
2616 component_status_table
[index
].done_status
= ALT_YES
;
2617 Free(component_status_table
[index
].return_type
);
2618 delete component_status_table
[index
].return_value
;
2619 if (return_type
!= NULL
&& return_type
[0] != '\0') {
2620 component_status_table
[index
].return_type
= mcopystr(return_type
);
2621 component_status_table
[index
].return_value
= new Text_Buf
;
2622 component_status_table
[index
].return_value
->push_raw(
2623 return_value_len
, return_value
);
2625 component_status_table
[index
].return_type
= NULL
;
2626 component_status_table
[index
].return_value
= NULL
;
2632 void TTCN_Runtime::set_component_killed(component component_reference
)
2634 switch (component_reference
) {
2636 if (is_mtc()) any_component_killed_status
= ALT_YES
;
2637 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2638 "ANY_COMPREF): can be used only on MTC.");
2641 if (is_mtc()) all_component_killed_status
= ALT_YES
;
2642 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2643 "ALL_COMPREF): can be used only on MTC.");
2647 case SYSTEM_COMPREF
:
2648 TTCN_error("Internal error: TTCN_Runtime::set_component_killed: "
2649 "invalid component reference: %d.", component_reference
);
2651 component_status_table
[get_component_status_table_index(
2652 component_reference
)].killed_status
= ALT_YES
;
2656 void TTCN_Runtime::cancel_component_done(component component_reference
)
2658 switch (component_reference
) {
2660 if (is_mtc()) any_component_done_status
= ALT_UNCHECKED
;
2661 else TTCN_error("Internal error: TTCN_Runtime::cancel_component_done("
2662 "ANY_COMPREF): can be used only on MTC.");
2667 case SYSTEM_COMPREF
:
2668 TTCN_error("Internal error: TTCN_Runtime::cancel_component_done: "
2669 "invalid component reference: %d.", component_reference
);
2671 if (in_component_status_table(component_reference
)) {
2672 int index
= get_component_status_table_index(component_reference
);
2673 component_status_table
[index
].done_status
= ALT_UNCHECKED
;
2674 Free(component_status_table
[index
].return_type
);
2675 component_status_table
[index
].return_type
= NULL
;
2676 delete component_status_table
[index
].return_value
;
2677 component_status_table
[index
].return_value
= NULL
;
2682 int TTCN_Runtime::get_component_status_table_index(
2683 component component_reference
)
2685 if (component_reference
< FIRST_PTC_COMPREF
) {
2686 TTCN_error("Internal error: TTCN_Runtime::"
2687 "get_component_status_table_index: invalid component reference: "
2688 "%d.", component_reference
);
2690 if (component_status_table_size
== 0) {
2691 // the table is empty
2692 // this will be the first entry
2693 component_status_table
= (component_status_table_struct
*)
2694 Malloc(sizeof(*component_status_table
));
2695 component_status_table
[0].done_status
= ALT_UNCHECKED
;
2696 component_status_table
[0].killed_status
= ALT_UNCHECKED
;
2697 component_status_table
[0].return_type
= NULL
;
2698 component_status_table
[0].return_value
= NULL
;
2699 component_status_table_size
= 1;
2700 component_status_table_offset
= component_reference
;
2702 } else if (component_reference
>= component_status_table_offset
) {
2703 // the table contains at least one entry that is smaller than
2704 // component_reference
2705 int component_index
=
2706 component_reference
- component_status_table_offset
;
2707 if (component_index
>= component_status_table_size
) {
2708 // component_reference is still not in the table
2709 // the table has to be extended at the end
2710 component_status_table
= (component_status_table_struct
*)
2711 Realloc(component_status_table
,
2712 (component_index
+ 1) * sizeof(*component_status_table
));
2713 // initializing the new table entries at the end
2714 for (int i
= component_status_table_size
;
2715 i
<= component_index
; i
++) {
2716 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2717 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2718 component_status_table
[i
].return_type
= NULL
;
2719 component_status_table
[i
].return_value
= NULL
;
2721 component_status_table_size
= component_index
+ 1;
2723 return component_index
;
2725 // component_reference has to be inserted before the existing table
2726 int offset_diff
= component_status_table_offset
- component_reference
;
2727 // offset_diff indicates how many new elements have to be inserted
2728 // before the existing table
2729 int new_size
= component_status_table_size
+ offset_diff
;
2730 component_status_table
= (component_status_table_struct
*)
2731 Realloc(component_status_table
,
2732 new_size
* sizeof(*component_status_table
));
2733 // moving forward the existing table
2734 memmove(component_status_table
+ offset_diff
, component_status_table
,
2735 component_status_table_size
* sizeof(*component_status_table
));
2736 // initializing the first table entries
2737 for (int i
= 0; i
< offset_diff
; i
++) {
2738 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2739 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2740 component_status_table
[i
].return_type
= NULL
;
2741 component_status_table
[i
].return_value
= NULL
;
2743 component_status_table_size
= new_size
;
2744 component_status_table_offset
= component_reference
;
2749 alt_status
TTCN_Runtime::get_killed_status(component component_reference
)
2751 return component_status_table
2752 [get_component_status_table_index(component_reference
)].killed_status
;
2755 boolean
TTCN_Runtime::in_component_status_table(component component_reference
)
2757 return component_reference
>= component_status_table_offset
&&
2758 component_reference
<
2759 component_status_table_size
+ component_status_table_offset
;
2762 void TTCN_Runtime::clear_component_status_table()
2764 for (component i
= 0; i
< component_status_table_size
; i
++) {
2765 Free(component_status_table
[i
].return_type
);
2766 delete component_status_table
[i
].return_value
;
2768 Free(component_status_table
);
2769 component_status_table
= NULL
;
2770 component_status_table_size
= 0;
2771 component_status_table_offset
= FIRST_PTC_COMPREF
;
2774 #define HASHTABLE_SIZE 97
2776 void TTCN_Runtime::initialize_component_process_tables()
2778 components_by_compref
= new component_process_struct
*[HASHTABLE_SIZE
];
2779 components_by_pid
= new component_process_struct
*[HASHTABLE_SIZE
];
2780 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2781 components_by_compref
[i
] = NULL
;
2782 components_by_pid
[i
] = NULL
;
2786 void TTCN_Runtime::add_component(component component_reference
,
2789 if (component_reference
!= MTC_COMPREF
&&
2790 get_component_by_compref(component_reference
) != NULL
)
2791 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2792 "duplicated component reference (%d)", component_reference
);
2793 if (get_component_by_pid(process_id
) != NULL
)
2794 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2795 "duplicated pid (%ld)", (long)process_id
);
2797 component_process_struct
*new_comp
= new component_process_struct
;
2798 new_comp
->component_reference
= component_reference
;
2799 new_comp
->process_id
= process_id
;
2800 new_comp
->process_killed
= FALSE
;
2802 new_comp
->prev_by_compref
= NULL
;
2803 component_process_struct
*& head_by_compref
=
2804 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2805 new_comp
->next_by_compref
= head_by_compref
;
2806 if (head_by_compref
!= NULL
) head_by_compref
->prev_by_compref
= new_comp
;
2807 head_by_compref
= new_comp
;
2809 new_comp
->prev_by_pid
= NULL
;
2810 component_process_struct
*& head_by_pid
=
2811 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2812 new_comp
->next_by_pid
= head_by_pid
;
2813 if (head_by_pid
!= NULL
) head_by_pid
->prev_by_pid
= new_comp
;
2814 head_by_pid
= new_comp
;
2817 void TTCN_Runtime::remove_component(component_process_struct
*comp
)
2819 if (comp
->next_by_compref
!= NULL
)
2820 comp
->next_by_compref
->prev_by_compref
= comp
->prev_by_compref
;
2821 if (comp
->prev_by_compref
!= NULL
)
2822 comp
->prev_by_compref
->next_by_compref
= comp
->next_by_compref
;
2823 else components_by_compref
[comp
->component_reference
% HASHTABLE_SIZE
] =
2824 comp
->next_by_compref
;
2825 if (comp
->next_by_pid
!= NULL
)
2826 comp
->next_by_pid
->prev_by_pid
= comp
->prev_by_pid
;
2827 if (comp
->prev_by_pid
!= NULL
)
2828 comp
->prev_by_pid
->next_by_pid
= comp
->next_by_pid
;
2829 else components_by_pid
[comp
->process_id
% HASHTABLE_SIZE
] =
2834 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_compref(
2835 component component_reference
)
2837 component_process_struct
*iter
=
2838 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2839 while (iter
!= NULL
) {
2840 if (iter
->component_reference
== component_reference
) break;
2841 iter
= iter
->next_by_compref
;
2846 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_pid(
2849 component_process_struct
*iter
=
2850 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2851 while (iter
!= NULL
) {
2852 if (iter
->process_id
== process_id
) break;
2853 iter
= iter
->next_by_pid
;
2858 void TTCN_Runtime::clear_component_process_tables()
2860 if (components_by_compref
== NULL
) return;
2861 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2862 while (components_by_compref
[i
] != NULL
)
2863 remove_component(components_by_compref
[i
]);
2864 while (components_by_pid
[i
] != NULL
)
2865 remove_component(components_by_pid
[i
]);
2867 delete [] components_by_compref
;
2868 components_by_compref
= NULL
;
2869 delete [] components_by_pid
;
2870 components_by_pid
= NULL
;
2873 void TTCN_Runtime::successful_process_creation()
2875 if (is_overloaded()) {
2876 TTCN_Communication::send_hc_ready();
2877 TTCN_Communication::disable_periodic_call();
2878 executor_state
= HC_ACTIVE
;
2882 void TTCN_Runtime::failed_process_creation()
2884 if (executor_state
== HC_ACTIVE
) {
2885 TTCN_Communication::enable_periodic_call();
2886 executor_state
= HC_OVERLOADED
;
2890 void TTCN_Runtime::wait_terminated_processes()
2892 // this function might be called from TCs too while returning from
2893 // TTCN_Communication::process_all_messages_hc() after fork()
2894 if (!is_hc()) return;
2899 struct rusage r_usage
= {{0,0},{0,0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}};
2901 struct rusage r_usage
= {{0,0},{0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2905 pid_t child_pid
= waitpid(-1, &statuscode
, WNOHANG
);
2906 getrusage(RUSAGE_CHILDREN
, &r_usage
);
2908 pid_t child_pid
= wait3(&statuscode
, WNOHANG
, &r_usage
);
2910 if (child_pid
<= 0) {
2918 TTCN_error("System call wait3() failed when waiting for "
2919 "terminated test component processes.");
2922 component_process_struct
*comp
= get_component_by_pid(child_pid
);
2925 const char *comp_name
= NULL
;
2926 if (comp
->component_reference
== MTC_COMPREF
) {
2927 reason
= API::ParallelPTC_reason::mtc__finished
;
2930 reason
= API::ParallelPTC_reason::ptc__finished
;
2931 comp_name
= COMPONENT::get_component_name(comp
->component_reference
);
2933 char *rusage
= NULL
;
2935 "user time: %ld.%06ld s, system time: %ld.%06ld s, "
2936 "maximum resident set size: %ld, "
2937 "integral resident set size: %ld, "
2938 "page faults not requiring physical I/O: %ld, "
2939 "page faults requiring physical I/O: %ld, "
2941 "block input operations: %ld, block output operations: %ld, "
2942 "messages sent: %ld, messages received: %ld, "
2943 "signals received: %ld, "
2944 "voluntary context switches: %ld, "
2945 "involuntary context switches: %ld }",
2946 (long)r_usage
.ru_utime
.tv_sec
, r_usage
.ru_utime
.tv_usec
,
2947 (long)r_usage
.ru_stime
.tv_sec
, r_usage
.ru_stime
.tv_usec
,
2948 r_usage
.ru_maxrss
, r_usage
.ru_idrss
,
2949 r_usage
.ru_minflt
, r_usage
.ru_majflt
, r_usage
.ru_nswap
,
2950 r_usage
.ru_inblock
, r_usage
.ru_oublock
,
2951 r_usage
.ru_msgsnd
, r_usage
.ru_msgrcv
, r_usage
.ru_nsignals
,
2952 r_usage
.ru_nvcsw
, r_usage
.ru_nivcsw
);
2953 // There are too many different integer types in the rusage structure.
2954 // Just format them into a string and and pass that to the logger.
2955 TTCN_Logger::log_par_ptc(reason
, NULL
, NULL
,
2956 comp
->component_reference
, comp_name
, rusage
, child_pid
, statuscode
);
2958 remove_component(comp
);
2960 TTCN_warning("wait3() system call returned unknown process id %ld.",
2966 void TTCN_Runtime::check_overload()
2968 if (!is_hc()) TTCN_error("Internal error: TTCN_Runtime::check_overload() "
2969 "can be used on HCs only.");
2970 if (!is_overloaded()) return;
2971 TTCN_Logger::log_executor_runtime(
2972 API::ExecutorRuntime_reason::overload__check
);
2973 pid_t child_pid
= fork();
2974 if (child_pid
< 0) {
2975 // fork failed, the host is still overloaded
2976 TTCN_Logger::log_executor_runtime(
2977 API::ExecutorRuntime_reason::overload__check__fail
);
2978 //TODO TTCN_Logger::OS_error();
2979 if (executor_state
== HC_OVERLOADED_TIMEOUT
) {
2980 // increase the call interval if the function was called because of
2982 TTCN_Communication::increase_call_interval();
2983 executor_state
= HC_OVERLOADED
;
2985 } else if (child_pid
> 0) {
2986 // fork was successful, this code runs on the parent process (HC)
2988 // wait until the dummy child terminates
2989 pid_t result_pid
= waitpid(child_pid
, &statuscode
, 0);
2990 if (result_pid
!= child_pid
) TTCN_error("System call waitpid() "
2991 "returned unexpected status code %ld when waiting for the dummy "
2992 "child process with PID %ld.", (long)result_pid
, (long)child_pid
);
2993 successful_process_creation();
2994 TTCN_Logger::log_executor_runtime(
2995 API::ExecutorRuntime_reason::overloaded__no__more
);
2996 // FIXME pid is not logged; it would need a separate function
2998 // analyze the status code and issue a warning if something strange
3000 if (WIFEXITED(statuscode
)) {
3001 int exitstatus
= WEXITSTATUS(statuscode
);
3002 if (exitstatus
!= EXIT_SUCCESS
) TTCN_warning("Dummy child process "
3003 "with PID %ld returned unsuccessful exit status (%d).",
3004 (long)child_pid
, exitstatus
);
3005 } else if (WIFSIGNALED(statuscode
)) {
3006 int signum
= WTERMSIG(statuscode
);
3007 TTCN_warning("Dummy child process with PID %ld was terminated by "
3008 "signal %d (%s).", (long)child_pid
, signum
,
3009 get_signal_name(signum
));
3011 TTCN_warning("Dummy child process with PID %ld was terminated by "
3012 "an unknown reason (return status: %d).", (long)child_pid
,
3015 // try to clean up some more zombies if possible
3016 wait_terminated_processes();
3018 // fork was successful, this code runs on the dummy child process
3019 // the dummy child process shall exit immediately