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
19 * Szabo, Janos Zoltan – initial implementation
20 * Zalanyi, Balazs Andor
23 ******************************************************************************/
24 #if defined(LINUX) && ! defined(_GNU_SOURCE)
25 // in order to get the prototype of non-standard strsignal()
35 #include <sys/types.h>
38 #include <sys/resource.h>
41 #include <sys/utsname.h>
44 #include "../common/memory.h"
45 #include "../common/version_internal.h"
47 #include "Communication.hh"
50 #include "Snapshot.hh"
53 #include "Module_list.hh"
54 #include "Component.hh"
56 #include "Verdicttype.hh"
57 #include "Charstring.hh"
58 #include "Fd_And_Timeout_User.hh"
59 #include <TitanLoggerApi.hh>
60 #include "Profiler.hh"
62 namespace API
= TitanLoggerApi
;
64 #ifndef MAXHOSTNAMELEN
65 # define MAXHOSTNAMELEN 256
68 #include "../common/dbgnew.hh"
70 TTCN_Runtime::executor_state_enum
71 TTCN_Runtime::executor_state
= UNDEFINED_STATE
;
73 qualified_name
TTCN_Runtime::component_type
= { NULL
, NULL
};
74 char *TTCN_Runtime::component_name
= NULL
;
75 boolean
TTCN_Runtime::is_alive
= FALSE
;
77 const char *TTCN_Runtime::control_module_name
= NULL
;
78 qualified_name
TTCN_Runtime::testcase_name
= { NULL
, NULL
};
80 char *TTCN_Runtime::host_name
= NULL
;
82 verdicttype
TTCN_Runtime::local_verdict
= NONE
;
83 unsigned int TTCN_Runtime::verdict_count
[5] = { 0, 0, 0, 0, 0 },
84 TTCN_Runtime::control_error_count
= 0;
85 CHARSTRING
TTCN_Runtime::verdict_reason(0, ""); // empty string
87 boolean
TTCN_Runtime::in_ttcn_try_block
= FALSE
;
89 char *TTCN_Runtime::begin_controlpart_command
= NULL
,
90 *TTCN_Runtime::end_controlpart_command
= NULL
,
91 *TTCN_Runtime::begin_testcase_command
= NULL
,
92 *TTCN_Runtime::end_testcase_command
= NULL
;
94 component
TTCN_Runtime::create_done_killed_compref
= NULL_COMPREF
;
95 boolean
TTCN_Runtime::running_alive_result
= FALSE
;
97 alt_status
TTCN_Runtime::any_component_done_status
= ALT_UNCHECKED
,
98 TTCN_Runtime::all_component_done_status
= ALT_UNCHECKED
,
99 TTCN_Runtime::any_component_killed_status
= ALT_UNCHECKED
,
100 TTCN_Runtime::all_component_killed_status
= ALT_UNCHECKED
;
101 int TTCN_Runtime::component_status_table_size
= 0;
102 component
TTCN_Runtime::component_status_table_offset
= FIRST_PTC_COMPREF
;
103 struct TTCN_Runtime::component_status_table_struct
{
104 alt_status done_status
, killed_status
;
106 Text_Buf
*return_value
;
107 } *TTCN_Runtime::component_status_table
= NULL
;
109 struct TTCN_Runtime::component_process_struct
{
110 component component_reference
;
112 boolean process_killed
;
113 struct component_process_struct
*prev_by_compref
, *next_by_compref
;
114 struct component_process_struct
*prev_by_pid
, *next_by_pid
;
115 } **TTCN_Runtime::components_by_compref
= NULL
,
116 **TTCN_Runtime::components_by_pid
= NULL
;
118 boolean
TTCN_Runtime::is_idle()
120 switch (executor_state
) {
133 boolean
TTCN_Runtime::verdict_enabled()
135 return executor_state
== SINGLE_TESTCASE
||
136 (executor_state
>= MTC_TESTCASE
&& executor_state
<= MTC_EXIT
) ||
137 (executor_state
>= PTC_INITIAL
&& executor_state
<= PTC_EXIT
);
140 void TTCN_Runtime::wait_for_state_change()
142 executor_state_enum old_state
= executor_state
;
144 TTCN_Snapshot::take_new(TRUE
);
145 } while (old_state
== executor_state
);
148 void TTCN_Runtime::clear_qualified_name(qualified_name
& q_name
)
150 Free(q_name
.module_name
);
151 q_name
.module_name
= NULL
;
152 Free(q_name
.definition_name
);
153 q_name
.definition_name
= NULL
;
156 void TTCN_Runtime::clean_up()
158 clear_qualified_name(component_type
);
159 Free(component_name
);
160 component_name
= NULL
;
161 control_module_name
= NULL
;
162 clear_qualified_name(testcase_name
);
165 clear_external_commands();
168 void TTCN_Runtime::initialize_component_type()
170 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__start
,
171 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
172 TTCN_Runtime::get_testcase_name());
174 Module_List::initialize_component(component_type
.module_name
,
175 component_type
.definition_name
, TRUE
);
176 PORT::set_parameters((component
)self
, component_name
);
179 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::init__component__finish
,
180 component_type
.module_name
, component_type
.definition_name
);
182 local_verdict
= NONE
;
186 void TTCN_Runtime::terminate_component_type()
188 if (component_type
.module_name
!= NULL
&&
189 component_type
.definition_name
!= NULL
) {
190 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::terminating__component
,
191 component_type
.module_name
, component_type
.definition_name
);
193 TTCN_Default::deactivate_all();
195 PORT::deactivate_all();
197 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::component__shut__down
,
198 component_type
.module_name
, component_type
.definition_name
, 0, NULL
,
199 TTCN_Runtime::get_testcase_name());
201 clear_qualified_name(component_type
);
202 Free(component_name
);
203 component_name
= NULL
;
207 void TTCN_Runtime::set_component_type(const char *component_type_module
,
208 const char *component_type_name
)
210 if (component_type_module
== NULL
|| component_type_module
[0] == '\0' ||
211 component_type_name
== NULL
|| component_type_name
[0] == '\0')
212 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
213 "Trying to set an invalid component type.");
214 if (component_type
.module_name
!= NULL
||
215 component_type
.definition_name
!= NULL
)
216 TTCN_error("Internal error: TTCN_Runtime::set_component_type: "
217 "Trying to set component type %s.%s while another one is active.",
218 component_type_module
, component_type_name
);
220 component_type
.module_name
= mcopystr(component_type_module
);
221 component_type
.definition_name
= mcopystr(component_type_name
);
224 void TTCN_Runtime::set_component_name(const char *new_component_name
)
226 Free(component_name
);
227 if (new_component_name
!= NULL
&& new_component_name
[0] != '\0')
228 component_name
= mcopystr(new_component_name
);
229 else component_name
= NULL
;
232 void TTCN_Runtime::set_testcase_name(const char *par_module_name
,
233 const char *par_testcase_name
)
235 if (par_module_name
== NULL
|| par_module_name
[0] == '\0' ||
236 par_testcase_name
== NULL
|| par_testcase_name
[0] == '\0')
237 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
238 "Trying to set an invalid testcase name.");
239 if (testcase_name
.module_name
!= NULL
||
240 testcase_name
.definition_name
!= NULL
)
241 TTCN_error("Internal error: TTCN_Runtime::set_testcase_name: "
242 "Trying to set testcase name %s.%s while another one is active.",
243 par_module_name
, par_testcase_name
);
245 testcase_name
.module_name
= mcopystr(par_module_name
);
246 testcase_name
.definition_name
= mcopystr(par_testcase_name
);
249 const char *TTCN_Runtime::get_host_name()
251 if (host_name
== NULL
) {
252 #if defined(SOLARIS8)
253 // Workaround for Solaris10 (lumped under SOLARIS8) + dynamic linking.
254 // "g++ -shared" seems to produce a very strange kind of symbol
255 // for gethostname in the .so, and linking fails with the infamous
256 // "ld: libttcn3-dynamic.so: gethostname: invalid version 3 (max 0)"
257 // The workaround is to use uname instead of gethostname.
259 if (uname(&uts
) < 0) {
260 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
261 TTCN_Logger::log_event_str("System call uname() failed.");
262 TTCN_Logger::OS_error();
263 TTCN_Logger::end_event();
264 host_name
= mcopystr("unknown");
266 host_name
= mcopystr(uts
.nodename
);
269 char tmp_str
[MAXHOSTNAMELEN
+ 1];
270 if (gethostname(tmp_str
, MAXHOSTNAMELEN
)) {
271 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED
);
272 TTCN_Logger::log_event_str("System call gethostname() failed.");
273 TTCN_Logger::OS_error();
274 TTCN_Logger::end_event();
276 } else tmp_str
[MAXHOSTNAMELEN
] = '\0';
277 if (tmp_str
[0] != '\0') host_name
= mcopystr(tmp_str
);
278 else host_name
= mcopystr("unknown");
284 CHARSTRING
TTCN_Runtime::get_testcase_id_macro()
286 if (in_controlpart()) TTCN_error("Macro %%testcaseId cannot be used from "
287 "the control part outside test cases.");
288 if (testcase_name
.definition_name
== NULL
||
289 testcase_name
.definition_name
[0] == '\0')
290 TTCN_error("Internal error: Evaluating macro %%testcaseId, but the "
291 "name of the current testcase is not set.");
292 return CHARSTRING(testcase_name
.definition_name
);
295 CHARSTRING
TTCN_Runtime::get_testcasename()
297 if (in_controlpart() || is_hc()) return CHARSTRING(""); // No error here.
299 if (!testcase_name
.definition_name
|| testcase_name
.definition_name
[0] == 0)
300 TTCN_error("Internal error: Evaluating predefined function testcasename()"
301 ", but the name of the current testcase is not set.");
303 return CHARSTRING(testcase_name
.definition_name
);
306 void TTCN_Runtime::load_logger_plugins()
308 TTCN_Logger::load_plugins((component
)self
, component_name
);
311 void TTCN_Runtime::set_logger_parameters()
313 TTCN_Logger::set_plugin_parameters((component
)self
, component_name
);
316 const char *TTCN_Runtime::get_signal_name(int signal_number
)
318 const char *signal_name
= strsignal(signal_number
);
319 if (signal_name
!= NULL
) return signal_name
;
320 else return "Unknown signal";
323 static void sigint_handler(int signum
)
325 if (signum
!= SIGINT
) {
326 TTCN_warning("Unexpected signal %d (%s) was caught by the handler of "
327 "SIGINT.", signum
, TTCN_Runtime::get_signal_name(signum
));
330 if (TTCN_Runtime::is_single()) {
331 TTCN_Logger::log_str(TTCN_Logger::WARNING_UNQUALIFIED
,
332 "Execution was interrupted by the user.");
333 if (TTCN_Runtime::get_state() == TTCN_Runtime::SINGLE_TESTCASE
) {
334 TTCN_Logger::log_executor_runtime(
335 API::ExecutorRuntime_reason::stopping__current__testcase
);
336 TTCN_Runtime::end_testcase();
340 TTCN_Logger::log_executor_runtime(
341 API::ExecutorRuntime_reason::exiting
);
347 void TTCN_Runtime::set_signal_handler(int signal_number
,
348 const char *signal_name
, signal_handler_type signal_handler
)
350 struct sigaction sig_act
;
351 if (sigaction(signal_number
, NULL
, &sig_act
))
352 TTCN_error("System call sigaction() failed when getting signal "
353 "handling information for %s.", signal_name
);
354 sig_act
.sa_handler
= signal_handler
;
355 sig_act
.sa_flags
= 0;
356 if (sigaction(signal_number
, &sig_act
, NULL
))
357 TTCN_error("System call sigaction() failed when changing the signal "
358 "handling settings for %s.", signal_name
);
361 void TTCN_Runtime::restore_default_handler(int signal_number
,
362 const char *signal_name
)
364 struct sigaction sig_act
;
365 if (sigaction(signal_number
, NULL
, &sig_act
))
366 TTCN_error("System call sigaction() failed when getting signal "
367 "handling information for %s.", signal_name
);
368 sig_act
.sa_handler
= SIG_DFL
;
369 sig_act
.sa_flags
= 0;
370 if (sigaction(signal_number
, &sig_act
, NULL
))
371 TTCN_error("System call sigaction() failed when restoring the "
372 "default signal handling settings for %s.", signal_name
);
375 void TTCN_Runtime::ignore_signal(int signal_number
, const char *signal_name
)
377 struct sigaction sig_act
;
378 if (sigaction(signal_number
, NULL
, &sig_act
))
379 TTCN_error("System call sigaction() failed when getting signal "
380 "handling information for %s.", signal_name
);
381 sig_act
.sa_handler
= SIG_IGN
;
382 sig_act
.sa_flags
= 0;
383 if (sigaction(signal_number
, &sig_act
, NULL
))
384 TTCN_error("System call sigaction() failed when disabling signal "
388 void TTCN_Runtime::enable_interrupt_handler()
390 set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
393 void TTCN_Runtime::disable_interrupt_handler()
395 ignore_signal(SIGINT
, "SIGINT");
398 void TTCN_Runtime::install_signal_handlers()
400 if (is_single()) set_signal_handler(SIGINT
, "SIGINT", sigint_handler
);
401 ignore_signal(SIGPIPE
, "SIGPIPE");
404 void TTCN_Runtime::restore_signal_handlers()
406 if (is_single()) restore_default_handler(SIGINT
, "SIGINT");
407 restore_default_handler(SIGPIPE
, "SIGPIPE");
410 int TTCN_Runtime::hc_main(const char *local_addr
, const char *MC_addr
,
411 unsigned short MC_port
)
413 int ret_val
= EXIT_SUCCESS
;
414 executor_state
= HC_INITIAL
;
415 TTCN_Logger::log_HC_start(get_host_name());
416 TTCN_Logger::write_logger_settings();
417 TTCN_Snapshot::check_fd_setsize();
419 if (local_addr
!= NULL
)
420 TTCN_Communication::set_local_address(local_addr
);
421 TTCN_Communication::set_mc_address(MC_addr
, MC_port
);
422 TTCN_Communication::connect_mc();
423 Module_List::send_versions();
424 executor_state
= HC_IDLE
;
425 TTCN_Communication::send_version();
426 initialize_component_process_tables();
428 TTCN_Snapshot::take_new(TRUE
);
429 TTCN_Communication::process_all_messages_hc();
430 } while (executor_state
>= HC_IDLE
&& executor_state
< HC_EXIT
);
431 if (executor_state
== HC_EXIT
) {
432 // called only on the HC
433 TTCN_Communication::disconnect_mc();
436 } catch (const TC_Error
& tc_error
) {
437 ret_val
= EXIT_FAILURE
;
440 // called on the newly created MTC and PTCs as well because
441 // the hashtables are inherited with fork()
442 clear_component_process_tables();
445 TTCN_Logger::log_executor_runtime(
446 API::ExecutorRuntime_reason::host__controller__finished
);
451 int TTCN_Runtime::mtc_main()
453 int ret_val
= EXIT_SUCCESS
;
454 TTCN_Runtime::load_logger_plugins();
455 TTCN_Runtime::set_logger_parameters();
456 TTCN_Logger::open_file();
457 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__started
);
458 TTCN_Logger::write_logger_settings();
460 TTCN_Communication::connect_mc();
461 executor_state
= MTC_IDLE
;
462 TTCN_Communication::send_mtc_created();
464 TTCN_Snapshot::take_new(TRUE
);
465 TTCN_Communication::process_all_messages_tc();
466 } while (executor_state
!= MTC_EXIT
);
467 TTCN_Logger::close_file();
468 TTCN_Communication::disconnect_mc();
470 } catch (const TC_Error
& tc_error
) {
471 ret_val
= EXIT_FAILURE
;
473 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::mtc__finished
);
477 int TTCN_Runtime::ptc_main()
479 int ret_val
= EXIT_SUCCESS
;
480 TTCN_Runtime::load_logger_plugins();
481 TTCN_Runtime::set_logger_parameters();
482 TTCN_Logger::open_file();
483 TTCN_Logger::begin_event(TTCN_Logger::EXECUTOR_COMPONENT
);
484 TTCN_Logger::log_event("TTCN-3 Parallel Test Component started on %s. "
485 "Component reference: ", get_host_name());
487 TTCN_Logger::log_event(", component type: %s.%s",
488 component_type
.module_name
, component_type
.definition_name
);
489 if (component_name
!= NULL
)
490 TTCN_Logger::log_event(", component name: %s", component_name
);
491 TTCN_Logger::log_event_str(". Version: " PRODUCT_NUMBER
".");
492 TTCN_Logger::end_event();
493 TTCN_Logger::write_logger_settings();
495 TTCN_Communication::connect_mc();
496 executor_state
= PTC_IDLE
;
497 TTCN_Communication::send_ptc_created((component
)self
);
499 initialize_component_type();
500 } catch (const TC_Error
& tc_error
) {
501 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::component__init__fail
);
502 ret_val
= EXIT_FAILURE
;
504 if (ret_val
== EXIT_SUCCESS
) {
505 if (ttcn3_debugger
.is_activated()) {
506 ttcn3_debugger
.open_output_file();
510 TTCN_Snapshot::take_new(TRUE
);
511 TTCN_Communication::process_all_messages_tc();
512 } while (executor_state
!= PTC_EXIT
);
513 } catch (const TC_Error
& tc_error
) {
514 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::error__idle__ptc
);
515 ret_val
= EXIT_FAILURE
;
518 if (ret_val
!= EXIT_SUCCESS
) {
519 // ignore errors in subsequent operations
521 terminate_component_type();
522 } catch (const TC_Error
& tc_error
) { }
524 TTCN_Communication::send_killed(local_verdict
, (const char *)verdict_reason
);
525 } catch (const TC_Error
& tc_error
) { }
526 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
527 local_verdict
, (const char *)verdict_reason
);
528 executor_state
= PTC_EXIT
;
530 TTCN_Communication::disconnect_mc();
531 clear_component_status_table();
533 } catch (const TC_Error
& tc_error
) {
534 ret_val
= EXIT_FAILURE
;
536 TTCN_Logger::log_executor_component(API::ExecutorComponent_reason::ptc__finished
);
540 component
TTCN_Runtime::create_component(
541 const char *created_component_type_module
,
542 const char *created_component_type_name
, const char *created_component_name
,
543 const char *created_component_location
, boolean created_component_alive
)
545 if (in_controlpart())
546 TTCN_error("Create operation cannot be performed in the control part.");
547 else if (is_single())
548 TTCN_error("Create operation cannot be performed in single mode.");
550 if (created_component_name
!= NULL
&&
551 created_component_name
[0] == '\0') {
552 TTCN_warning("Empty charstring value was ignored as component name "
553 "in create operation.");
554 created_component_name
= NULL
;
556 if (created_component_location
!= NULL
&&
557 created_component_location
[0] == '\0') {
558 TTCN_warning("Empty charstring value was ignored as component location "
559 "in create operation.");
560 created_component_location
= NULL
;
563 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
564 TTCN_Logger::log_event("Creating new %sPTC with component type %s.%s",
565 created_component_alive
? "alive ": "", created_component_type_module
,
566 created_component_type_name
);
567 if (created_component_name
!= NULL
)
568 TTCN_Logger::log_event(", component name: %s", created_component_name
);
569 if (created_component_location
!= NULL
)
570 TTCN_Logger::log_event(", location: %s", created_component_location
);
571 TTCN_Logger::log_char('.');
572 TTCN_Logger::end_event();
574 switch (executor_state
) {
576 executor_state
= MTC_CREATE
;
579 executor_state
= PTC_CREATE
;
582 TTCN_error("Internal error: Executing create operation in invalid "
585 TTCN_Communication::send_create_req(created_component_type_module
,
586 created_component_type_name
, created_component_name
,
587 created_component_location
, created_component_alive
);
589 // updating the component status flags
590 // 'any component.done' and 'any component.killed' might be successful
591 // from now since the PTC can terminate by itself
592 if (any_component_done_status
== ALT_NO
)
593 any_component_done_status
= ALT_UNCHECKED
;
594 if (any_component_killed_status
== ALT_NO
)
595 any_component_killed_status
= ALT_UNCHECKED
;
596 // 'all component.killed' must be re-evaluated later
597 all_component_killed_status
= ALT_UNCHECKED
;
599 wait_for_state_change();
601 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created
,
602 created_component_type_module
, created_component_type_name
,
603 create_done_killed_compref
, created_component_name
,
604 created_component_location
, created_component_alive
);
606 COMPONENT::register_component_name(create_done_killed_compref
,
607 created_component_name
);
608 return create_done_killed_compref
;
611 void TTCN_Runtime::prepare_start_component(const COMPONENT
& component_reference
,
612 const char *module_name
, const char *function_name
, Text_Buf
& text_buf
)
614 if (in_controlpart()) TTCN_error("Start test component operation cannot "
615 "be performed in the control part.");
616 else if (is_single()) TTCN_error("Start test component operation cannot "
617 "be performed in single mode.");
618 if (!component_reference
.is_bound()) TTCN_error("Performing a start "
619 "operation on an unbound component reference.");
620 component compref
= (component
)component_reference
;
623 TTCN_error("Start operation cannot be performed on the null "
624 "component reference.");
626 TTCN_error("Start operation cannot be performed on the component "
627 "reference of MTC.");
629 TTCN_error("Start operation cannot be performed on the component "
630 "reference of system.");
632 TTCN_error("Internal error: 'any component' cannot be started.");
634 TTCN_error("Internal error: 'all component' cannot be started.");
638 if (self
== compref
) TTCN_error("Start operation cannot be performed on "
639 "the own component reference of the initiating component (i.e. "
640 "'self.start' is not allowed).");
641 if (in_component_status_table(compref
)) {
642 if (get_killed_status(compref
) == ALT_YES
) {
643 TTCN_error("PTC with component reference %d is not alive anymore. "
644 "Start operation cannot be performed on it.", compref
);
646 // the done status of the PTC shall be invalidated
647 cancel_component_done(compref
);
649 TTCN_Communication::prepare_start_req(text_buf
, compref
, module_name
,
653 void TTCN_Runtime::send_start_component(Text_Buf
& text_buf
)
655 switch (executor_state
) {
657 executor_state
= MTC_START
;
660 executor_state
= PTC_START
;
663 TTCN_error("Internal error: Executing component start operation "
664 "in invalid state.");
666 // text_buf already contains a complete START_REQ message.
667 TTCN_Communication::send_message(text_buf
);
669 // updating the component status flags
670 // 'all component.done' must be re-evaluated later
671 all_component_done_status
= ALT_UNCHECKED
;
673 wait_for_state_change();
674 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__started
);
677 void TTCN_Runtime::start_function(const char *module_name
,
678 const char *function_name
, Text_Buf
& text_buf
)
680 switch (executor_state
) {
685 // the START message must be dropped here because normally it is
686 // dropped in function_started()
687 text_buf
.cut_message();
688 TTCN_error("Internal error: Message START arrived in invalid state.");
691 Module_List::start_function(module_name
, function_name
, text_buf
);
692 // do nothing: the function terminated normally
693 // the message STOPPED or STOPPED_KILLED is already sent out
694 // and the state variable is updated
696 } catch (const TC_End
& TC_end
) {
697 // executor_state is already set by stop_execution or kill_execution
698 switch (executor_state
) {
700 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
701 "Function %s was stopped. PTC remains alive and is waiting for next start.",
703 // send a STOPPED message without return value
704 TTCN_Communication::send_stopped();
705 // return and do nothing else
708 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__stopped
, NULL
,
712 TTCN_error("Internal error: PTC was stopped in invalid state.");
714 } catch (const TC_Error
& TC_error
) {
715 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__error
, NULL
,
717 executor_state
= PTC_EXIT
;
719 // the control reaches this code if the PTC has to be terminated
721 // first terminate all ports and timers
722 // this may affect the final verdict
723 terminate_component_type();
724 // send a STOPPED_KILLED message without return value
725 TTCN_Communication::send_stopped_killed(local_verdict
, verdict_reason
);
726 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
727 local_verdict
, (const char *)verdict_reason
);
730 void TTCN_Runtime::function_started(Text_Buf
& text_buf
)
732 // The buffer still contains the incoming START message.
733 text_buf
.cut_message();
734 executor_state
= PTC_FUNCTION
;
735 // The remaining messages must be processed now.
736 TTCN_Communication::process_all_messages_tc();
739 void TTCN_Runtime::prepare_function_finished(const char *return_type
,
742 if (executor_state
!= PTC_FUNCTION
)
743 TTCN_error("Internal error: PTC behaviour function finished in invalid "
746 // Prepare a STOPPED message with the possible return value.
747 TTCN_Communication::prepare_stopped(text_buf
, return_type
);
749 // First the ports and timers must be stopped and deactivated. The
750 // user_unmap and user_stop functions of Test Ports may detect errors
751 // that must be considered in the final verdict of the PTC.
752 terminate_component_type();
753 // Prepare a STOPPED_KILLED message with the final verdict and the
754 // possible return value.
755 TTCN_Communication::prepare_stopped_killed(text_buf
, local_verdict
,
756 return_type
, verdict_reason
);
760 void TTCN_Runtime::send_function_finished(Text_Buf
& text_buf
)
762 // send out the STOPPED or STOPPED_KILLED message, which is already
763 // complete and contains the return value
764 TTCN_Communication::send_message(text_buf
);
765 // log the final verdict if necessary and update the state variable
766 if (is_alive
) executor_state
= PTC_STOPPED
;
768 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
769 local_verdict
, (const char *)verdict_reason
);
770 executor_state
= PTC_EXIT
;
774 void TTCN_Runtime::function_finished(const char *function_name
)
776 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::function__finished
, NULL
,
777 function_name
, 0, NULL
, NULL
, is_alive
);
779 prepare_function_finished(NULL
, text_buf
);
780 send_function_finished(text_buf
);
783 alt_status
TTCN_Runtime::component_done(component component_reference
)
785 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
786 "in the control part.");
787 switch (component_reference
) {
789 TTCN_error("Done operation cannot be performed on the null "
790 "component reference.");
792 TTCN_error("Done operation cannot be performed on the component "
793 "reference of MTC.");
795 TTCN_error("Done operation cannot be performed on the component "
796 "reference of system.");
798 return any_component_done();
800 return all_component_done();
802 return ptc_done(component_reference
);
806 alt_status
TTCN_Runtime::component_done(component component_reference
,
807 const char *return_type
, Text_Buf
*& text_buf
)
809 if (in_controlpart()) TTCN_error("Done operation cannot be performed "
810 "in the control part.");
811 switch (component_reference
) {
813 TTCN_error("Done operation cannot be performed on the null "
814 "component reference.");
816 TTCN_error("Done operation cannot be performed on the component "
817 "reference of MTC.");
819 TTCN_error("Done operation cannot be performed on the component "
820 "reference of system.");
822 TTCN_error("Done operation with return value cannot be performed on "
825 TTCN_error("Done operation with return value cannot be performed on "
828 // the argument refers to a PTC
831 if (is_single()) TTCN_error("Done operation on a component reference "
832 "cannot be performed in single mode.");
833 if (self
== component_reference
) {
834 TTCN_warning("Done operation on the component reference of self "
835 "will never succeed.");
838 int index
= get_component_status_table_index(component_reference
);
839 // we cannot use the killed status because we need the return value
840 switch (component_status_table
[index
].done_status
) {
842 switch (executor_state
) {
844 executor_state
= MTC_DONE
;
847 executor_state
= PTC_DONE
;
850 TTCN_error("Internal error: Executing done operation in "
853 TTCN_Communication::send_done_req(component_reference
);
854 component_status_table
[index
].done_status
= ALT_MAYBE
;
855 create_done_killed_compref
= component_reference
;
857 wait_for_state_change();
858 // always re-evaluate the current alternative using a new snapshot
861 if (component_status_table
[index
].return_type
!= NULL
) {
862 if (!strcmp(component_status_table
[index
].return_type
,
864 component_status_table
[index
].return_value
->rewind();
865 text_buf
= component_status_table
[index
].return_value
;
868 TTCN_Logger::log_matching_done(return_type
, component_reference
,
869 component_status_table
[index
].return_type
,
870 API::MatchingDoneType_reason::done__failed__wrong__return__type
);
874 TTCN_Logger::log_matching_done(return_type
, component_reference
, NULL
,
875 API::MatchingDoneType_reason::done__failed__no__return
);
884 alt_status
TTCN_Runtime::component_killed(component component_reference
)
886 if (in_controlpart()) TTCN_error("Killed operation cannot be performed "
887 "in the control part.");
888 switch (component_reference
) {
890 TTCN_error("Killed operation cannot be performed on the null "
891 "component reference.");
893 TTCN_error("Killed operation cannot be performed on the component "
894 "reference of MTC.");
896 TTCN_error("Killed operation cannot be performed on the component "
897 "reference of system.");
899 return any_component_killed();
901 return all_component_killed();
903 return ptc_killed(component_reference
);
907 boolean
TTCN_Runtime::component_running(component component_reference
)
909 if (in_controlpart()) TTCN_error("Component running operation "
910 "cannot be performed in the control part.");
911 switch (component_reference
) {
913 TTCN_error("Running operation cannot be performed on the null "
914 "component reference.");
916 TTCN_error("Running operation cannot be performed on the component "
917 "reference of MTC.");
919 TTCN_error("Running operation cannot be performed on the component "
920 "reference of system.");
922 return any_component_running();
924 return all_component_running();
926 return ptc_running(component_reference
);
930 boolean
TTCN_Runtime::component_alive(component component_reference
)
932 if (in_controlpart()) TTCN_error("Alive operation cannot be performed "
933 "in the control part.");
934 switch (component_reference
) {
936 TTCN_error("Alive operation cannot be performed on the null "
937 "component reference.");
939 TTCN_error("Alive operation cannot be performed on the component "
940 "reference of MTC.");
942 TTCN_error("Alive operation cannot be performed on the component "
943 "reference of system.");
945 return any_component_alive();
947 return all_component_alive();
949 return ptc_alive(component_reference
);
953 void TTCN_Runtime::stop_component(component component_reference
)
955 if (in_controlpart()) TTCN_error("Component stop operation cannot be "
956 "performed in the control part.");
958 if (self
== component_reference
) stop_execution();
959 switch (component_reference
) {
961 TTCN_error("Stop operation cannot be performed on the null component "
967 TTCN_error("Stop operation cannot be performed on the component "
968 "reference of system.");
970 TTCN_error("Internal error: 'any component' cannot be stopped.");
972 stop_all_component();
975 stop_ptc(component_reference
);
979 void TTCN_Runtime::stop_execution()
981 if (in_controlpart()) {
982 TTCN_Logger::log_executor_runtime(
983 API::ExecutorRuntime_reason::stopping__control__part__execution
);
985 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
986 "Stopping test component execution.");
988 // the state variable indicates whether the component remains alive
989 // after termination or not
990 if (is_alive
) executor_state
= PTC_STOPPED
;
991 else executor_state
= PTC_EXIT
;
997 void TTCN_Runtime::kill_component(component component_reference
)
999 if (in_controlpart()) TTCN_error("Kill operation cannot be performed in "
1000 "the control part.");
1002 if (self
== component_reference
) kill_execution();
1003 switch (component_reference
) {
1005 TTCN_error("Kill operation cannot be performed on the null component "
1008 // 'mtc.kill' means exactly the same as 'mtc.stop'
1011 case SYSTEM_COMPREF
:
1012 TTCN_error("Kill operation cannot be performed on the component "
1013 "reference of system.");
1015 TTCN_error("Internal error: 'any component' cannot be killed.");
1017 kill_all_component();
1020 kill_ptc(component_reference
);
1024 void TTCN_Runtime::kill_execution()
1026 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1027 "Terminating test component execution.");
1028 if (is_ptc()) executor_state
= PTC_EXIT
;
1032 alt_status
TTCN_Runtime::ptc_done(component component_reference
)
1034 if (is_single()) TTCN_error("Done operation on a component reference "
1035 "cannot be performed in single mode.");
1036 if (self
== component_reference
) {
1037 TTCN_warning("Done operation on the component reference of self "
1038 "will never succeed.");
1041 int index
= get_component_status_table_index(component_reference
);
1042 // a successful killed operation on the component reference implies done
1043 if (component_status_table
[index
].killed_status
== ALT_YES
)
1045 switch (component_status_table
[index
].done_status
) {
1047 switch (executor_state
) {
1049 executor_state
= MTC_DONE
;
1052 executor_state
= PTC_DONE
;
1055 TTCN_error("Internal error: Executing done operation in "
1058 TTCN_Communication::send_done_req(component_reference
);
1059 component_status_table
[index
].done_status
= ALT_MAYBE
;
1060 create_done_killed_compref
= component_reference
;
1061 // wait for DONE_ACK
1062 wait_for_state_change();
1063 // always re-evaluate the current alternative using a new snapshot
1071 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__done
,
1072 NULL
, NULL
, component_reference
);
1076 alt_status
TTCN_Runtime::any_component_done()
1078 // the operation is never successful in single mode
1079 if (is_single()) goto failure
;
1080 if (!is_mtc()) TTCN_error("Operation 'any component.done' can only be "
1081 "performed on the MTC.");
1082 // the operation is successful if there is a component reference with a
1083 // successful done or killed operation
1084 for (int i
= 0; i
< component_status_table_size
; i
++) {
1085 if (component_status_table
[i
].done_status
== ALT_YES
||
1086 component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1088 // a successful 'any component.killed' implies 'any component.done'
1089 if (any_component_killed_status
== ALT_YES
) goto success
;
1090 switch (any_component_done_status
) {
1092 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1093 "Executing 'any component.done' in invalid state.");
1094 executor_state
= MTC_DONE
;
1095 TTCN_Communication::send_done_req(ANY_COMPREF
);
1096 any_component_done_status
= ALT_MAYBE
;
1097 create_done_killed_compref
= ANY_COMPREF
;
1098 // wait for DONE_ACK
1099 wait_for_state_change();
1100 // always re-evaluate the current alternative using a new snapshot
1110 TTCN_Logger::log_matching_done(0, 0, 0,
1111 API::MatchingDoneType_reason::any__component__done__successful
);
1114 TTCN_Logger::log_matching_done(0, 0, 0,
1115 API::MatchingDoneType_reason::any__component__done__failed
);
1119 alt_status
TTCN_Runtime::all_component_done()
1121 // the operation is always successful in single mode
1122 if (is_single()) goto success
;
1123 if (!is_mtc()) TTCN_error("Operation 'all component.done' can only be "
1124 "performed on the MTC.");
1125 // a successful 'all component.killed' implies 'all component.done'
1126 if (all_component_killed_status
== ALT_YES
) goto success
;
1127 switch (all_component_done_status
) {
1129 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1130 "Executing 'all component.done' in invalid state.");
1131 executor_state
= MTC_DONE
;
1132 TTCN_Communication::send_done_req(ALL_COMPREF
);
1133 all_component_done_status
= ALT_MAYBE
;
1134 create_done_killed_compref
= ALL_COMPREF
;
1135 // wait for DONE_ACK
1136 wait_for_state_change();
1137 // always re-evaluate the current alternative using a new snapshot
1145 TTCN_Logger::log_matching_done(0, 0, 0,
1146 API::MatchingDoneType_reason::all__component__done__successful
);
1150 alt_status
TTCN_Runtime::ptc_killed(component component_reference
)
1152 if (is_single()) TTCN_error("Killed operation on a component reference "
1153 "cannot be performed in single mode.");
1154 if (self
== component_reference
) {
1155 TTCN_warning("Killed operation on the component reference of self "
1156 "will never succeed.");
1159 int index
= get_component_status_table_index(component_reference
);
1160 switch (component_status_table
[index
].killed_status
) {
1162 switch (executor_state
) {
1164 executor_state
= MTC_KILLED
;
1167 executor_state
= PTC_KILLED
;
1170 TTCN_error("Internal error: Executing killed operation in "
1173 TTCN_Communication::send_killed_req(component_reference
);
1174 component_status_table
[index
].killed_status
= ALT_MAYBE
;
1175 create_done_killed_compref
= component_reference
;
1176 // wait for KILLED_ACK
1177 wait_for_state_change();
1178 // always re-evaluate the current alternative using a new snapshot
1186 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
,
1187 NULL
, NULL
, component_reference
);
1191 alt_status
TTCN_Runtime::any_component_killed()
1193 // the operation is never successful in single mode
1194 if (is_single()) goto failure
;
1195 if (!is_mtc()) TTCN_error("Operation 'any component.killed' can only be "
1196 "performed on the MTC.");
1197 // the operation is successful if there is a component reference with a
1198 // successful killed operation
1199 for (int i
= 0; i
< component_status_table_size
; i
++) {
1200 if (component_status_table
[i
].killed_status
== ALT_YES
) goto success
;
1202 switch (any_component_killed_status
) {
1204 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1205 "Executing 'any component.killed' in invalid state.");
1206 executor_state
= MTC_KILLED
;
1207 TTCN_Communication::send_killed_req(ANY_COMPREF
);
1208 any_component_killed_status
= ALT_MAYBE
;
1209 create_done_killed_compref
= ANY_COMPREF
;
1210 // wait for KILLED_ACK
1211 wait_for_state_change();
1212 // always re-evaluate the current alternative using a new snapshot
1222 TTCN_Logger::log_matching_done(0, 0, 0,
1223 API::MatchingDoneType_reason::any__component__killed__successful
);
1226 TTCN_Logger::log_matching_done(0, 0, 0,
1227 API::MatchingDoneType_reason::any__component__killed__failed
);
1231 alt_status
TTCN_Runtime::all_component_killed()
1233 // the operation is always successful in single mode
1234 if (is_single()) goto success
;
1235 if (!is_mtc()) TTCN_error("Operation 'all component.killed' can only be "
1236 "performed on the MTC.");
1237 switch (all_component_killed_status
) {
1239 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1240 "Executing 'all component.killed' in invalid state.");
1241 executor_state
= MTC_KILLED
;
1242 TTCN_Communication::send_killed_req(ALL_COMPREF
);
1243 all_component_killed_status
= ALT_MAYBE
;
1244 create_done_killed_compref
= ALL_COMPREF
;
1245 // wait for KILLED_ACK
1246 wait_for_state_change();
1247 // always re-evaluate the current alternative using a new snapshot
1255 TTCN_Logger::log_matching_done(0, 0, 0,
1256 API::MatchingDoneType_reason::all__component__killed__successful
);
1260 boolean
TTCN_Runtime::ptc_running(component component_reference
)
1262 if (is_single()) TTCN_error("Running operation on a component reference "
1263 "cannot be performed in single mode.");
1264 // the answer is always true if the operation refers to self
1265 if (self
== component_reference
) {
1266 TTCN_warning("Running operation on the component reference of self "
1267 "always returns true.");
1270 // look into the component status tables
1271 if (in_component_status_table(component_reference
)) {
1272 int index
= get_component_status_table_index(component_reference
);
1273 // the answer is false if a successful done or killed operation was
1274 // performed on the component reference
1275 if (component_status_table
[index
].done_status
== ALT_YES
||
1276 component_status_table
[index
].killed_status
== ALT_YES
)
1279 // status flags all_component_done or all_component_killed cannot be used
1280 // because the component reference might be invalid (e.g. stale)
1282 // the decision cannot be made locally, MC must be asked
1283 switch (executor_state
) {
1285 executor_state
= MTC_RUNNING
;
1288 executor_state
= PTC_RUNNING
;
1291 TTCN_error("Internal error: Executing component running operation "
1292 "in invalid state.");
1294 TTCN_Communication::send_is_running(component_reference
);
1296 wait_for_state_change();
1297 return running_alive_result
;
1300 boolean
TTCN_Runtime::any_component_running()
1302 // the answer is always false in single mode
1303 if (is_single()) return FALSE
;
1304 if (!is_mtc()) TTCN_error("Operation 'any component.running' can only be "
1305 "performed on the MTC.");
1306 // the answer is false if 'all component.done' or 'all component.killed'
1307 // operation was successful
1308 if (all_component_done_status
== ALT_YES
||
1309 all_component_killed_status
== ALT_YES
) return FALSE
;
1310 // the decision cannot be made locally, MC must be asked
1311 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1312 "Executing 'any component.running' in invalid state.");
1313 TTCN_Communication::send_is_running(ANY_COMPREF
);
1314 executor_state
= MTC_RUNNING
;
1316 wait_for_state_change();
1317 // update the status of 'all component.done' in case of negative answer
1318 if (!running_alive_result
) all_component_done_status
= ALT_YES
;
1319 return running_alive_result
;
1322 boolean
TTCN_Runtime::all_component_running()
1324 // the answer is always true in single mode
1325 if (is_single()) return TRUE
;
1326 if (!is_mtc()) TTCN_error("Operation 'all component.running' can only be "
1327 "performed on the MTC.");
1328 // return true if no PTCs exist
1329 if (any_component_done_status
== ALT_NO
) return TRUE
;
1330 // the done and killed status flags cannot be used since the components
1331 // that were explicitly stopped or killed must be ignored
1333 // the decision cannot be made locally, MC must be asked
1334 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1335 "Executing 'all component.running' in invalid state.");
1336 TTCN_Communication::send_is_running(ALL_COMPREF
);
1337 executor_state
= MTC_RUNNING
;
1339 wait_for_state_change();
1340 return running_alive_result
;
1343 boolean
TTCN_Runtime::ptc_alive(component component_reference
)
1345 if (is_single()) TTCN_error("Alive operation on a component reference "
1346 "cannot be performed in single mode.");
1347 // the answer is always true if the operation refers to self
1348 if (self
== component_reference
) {
1349 TTCN_warning("Alive operation on the component reference of self "
1350 "always returns true.");
1353 // the answer is false if a successful killed operation was performed
1354 // on the component reference
1355 if (in_component_status_table(component_reference
) &&
1356 get_killed_status(component_reference
) == ALT_YES
) return FALSE
;
1357 // status flag of 'all component.killed' cannot be used because the
1358 // component reference might be invalid (e.g. stale)
1360 // the decision cannot be made locally, MC must be asked
1361 switch (executor_state
) {
1363 executor_state
= MTC_ALIVE
;
1366 executor_state
= PTC_ALIVE
;
1369 TTCN_error("Internal error: Executing component running operation "
1370 "in invalid state.");
1372 TTCN_Communication::send_is_alive(component_reference
);
1374 wait_for_state_change();
1375 return running_alive_result
;
1378 boolean
TTCN_Runtime::any_component_alive()
1380 // the answer is always false in single mode
1381 if (is_single()) return FALSE
;
1382 if (!is_mtc()) TTCN_error("Operation 'any component.alive' can only be "
1383 "performed on the MTC.");
1384 // the answer is false if 'all component.killed' operation was successful
1385 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1386 // the decision cannot be made locally, MC must be asked
1387 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1388 "Executing 'any component.alive' in invalid state.");
1389 TTCN_Communication::send_is_alive(ANY_COMPREF
);
1390 executor_state
= MTC_ALIVE
;
1392 wait_for_state_change();
1393 // update the status of 'all component.killed' in case of negative answer
1394 if (!running_alive_result
) all_component_killed_status
= ALT_YES
;
1395 return running_alive_result
;
1398 boolean
TTCN_Runtime::all_component_alive()
1400 // the answer is always true in single mode
1401 if (is_single()) return TRUE
;
1402 if (!is_mtc()) TTCN_error("Operation 'all component.alive' can only be "
1403 "performed on the MTC.");
1404 // return true if no PTCs exist
1405 if (any_component_killed_status
== ALT_NO
) return TRUE
;
1406 // return false if at least one PTC has been created and
1407 // 'all component.killed' was successful after the create operation
1408 if (all_component_killed_status
== ALT_YES
) return FALSE
;
1409 // the operation is successful if there is a component reference with a
1410 // successful killed operation
1411 for (int i
= 0; i
< component_status_table_size
; i
++) {
1412 if (component_status_table
[i
].killed_status
== ALT_YES
) return FALSE
;
1415 // the decision cannot be made locally, MC must be asked
1416 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1417 "Executing 'all component.alive' in invalid state.");
1418 TTCN_Communication::send_is_alive(ALL_COMPREF
);
1419 executor_state
= MTC_ALIVE
;
1421 wait_for_state_change();
1422 return running_alive_result
;
1425 void TTCN_Runtime::stop_mtc()
1427 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::stopping__mtc
);
1428 TTCN_Communication::send_stop_req(MTC_COMPREF
);
1432 void TTCN_Runtime::stop_ptc(component component_reference
)
1434 if (is_single()) TTCN_error("Stop operation on a component reference "
1435 "cannot be performed in single mode.");
1436 // do nothing if a successful done or killed operation was performed on
1437 // the component reference
1438 if (in_component_status_table(component_reference
)) {
1439 int index
= get_component_status_table_index(component_reference
);
1440 if (component_status_table
[index
].done_status
== ALT_YES
||
1441 component_status_table
[index
].killed_status
== ALT_YES
)
1444 // status flags all_component_done or all_component_killed cannot be used
1445 // because the component reference might be invalid (e.g. stale)
1447 // MC must be asked to stop the PTC
1448 switch (executor_state
) {
1450 executor_state
= MTC_STOP
;
1453 executor_state
= PTC_STOP
;
1456 TTCN_error("Internal error: Executing component stop operation "
1457 "in invalid state.");
1459 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1460 "Stopping PTC with component reference %d.", component_reference
);
1461 TTCN_Communication::send_stop_req(component_reference
);
1462 // wait for STOP_ACK
1463 wait_for_state_change();
1464 // done status of the PTC cannot be updated because its return type and
1465 // return value is unknown
1466 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__stopped
,
1467 NULL
, NULL
, component_reference
);
1470 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1471 "PTC with component reference %d is not running. "
1472 "Stop operation had no effect.", component_reference
);
1475 void TTCN_Runtime::stop_all_component()
1477 // do nothing in single mode
1478 if (is_single()) goto ignore
;
1479 if (!is_mtc()) TTCN_error("Operation 'all component.stop' can only be "
1480 "performed on the MTC.");
1481 // do nothing if 'all component.done' or 'all component.killed'
1483 if (all_component_done_status
== ALT_YES
||
1484 all_component_killed_status
== ALT_YES
) goto ignore
;
1485 // a request must be sent to MC
1486 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1487 "Executing 'all component.stop' in invalid state.");
1488 executor_state
= MTC_STOP
;
1489 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Stopping all components.");
1490 TTCN_Communication::send_stop_req(ALL_COMPREF
);
1491 // wait for STOP_ACK
1492 wait_for_state_change();
1493 // 'all component.done' will be successful later
1494 all_component_done_status
= ALT_YES
;
1495 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__stopped
);
1498 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "No PTCs are running. "
1499 "Operation 'all component.stop' had no effect.");
1502 void TTCN_Runtime::kill_ptc(component component_reference
)
1504 if (is_single()) TTCN_error("Kill operation on a component reference "
1505 "cannot be performed in single mode.");
1506 // do nothing if a successful killed operation was performed on
1507 // the component reference
1508 if (in_component_status_table(component_reference
) &&
1509 get_killed_status(component_reference
) == ALT_YES
) goto ignore
;
1510 // status flags all_component_killed cannot be used because the component
1511 // reference might be invalid (e.g. stale)
1513 // MC must be asked to kill the PTC
1514 switch (executor_state
) {
1516 executor_state
= MTC_KILL
;
1519 executor_state
= PTC_KILL
;
1522 TTCN_error("Internal error: Executing kill operation in invalid "
1525 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1526 "Killing PTC with component reference %d.", component_reference
);
1527 TTCN_Communication::send_kill_req(component_reference
);
1528 // wait for KILL_ACK
1529 wait_for_state_change();
1530 // updating the killed status of the PTC
1532 int index
= get_component_status_table_index(component_reference
);
1533 component_status_table
[index
].killed_status
= ALT_YES
;
1535 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__killed
, NULL
, NULL
,
1536 component_reference
);
1539 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1540 "PTC with component reference %d is not alive anymore. "
1541 "Kill operation had no effect.", component_reference
);
1544 void TTCN_Runtime::kill_all_component()
1546 // do nothing in single mode
1547 if (is_single()) goto ignore
;
1548 if (!is_mtc()) TTCN_error("Operation 'all component.kill' can only be "
1549 "performed on the MTC.");
1550 // do nothing if 'all component.killed' was successful
1551 if (all_component_killed_status
== ALT_YES
) goto ignore
;
1552 // a request must be sent to MC
1553 if (executor_state
!= MTC_TESTCASE
) TTCN_error("Internal error: "
1554 "Executing 'all component.kill' in invalid state.");
1555 executor_state
= MTC_KILL
;
1556 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
, "Killing all components.");
1557 TTCN_Communication::send_kill_req(ALL_COMPREF
);
1558 // wait for KILL_ACK
1559 wait_for_state_change();
1560 // 'all component.done' and 'all component.killed' will be successful later
1561 all_component_done_status
= ALT_YES
;
1562 all_component_killed_status
= ALT_YES
;
1563 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::all__comps__killed
);
1566 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
1567 "There are no alive PTCs. Operation 'all component.kill' had no effect.");
1570 void TTCN_Runtime::check_port_name(const char *port_name
,
1571 const char *operation_name
, const char *which_argument
)
1573 if (port_name
== NULL
)
1574 TTCN_error("Internal error: The port name in the %s argument of %s "
1575 "operation is a NULL pointer.", which_argument
, operation_name
);
1576 if (port_name
[0] == '\0')
1577 TTCN_error("Internal error: The %s argument of %s operation contains "
1578 "an empty string as port name.", which_argument
, operation_name
);
1579 /** \todo check whether port_name contains a valid TTCN-3 identifier
1580 * (and array index) */
1583 void TTCN_Runtime::connect_port(
1584 const COMPONENT
& src_compref
, const char *src_port
,
1585 const COMPONENT
& dst_compref
, const char *dst_port
)
1587 check_port_name(src_port
, "connect", "first");
1588 check_port_name(dst_port
, "connect", "second");
1590 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1591 TTCN_Logger::log_event_str("Connecting ports ");
1592 COMPONENT::log_component_reference(src_compref
);
1593 TTCN_Logger::log_event(":%s and ", src_port
);
1594 COMPONENT::log_component_reference(dst_compref
);
1595 TTCN_Logger::log_event(":%s.", dst_port
);
1596 TTCN_Logger::end_event();
1598 if (!src_compref
.is_bound()) TTCN_error("The first argument of connect "
1599 "operation contains an unbound component reference.");
1600 component src_component
= src_compref
;
1601 switch (src_component
) {
1603 TTCN_error("The first argument of connect operation contains the "
1604 "null component reference.");
1605 case SYSTEM_COMPREF
:
1606 TTCN_error("The first argument of connect operation refers to a "
1611 if (!dst_compref
.is_bound()) TTCN_error("The second argument of connect "
1612 "operation contains an unbound component reference.");
1613 component dst_component
= dst_compref
;
1614 switch (dst_component
) {
1616 TTCN_error("The second argument of connect operation contains the "
1617 "null component reference.");
1618 case SYSTEM_COMPREF
:
1619 TTCN_error("The second argument of connect operation refers to a "
1625 switch (executor_state
) {
1626 case SINGLE_TESTCASE
:
1627 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1628 TTCN_error("Both endpoints of connect operation must refer to "
1629 "ports of mtc in single mode.");
1630 PORT::make_local_connection(src_port
, dst_port
);
1633 TTCN_Communication::send_connect_req(src_component
, src_port
,
1634 dst_component
, dst_port
);
1635 executor_state
= MTC_CONNECT
;
1636 wait_for_state_change();
1639 TTCN_Communication::send_connect_req(src_component
, src_port
,
1640 dst_component
, dst_port
);
1641 executor_state
= PTC_CONNECT
;
1642 wait_for_state_change();
1645 if (in_controlpart()) {
1646 TTCN_error("Connect operation cannot be performed in the "
1649 TTCN_error("Internal error: Executing connect operation "
1650 "in invalid state.");
1654 TTCN_Logger::log_portconnmap(API::ParPort_operation::connect__
,
1655 src_compref
, src_port
, dst_compref
, dst_port
);
1658 void TTCN_Runtime::disconnect_port(
1659 const COMPONENT
& src_compref
, const char *src_port
,
1660 const COMPONENT
& dst_compref
, const char *dst_port
)
1662 check_port_name(src_port
, "disconnect", "first");
1663 check_port_name(dst_port
, "disconnect", "second");
1665 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1666 TTCN_Logger::log_event_str("Disconnecting ports ");
1667 COMPONENT::log_component_reference(src_compref
);
1668 TTCN_Logger::log_event(":%s and ", src_port
);
1669 COMPONENT::log_component_reference(dst_compref
);
1670 TTCN_Logger::log_event(":%s.", dst_port
);
1671 TTCN_Logger::end_event();
1673 if (!src_compref
.is_bound()) TTCN_error("The first argument of disconnect "
1674 "operation contains an unbound component reference.");
1675 component src_component
= src_compref
;
1676 switch (src_component
) {
1678 TTCN_error("The first argument of disconnect operation contains the "
1679 "null component reference.");
1680 case SYSTEM_COMPREF
:
1681 TTCN_error("The first argument of disconnect operation refers to a "
1686 if (!dst_compref
.is_bound()) TTCN_error("The second argument of disconnect "
1687 "operation contains an unbound component reference.");
1688 component dst_component
= dst_compref
;
1689 switch (dst_component
) {
1691 TTCN_error("The second argument of disconnect operation contains the "
1692 "null component reference.");
1693 case SYSTEM_COMPREF
:
1694 TTCN_error("The second argument of disconnect operation refers to a "
1700 switch (executor_state
) {
1701 case SINGLE_TESTCASE
:
1702 if (src_component
!= MTC_COMPREF
|| dst_component
!= MTC_COMPREF
)
1703 TTCN_error("Both endpoints of disconnect operation must refer to "
1704 "ports of mtc in single mode.");
1705 PORT::terminate_local_connection(src_port
, dst_port
);
1708 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1709 dst_component
, dst_port
);
1710 executor_state
= MTC_DISCONNECT
;
1711 wait_for_state_change();
1714 TTCN_Communication::send_disconnect_req(src_component
, src_port
,
1715 dst_component
, dst_port
);
1716 executor_state
= PTC_DISCONNECT
;
1717 wait_for_state_change();
1720 if (in_controlpart()) {
1721 TTCN_error("Disonnect operation cannot be performed in the "
1724 TTCN_error("Internal error: Executing disconnect operation "
1725 "in invalid state.");
1729 TTCN_Logger::log_portconnmap(API::ParPort_operation::disconnect__
,
1730 src_compref
, src_port
, dst_compref
, dst_port
);
1733 void TTCN_Runtime::map_port(
1734 const COMPONENT
& src_compref
, const char *src_port
,
1735 const COMPONENT
& dst_compref
, const char *dst_port
)
1737 check_port_name(src_port
, "map", "first");
1738 check_port_name(dst_port
, "map", "second");
1740 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1741 TTCN_Logger::log_event_str("Mapping port ");
1742 COMPONENT::log_component_reference(src_compref
);
1743 TTCN_Logger::log_event(":%s to ", src_port
);
1744 COMPONENT::log_component_reference(dst_compref
);
1745 TTCN_Logger::log_event(":%s.", dst_port
);
1746 TTCN_Logger::end_event();
1748 if (!src_compref
.is_bound()) TTCN_error("The first argument of map "
1749 "operation contains an unbound component reference.");
1750 component src_component
= src_compref
;
1751 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1752 "map operation contains the null component reference.");
1753 if (!dst_compref
.is_bound()) TTCN_error("The second argument of map "
1754 "operation contains an unbound component reference.");
1755 component dst_component
= dst_compref
;
1756 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1757 "map operation contains the null component reference.");
1759 component comp_reference
;
1760 const char *comp_port
, *system_port
;
1762 if (src_component
== SYSTEM_COMPREF
) {
1763 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1764 "map operation refer to system ports.");
1765 comp_reference
= dst_component
;
1766 comp_port
= dst_port
;
1767 system_port
= src_port
;
1768 } else if (dst_component
== SYSTEM_COMPREF
) {
1769 comp_reference
= src_component
;
1770 comp_port
= src_port
;
1771 system_port
= dst_port
;
1773 TTCN_error("Both arguments of map operation refer to test component "
1775 // to avoid warnings
1779 switch (executor_state
) {
1780 case SINGLE_TESTCASE
:
1781 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1782 "can be mapped in single mode.");
1783 PORT::map_port(comp_port
, system_port
);
1786 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1788 executor_state
= MTC_MAP
;
1789 wait_for_state_change();
1792 TTCN_Communication::send_map_req(comp_reference
, comp_port
,
1794 executor_state
= PTC_MAP
;
1795 wait_for_state_change();
1798 if (in_controlpart()) {
1799 TTCN_error("Map operation cannot be performed in the "
1802 TTCN_error("Internal error: Executing map operation "
1803 "in invalid state.");
1807 TTCN_Logger::log_portconnmap(API::ParPort_operation::map__
,
1808 src_compref
, src_port
, dst_compref
, dst_port
);
1811 void TTCN_Runtime::unmap_port(
1812 const COMPONENT
& src_compref
, const char *src_port
,
1813 const COMPONENT
& dst_compref
, const char *dst_port
)
1815 check_port_name(src_port
, "unmap", "first");
1816 check_port_name(dst_port
, "unmap", "second");
1818 TTCN_Logger::begin_event(TTCN_Logger::PARALLEL_UNQUALIFIED
);
1819 TTCN_Logger::log_event_str("Unmapping port ");
1820 COMPONENT::log_component_reference(src_compref
);
1821 TTCN_Logger::log_event(":%s from ", src_port
);
1822 COMPONENT::log_component_reference(dst_compref
);
1823 TTCN_Logger::log_event(":%s.", dst_port
);
1824 TTCN_Logger::end_event();
1826 if (!src_compref
.is_bound()) TTCN_error("The first argument of unmap "
1827 "operation contains an unbound component reference.");
1828 component src_component
= src_compref
;
1829 if (src_component
== NULL_COMPREF
) TTCN_error("The first argument of "
1830 "unmap operation contains the null component reference.");
1831 if (!dst_compref
.is_bound()) TTCN_error("The second argument of unmap "
1832 "operation contains an unbound component reference.");
1833 component dst_component
= dst_compref
;
1834 if (dst_component
== NULL_COMPREF
) TTCN_error("The second argument of "
1835 "unmap operation contains the null component reference.");
1837 component comp_reference
;
1838 const char *comp_port
, *system_port
;
1840 if (src_component
== SYSTEM_COMPREF
) {
1841 if (dst_component
== SYSTEM_COMPREF
) TTCN_error("Both arguments of "
1842 "unmap operation refer to system ports.");
1843 comp_reference
= dst_component
;
1844 comp_port
= dst_port
;
1845 system_port
= src_port
;
1846 } else if (dst_component
== SYSTEM_COMPREF
) {
1847 comp_reference
= src_component
;
1848 comp_port
= src_port
;
1849 system_port
= dst_port
;
1851 TTCN_error("Both arguments of unmap operation refer to test component "
1853 // to avoid warnings
1857 switch (executor_state
) {
1858 case SINGLE_TESTCASE
:
1859 if (comp_reference
!= MTC_COMPREF
) TTCN_error("Only the ports of mtc "
1860 "can be unmapped in single mode.");
1861 PORT::unmap_port(comp_port
, system_port
);
1864 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1866 executor_state
= MTC_UNMAP
;
1867 wait_for_state_change();
1870 TTCN_Communication::send_unmap_req(comp_reference
, comp_port
,
1872 executor_state
= PTC_UNMAP
;
1873 wait_for_state_change();
1876 if (in_controlpart()) {
1877 TTCN_error("Unmap operation cannot be performed in the "
1880 TTCN_error("Internal error: Executing unmap operation "
1881 "in invalid state.");
1885 TTCN_Logger::log_portconnmap(API::ParPort_operation::unmap__
,
1886 src_compref
, src_port
, dst_compref
, dst_port
);
1889 void TTCN_Runtime::begin_controlpart(const char *module_name
)
1891 control_module_name
= module_name
;
1892 execute_command(begin_controlpart_command
, module_name
);
1893 TTCN_Logger::log_controlpart_start_stop(module_name
, 0);
1896 void TTCN_Runtime::end_controlpart()
1898 TTCN_Default::deactivate_all();
1899 TTCN_Default::reset_counter();
1901 TTCN_Logger::log_controlpart_start_stop(control_module_name
, 1);
1902 execute_command(end_controlpart_command
, control_module_name
);
1903 control_module_name
= NULL
;
1906 void TTCN_Runtime::check_begin_testcase(boolean has_timer
, double timer_value
)
1908 if (!in_controlpart()) {
1909 if (is_single() || is_mtc()) TTCN_error("Test case cannot be executed "
1910 "while another one (%s.%s) is running.", testcase_name
.module_name
,
1911 testcase_name
.definition_name
);
1912 else if (is_ptc()) TTCN_error("Test case cannot be executed on a PTC.");
1913 else TTCN_error("Internal error: Executing a test case in an invalid "
1916 if (has_timer
&& timer_value
< 0.0) TTCN_error("The test case supervisor "
1917 "timer has negative duration (%g s).", timer_value
);
1920 void TTCN_Runtime::begin_testcase(
1921 const char *par_module_name
, const char *par_testcase_name
,
1922 const char *mtc_comptype_module
, const char *mtc_comptype_name
,
1923 const char *system_comptype_module
, const char *system_comptype_name
,
1924 boolean has_timer
, double timer_value
)
1926 switch (executor_state
) {
1927 case SINGLE_CONTROLPART
:
1928 executor_state
= SINGLE_TESTCASE
;
1930 case MTC_CONTROLPART
:
1931 TTCN_Communication::send_testcase_started(par_module_name
,
1932 par_testcase_name
, mtc_comptype_module
, mtc_comptype_name
,
1933 system_comptype_module
, system_comptype_name
);
1934 executor_state
= MTC_TESTCASE
;
1937 TTCN_error("Internal error: Executing a test case in an invalid "
1940 TIMER::save_control_timers();
1941 TTCN_Default::save_control_defaults();
1942 set_testcase_name(par_module_name
, par_testcase_name
);
1943 char *command_arguments
= mprintf("%s.%s", testcase_name
.module_name
,
1944 testcase_name
.definition_name
);
1945 execute_command(begin_testcase_command
, command_arguments
);
1946 Free(command_arguments
);
1947 TTCN_Logger::log_testcase_started(testcase_name
);
1948 if (has_timer
) testcase_timer
.start(timer_value
);
1949 set_component_type(mtc_comptype_module
, mtc_comptype_name
);
1950 initialize_component_type();
1951 // at the beginning of the testcase no PTCs exist
1952 any_component_done_status
= ALT_NO
;
1953 all_component_done_status
= ALT_YES
;
1954 any_component_killed_status
= ALT_NO
;
1955 all_component_killed_status
= ALT_YES
;
1958 verdicttype
TTCN_Runtime::end_testcase()
1960 switch (executor_state
) {
1970 case MTC_DISCONNECT
:
1973 executor_state
= MTC_TESTCASE
;
1976 case SINGLE_TESTCASE
:
1977 disable_interrupt_handler();
1980 TTCN_error("Internal error: Ending a testcase in an invalid state.");
1982 testcase_timer
.stop();
1983 terminate_component_type();
1984 if (executor_state
== MTC_TESTCASE
) {
1985 TTCN_Logger::log_executor_runtime(
1986 API::ExecutorRuntime_reason::waiting__for__ptcs__to__finish
);
1987 TTCN_Communication::send_testcase_finished(local_verdict
, verdict_reason
);
1988 executor_state
= MTC_TERMINATING_TESTCASE
;
1989 wait_for_state_change();
1990 } else if (executor_state
== SINGLE_TESTCASE
) {
1991 executor_state
= SINGLE_CONTROLPART
;
1992 enable_interrupt_handler();
1994 TTCN_Logger::log_testcase_finished(testcase_name
, local_verdict
,
1996 verdict_count
[local_verdict
]++;
1997 // testcase name should come first for backward compatibility
1998 char *command_arguments
= mprintf("%s.%s %s",
1999 testcase_name
.module_name
, testcase_name
.definition_name
,
2000 verdict_name
[local_verdict
]);
2001 execute_command(end_testcase_command
, command_arguments
);
2002 Free(command_arguments
);
2003 clear_qualified_name(testcase_name
);
2004 // clean up component status caches
2005 clear_component_status_table();
2006 any_component_done_status
= ALT_UNCHECKED
;
2007 all_component_done_status
= ALT_UNCHECKED
;
2008 any_component_killed_status
= ALT_UNCHECKED
;
2009 all_component_killed_status
= ALT_UNCHECKED
;
2010 // restore the control part timers and defaults
2011 TTCN_Default::restore_control_defaults();
2012 TIMER::restore_control_timers();
2013 if (executor_state
== MTC_PAUSED
) {
2014 TTCN_Logger::log_executor_runtime(
2015 API::ExecutorRuntime_reason::user__paused__waiting__to__resume
);
2016 wait_for_state_change();
2017 if (executor_state
!= MTC_TERMINATING_EXECUTION
)
2018 TTCN_Logger::log_executor_runtime(
2019 API::ExecutorRuntime_reason::resuming__execution
);
2021 if (executor_state
== MTC_TERMINATING_EXECUTION
) {
2022 executor_state
= MTC_CONTROLPART
;
2023 TTCN_Logger::log_executor_runtime(
2024 API::ExecutorRuntime_reason::terminating__execution
);
2027 return local_verdict
;
2030 void TTCN_Runtime::log_verdict_statistics()
2032 unsigned int total_testcases
= verdict_count
[NONE
] + verdict_count
[PASS
] +
2033 verdict_count
[INCONC
] + verdict_count
[FAIL
] + verdict_count
[ERROR
];
2035 verdicttype overall_verdict
;
2036 if (control_error_count
> 0 || verdict_count
[ERROR
] > 0)
2037 overall_verdict
= ERROR
;
2038 else if (verdict_count
[FAIL
] > 0) overall_verdict
= FAIL
;
2039 else if (verdict_count
[INCONC
] > 0) overall_verdict
= INCONC
;
2040 else if (verdict_count
[PASS
] > 0) overall_verdict
= PASS
;
2041 else overall_verdict
= NONE
;
2043 if (total_testcases
> 0) {
2044 TTCN_Logger::log_verdict_statistics(verdict_count
[NONE
], (100.0 * verdict_count
[NONE
]) / total_testcases
,
2045 verdict_count
[PASS
], (100.0 * verdict_count
[PASS
]) / total_testcases
,
2046 verdict_count
[INCONC
], (100.0 * verdict_count
[INCONC
]) / total_testcases
,
2047 verdict_count
[FAIL
], (100.0 * verdict_count
[FAIL
]) / total_testcases
,
2048 verdict_count
[ERROR
], (100.0 * verdict_count
[ERROR
]) / total_testcases
);
2050 TTCN_Logger::log_verdict_statistics(0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0, 0, 0.0);
2053 if (control_error_count
> 0) {
2054 TTCN_Logger::log_controlpart_errors(control_error_count
);
2057 TTCN_Logger::log(TTCN_Logger::STATISTICS_VERDICT
, "Test execution summary: "
2058 "%u test case%s executed. Overall verdict: %s", total_testcases
,
2059 total_testcases
> 1 ? "s were" : " was", verdict_name
[overall_verdict
]);
2061 verdict_count
[NONE
] = 0;
2062 verdict_count
[PASS
] = 0;
2063 verdict_count
[INCONC
] = 0;
2064 verdict_count
[FAIL
] = 0;
2065 verdict_count
[ERROR
] = 0;
2066 control_error_count
= 0;
2069 void TTCN_Runtime::begin_action()
2071 TTCN_Logger::begin_event(TTCN_Logger::ACTION_UNQUALIFIED
);
2072 TTCN_Logger::log_event_str("Action: ");
2075 void TTCN_Runtime::end_action()
2077 TTCN_Logger::end_event();
2080 void TTCN_Runtime::setverdict(verdicttype new_value
, const char* reason
)
2082 if (verdict_enabled()) {
2083 if (new_value
== ERROR
)
2084 TTCN_error("Error verdict cannot be set explicitly.");
2085 setverdict_internal(new_value
, reason
);
2086 } else if (in_controlpart()) {
2087 TTCN_error("Verdict cannot be set in the control part.");
2089 TTCN_error("Internal error: Setting the verdict in invalid state.");
2093 void TTCN_Runtime::setverdict(const VERDICTTYPE
& new_value
, const char* reason
)
2095 if (!new_value
.is_bound()) TTCN_error("The argument of setverdict "
2096 "operation is an unbound verdict value.");
2097 setverdict((verdicttype
)new_value
, reason
);
2100 void TTCN_Runtime::set_error_verdict()
2102 if (verdict_enabled()) setverdict_internal(ERROR
);
2103 else if (is_single() || is_mtc()) control_error_count
++;
2106 verdicttype
TTCN_Runtime::getverdict()
2108 if (verdict_enabled())
2109 TTCN_Logger::log_getverdict(local_verdict
);
2110 else if (in_controlpart()) TTCN_error("Getverdict operation cannot be "
2111 "performed in the control part.");
2112 else TTCN_error("Internal error: Performing getverdict operation in "
2114 return local_verdict
;
2117 void TTCN_Runtime::setverdict_internal(verdicttype new_value
,
2120 if (new_value
< NONE
|| new_value
> ERROR
)
2121 TTCN_error("Internal error: setting an invalid verdict value (%d).",
2123 verdicttype old_verdict
= local_verdict
;
2124 if (local_verdict
< new_value
) {
2125 verdict_reason
= reason
;
2126 local_verdict
= new_value
;
2127 if (reason
== NULL
|| reason
[0] == '\0')
2128 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2129 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2130 } else if (local_verdict
== new_value
) {
2131 if (reason
== NULL
|| reason
[0] == '\0')
2132 TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
);
2133 else TTCN_Logger::log_setverdict(new_value
, old_verdict
, local_verdict
, reason
, reason
);
2135 if (new_value
== FAIL
) {
2136 ttcn3_debugger
.breakpoint_entry(TTCN3_Debugger::SBP_FAIL_VERDICT
);
2138 else if (new_value
== ERROR
) {
2139 ttcn3_debugger
.breakpoint_entry(TTCN3_Debugger::SBP_ERROR_VERDICT
);
2143 void TTCN_Runtime::set_begin_controlpart_command(const char *new_command
)
2145 Free(begin_controlpart_command
);
2146 begin_controlpart_command
= shell_escape(new_command
);
2149 void TTCN_Runtime::set_end_controlpart_command(const char *new_command
)
2151 Free(end_controlpart_command
);
2152 end_controlpart_command
= shell_escape(new_command
);
2155 void TTCN_Runtime::set_begin_testcase_command(const char *new_command
)
2157 Free(begin_testcase_command
);
2158 begin_testcase_command
= shell_escape(new_command
);
2161 void TTCN_Runtime::set_end_testcase_command(const char *new_command
)
2163 Free(end_testcase_command
);
2164 end_testcase_command
= shell_escape(new_command
);
2167 void TTCN_Runtime::clear_external_commands()
2169 Free(begin_controlpart_command
);
2170 begin_controlpart_command
= NULL
;
2171 Free(end_controlpart_command
);
2172 end_controlpart_command
= NULL
;
2173 Free(begin_testcase_command
);
2174 begin_testcase_command
= NULL
;
2175 Free(end_testcase_command
);
2176 end_testcase_command
= NULL
;
2179 char *TTCN_Runtime::shell_escape(const char *command_str
)
2181 if (command_str
== NULL
|| command_str
[0] == '\0') return NULL
;
2182 boolean has_special_char
= FALSE
;
2183 for (int i
= 0; !has_special_char
&& command_str
[i
] != '\0'; i
++) {
2184 switch (command_str
[i
]) {
2206 // special characters interpreted by the shell except '
2207 has_special_char
= TRUE
;
2210 // non-printable characters also need special handling
2211 if (!isprint(command_str
[i
])) has_special_char
= TRUE
;
2214 char *ret_val
= memptystr();
2215 // indicates whether we are in an unclosed ' string
2216 boolean in_apostrophes
= FALSE
;
2217 for (int i
= 0; command_str
[i
] != '\0'; i
++) {
2218 if (command_str
[i
] == '\'') {
2219 if (in_apostrophes
) {
2220 // close the open literal
2221 ret_val
= mputc(ret_val
, '\'');
2222 in_apostrophes
= FALSE
;
2224 // substitute with \'
2225 ret_val
= mputstr(ret_val
, "\\'");
2227 if (has_special_char
&& !in_apostrophes
) {
2229 ret_val
= mputc(ret_val
, '\'');
2230 in_apostrophes
= TRUE
;
2232 // append the single character
2233 ret_val
= mputc(ret_val
, command_str
[i
]);
2236 // close the open literal
2237 if (in_apostrophes
) ret_val
= mputc(ret_val
, '\'');
2241 void TTCN_Runtime::execute_command(const char *command_name
,
2242 const char *argument_string
)
2244 if (command_name
!= NULL
) {
2245 char *command_string
= mprintf("%s %s", command_name
, argument_string
);
2247 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_START
, command_string
);
2248 int return_status
= system(command_string
);
2249 if (return_status
== -1) TTCN_error("Execution of external "
2250 "command `%s' failed.", command_string
);
2251 else if (WIFEXITED(return_status
)) {
2252 int exit_status
= WEXITSTATUS(return_status
);
2253 if (exit_status
== EXIT_SUCCESS
)
2254 TTCN_Logger::log_extcommand(TTCN_Logger::EXTCOMMAND_SUCCESS
, command_string
);
2255 else TTCN_warning("External command `%s' returned "
2256 "unsuccessful exit status (%d).", command_string
,
2258 } else if (WIFSIGNALED(return_status
)) {
2259 int signal_number
= WTERMSIG(return_status
);
2260 TTCN_warning("External command `%s' was terminated by signal "
2261 "%d (%s).", command_string
, signal_number
,
2262 get_signal_name(signal_number
));
2264 TTCN_warning("External command `%s' was terminated by an "
2265 "unknown reason (return status: %d).", command_string
,
2269 // to prevent from memory leaks
2270 Free(command_string
);
2273 Free(command_string
);
2277 void TTCN_Runtime::process_create_mtc()
2279 switch (executor_state
) {
2284 TTCN_Communication::send_error("Message CREATE_MTC arrived in invalid "
2289 // clean Emergency log buffer before fork, to avoid duplication
2290 TTCN_Logger::ring_buffer_dump(false);
2292 pid_t mtc_pid
= fork();
2295 TTCN_Communication::send_create_nak(MTC_COMPREF
, "system call fork() "
2296 "failed (%s)", strerror(errno
));
2297 failed_process_creation();
2298 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2299 TTCN_Logger::log_event_str("System call fork() failed when creating "
2301 TTCN_Logger::OS_error();
2302 TTCN_Logger::end_event();
2303 } else if (mtc_pid
> 0) {
2304 // fork() was successful, this code runs on the parent process (HC)
2305 TTCN_Logger::log_mtc_created(mtc_pid
);
2306 add_component(MTC_COMPREF
, mtc_pid
);
2307 successful_process_creation();
2308 // let the HC's TTCN-3 Profiler know of the MTC
2309 ttcn3_prof
.add_child_process(mtc_pid
);
2311 // fork() was successful, this code runs on the child process (MTC)
2312 // The inherited epoll fd has to be closed first, and then the mc fd
2313 // (The inherited epoll fd shares its database with the parent process.)
2314 Fd_And_Timeout_User::reopenEpollFd();
2315 TTCN_Communication::close_mc_connection();
2317 executor_state
= MTC_INITIAL
;
2321 void TTCN_Runtime::process_create_ptc(component component_reference
,
2322 const char *component_type_module
, const char *component_type_name
,
2323 const char *par_component_name
, boolean par_is_alive
,
2324 const char *current_testcase_module
, const char *current_testcase_name
)
2326 switch (executor_state
) {
2331 TTCN_Communication::send_error("Message CREATE_PTC arrived in invalid "
2336 // clean Emergency log buffer before fork, to avoid duplication
2337 TTCN_Logger::ring_buffer_dump(false);
2339 pid_t ptc_pid
= fork();
2342 TTCN_Communication::send_create_nak(component_reference
, "system call "
2343 "fork() failed (%s)", strerror(errno
));
2344 failed_process_creation();
2345 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED
);
2346 TTCN_Logger::log_event("System call fork() failed when creating PTC "
2347 "with component reference %d.", component_reference
);
2348 TTCN_Logger::OS_error();
2349 TTCN_Logger::end_event();
2350 } else if (ptc_pid
> 0) {
2351 // fork() was successful, this code runs on the parent process (HC)
2352 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::ptc__created__pid
,
2353 component_type_module
, component_type_name
, component_reference
,
2354 par_component_name
, current_testcase_name
, ptc_pid
);
2355 add_component(component_reference
, ptc_pid
);
2356 COMPONENT::register_component_name(component_reference
,
2357 par_component_name
);
2358 successful_process_creation();
2359 // let the HC's TTCN-3 Profiler know of this new PTC
2360 ttcn3_prof
.add_child_process(ptc_pid
);
2362 // fork() was successful, this code runs on the child process (PTC)
2363 // The inherited epoll fd has to be closed first, and then the mc fd
2364 // (The inherited epoll fd shares its database with the parent process.)
2365 Fd_And_Timeout_User::reopenEpollFd();
2366 TTCN_Communication::close_mc_connection();
2367 self
= component_reference
;
2368 set_component_type(component_type_module
, component_type_name
);
2369 set_component_name(par_component_name
);
2370 is_alive
= par_is_alive
;
2371 set_testcase_name(current_testcase_module
, current_testcase_name
);
2372 executor_state
= PTC_INITIAL
;
2376 void TTCN_Runtime::process_create_ack(component new_component
)
2378 switch (executor_state
) {
2380 executor_state
= MTC_TESTCASE
;
2381 case MTC_TERMINATING_TESTCASE
:
2384 executor_state
= PTC_FUNCTION
;
2387 TTCN_error("Internal error: Message CREATE_ACK arrived in invalid "
2390 create_done_killed_compref
= new_component
;
2393 void TTCN_Runtime::process_running(boolean result_value
)
2395 switch (executor_state
) {
2397 executor_state
= MTC_TESTCASE
;
2398 case MTC_TERMINATING_TESTCASE
:
2401 executor_state
= PTC_FUNCTION
;
2404 TTCN_error("Internal error: Message RUNNING arrived in invalid state.");
2406 running_alive_result
= result_value
;
2409 void TTCN_Runtime::process_alive(boolean result_value
)
2411 switch (executor_state
) {
2413 executor_state
= MTC_TESTCASE
;
2414 case MTC_TERMINATING_TESTCASE
:
2417 executor_state
= PTC_FUNCTION
;
2420 TTCN_error("Internal error: Message ALIVE arrived in invalid state.");
2422 running_alive_result
= result_value
;
2425 void TTCN_Runtime::process_done_ack(boolean done_status
,
2426 const char *return_type
, int return_value_len
, const void *return_value
)
2428 switch (executor_state
) {
2430 executor_state
= MTC_TESTCASE
;
2431 case MTC_TERMINATING_TESTCASE
:
2434 executor_state
= PTC_FUNCTION
;
2437 TTCN_error("Internal error: Message DONE_ACK arrived in invalid "
2440 if (done_status
) set_component_done(create_done_killed_compref
,
2441 return_type
, return_value_len
, return_value
);
2442 create_done_killed_compref
= NULL_COMPREF
;
2445 void TTCN_Runtime::process_killed_ack(boolean killed_status
)
2447 switch (executor_state
) {
2449 executor_state
= MTC_TESTCASE
;
2450 case MTC_TERMINATING_TESTCASE
:
2453 executor_state
= PTC_FUNCTION
;
2456 TTCN_error("Internal error: Message KILLED_ACK arrived in invalid "
2459 if (killed_status
) set_component_killed(create_done_killed_compref
);
2460 create_done_killed_compref
= NULL_COMPREF
;
2463 void TTCN_Runtime::process_ptc_verdict(Text_Buf
& text_buf
)
2465 if (executor_state
!= MTC_TERMINATING_TESTCASE
)
2466 TTCN_error("Internal error: Message PTC_VERDICT arrived in invalid state.");
2468 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2469 local_verdict
, (const char *)verdict_reason
,
2470 TitanLoggerApi::FinalVerdictType_choice_notification::setting__final__verdict__of__the__test__case
);
2471 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2472 local_verdict
, (const char *)verdict_reason
);
2473 int n_ptcs
= text_buf
.pull_int().get_val();
2475 for (int i
= 0; i
< n_ptcs
; i
++) {
2476 component ptc_compref
= text_buf
.pull_int().get_val();
2477 char *ptc_name
= text_buf
.pull_string();
2478 verdicttype ptc_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
2479 char *ptc_verdict_reason
= text_buf
.pull_string();
2480 if (ptc_verdict
< NONE
|| ptc_verdict
> ERROR
) {
2482 TTCN_error("Internal error: Invalid PTC verdict was "
2483 "received from MC: %d.", ptc_verdict
);
2485 verdicttype new_verdict
= local_verdict
;
2486 if (ptc_verdict
> local_verdict
) {
2487 new_verdict
= ptc_verdict
;
2488 verdict_reason
= CHARSTRING(ptc_verdict_reason
);
2490 TTCN_Logger::log_final_verdict(true, ptc_verdict
, local_verdict
,
2491 new_verdict
, ptc_verdict_reason
, -1, ptc_compref
, ptc_name
);
2493 delete [] ptc_verdict_reason
;
2494 local_verdict
= new_verdict
;
2497 TTCN_Logger::log_final_verdict(false, local_verdict
, local_verdict
,
2498 local_verdict
, (const char *)verdict_reason
,
2499 TitanLoggerApi::FinalVerdictType_choice_notification::no__ptcs__were__created
);
2502 boolean continue_execution
= (boolean
)text_buf
.pull_int().get_val();
2503 if (continue_execution
) executor_state
= MTC_CONTROLPART
;
2504 else executor_state
= MTC_PAUSED
;
2507 void TTCN_Runtime::process_kill()
2510 TTCN_error("Internal error: Message KILL arrived in invalid state.");
2511 switch (executor_state
) {
2514 TTCN_Logger::log_par_ptc(API::ParallelPTC_reason::kill__request__frm__mc
);
2515 // This may affect the final verdict.
2516 terminate_component_type();
2517 // Send a KILLED message so that the value returned by previous behaviour
2518 // function remains active.
2519 TTCN_Communication::send_killed(local_verdict
);
2520 TTCN_Logger::log_final_verdict(true, local_verdict
, local_verdict
,
2521 local_verdict
, (const char *)verdict_reason
);
2522 executor_state
= PTC_EXIT
;
2526 TTCN_Logger::log_str(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2527 "Kill was requested from MC.");
2532 void TTCN_Runtime::process_kill_process(component component_reference
)
2534 if (!is_hc()) TTCN_error("Internal error: Message KILL_PROCESS arrived "
2535 "in invalid state.");
2536 component_process_struct
*comp
=
2537 get_component_by_compref(component_reference
);
2539 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2540 "Killing component with component reference %d, process id: %ld.",
2541 component_reference
, (long)comp
->process_id
);
2542 if (comp
->process_killed
) TTCN_warning("Process with process id %ld "
2543 "has been already killed. Killing it again.",
2544 (long)comp
->process_id
);
2545 if (kill(comp
->process_id
, SIGKILL
)) {
2546 if (errno
== ESRCH
) {
2548 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2549 "Process with process id %ld has already terminated.", (long)comp
->process_id
);
2550 } else TTCN_error("kill() system call failed on process id %ld.",
2551 (long)comp
->process_id
);
2553 comp
->process_killed
= TRUE
;
2555 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED
,
2556 "Component with component reference %d does not exist. "
2557 "Request for killing was ignored.", component_reference
);
2561 void TTCN_Runtime::set_component_done(component component_reference
,
2562 const char *return_type
, int return_value_len
,
2563 const void *return_value
)
2565 switch (component_reference
) {
2567 if (is_mtc()) any_component_done_status
= ALT_YES
;
2568 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2569 "ANY_COMPREF): can be used only on MTC.");
2572 if (is_mtc()) all_component_done_status
= ALT_YES
;
2573 else TTCN_error("Internal error: TTCN_Runtime::set_component_done("
2574 "ALL_COMPREF): can be used only on MTC.");
2578 case SYSTEM_COMPREF
:
2579 TTCN_error("Internal error: TTCN_Runtime::set_component_done: "
2580 "invalid component reference: %d.", component_reference
);
2583 int index
= get_component_status_table_index(component_reference
);
2584 component_status_table
[index
].done_status
= ALT_YES
;
2585 Free(component_status_table
[index
].return_type
);
2586 delete component_status_table
[index
].return_value
;
2587 if (return_type
!= NULL
&& return_type
[0] != '\0') {
2588 component_status_table
[index
].return_type
= mcopystr(return_type
);
2589 component_status_table
[index
].return_value
= new Text_Buf
;
2590 component_status_table
[index
].return_value
->push_raw(
2591 return_value_len
, return_value
);
2593 component_status_table
[index
].return_type
= NULL
;
2594 component_status_table
[index
].return_value
= NULL
;
2600 void TTCN_Runtime::set_component_killed(component component_reference
)
2602 switch (component_reference
) {
2604 if (is_mtc()) any_component_killed_status
= ALT_YES
;
2605 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2606 "ANY_COMPREF): can be used only on MTC.");
2609 if (is_mtc()) all_component_killed_status
= ALT_YES
;
2610 else TTCN_error("Internal error: TTCN_Runtime::set_component_killed("
2611 "ALL_COMPREF): can be used only on MTC.");
2615 case SYSTEM_COMPREF
:
2616 TTCN_error("Internal error: TTCN_Runtime::set_component_killed: "
2617 "invalid component reference: %d.", component_reference
);
2619 component_status_table
[get_component_status_table_index(
2620 component_reference
)].killed_status
= ALT_YES
;
2624 void TTCN_Runtime::cancel_component_done(component component_reference
)
2626 switch (component_reference
) {
2628 if (is_mtc()) any_component_done_status
= ALT_UNCHECKED
;
2629 else TTCN_error("Internal error: TTCN_Runtime::cancel_component_done("
2630 "ANY_COMPREF): can be used only on MTC.");
2635 case SYSTEM_COMPREF
:
2636 TTCN_error("Internal error: TTCN_Runtime::cancel_component_done: "
2637 "invalid component reference: %d.", component_reference
);
2639 if (in_component_status_table(component_reference
)) {
2640 int index
= get_component_status_table_index(component_reference
);
2641 component_status_table
[index
].done_status
= ALT_UNCHECKED
;
2642 Free(component_status_table
[index
].return_type
);
2643 component_status_table
[index
].return_type
= NULL
;
2644 delete component_status_table
[index
].return_value
;
2645 component_status_table
[index
].return_value
= NULL
;
2650 int TTCN_Runtime::get_component_status_table_index(
2651 component component_reference
)
2653 if (component_reference
< FIRST_PTC_COMPREF
) {
2654 TTCN_error("Internal error: TTCN_Runtime::"
2655 "get_component_status_table_index: invalid component reference: "
2656 "%d.", component_reference
);
2658 if (component_status_table_size
== 0) {
2659 // the table is empty
2660 // this will be the first entry
2661 component_status_table
= (component_status_table_struct
*)
2662 Malloc(sizeof(*component_status_table
));
2663 component_status_table
[0].done_status
= ALT_UNCHECKED
;
2664 component_status_table
[0].killed_status
= ALT_UNCHECKED
;
2665 component_status_table
[0].return_type
= NULL
;
2666 component_status_table
[0].return_value
= NULL
;
2667 component_status_table_size
= 1;
2668 component_status_table_offset
= component_reference
;
2670 } else if (component_reference
>= component_status_table_offset
) {
2671 // the table contains at least one entry that is smaller than
2672 // component_reference
2673 int component_index
=
2674 component_reference
- component_status_table_offset
;
2675 if (component_index
>= component_status_table_size
) {
2676 // component_reference is still not in the table
2677 // the table has to be extended at the end
2678 component_status_table
= (component_status_table_struct
*)
2679 Realloc(component_status_table
,
2680 (component_index
+ 1) * sizeof(*component_status_table
));
2681 // initializing the new table entries at the end
2682 for (int i
= component_status_table_size
;
2683 i
<= component_index
; i
++) {
2684 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2685 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2686 component_status_table
[i
].return_type
= NULL
;
2687 component_status_table
[i
].return_value
= NULL
;
2689 component_status_table_size
= component_index
+ 1;
2691 return component_index
;
2693 // component_reference has to be inserted before the existing table
2694 int offset_diff
= component_status_table_offset
- component_reference
;
2695 // offset_diff indicates how many new elements have to be inserted
2696 // before the existing table
2697 int new_size
= component_status_table_size
+ offset_diff
;
2698 component_status_table
= (component_status_table_struct
*)
2699 Realloc(component_status_table
,
2700 new_size
* sizeof(*component_status_table
));
2701 // moving forward the existing table
2702 memmove(component_status_table
+ offset_diff
, component_status_table
,
2703 component_status_table_size
* sizeof(*component_status_table
));
2704 // initializing the first table entries
2705 for (int i
= 0; i
< offset_diff
; i
++) {
2706 component_status_table
[i
].done_status
= ALT_UNCHECKED
;
2707 component_status_table
[i
].killed_status
= ALT_UNCHECKED
;
2708 component_status_table
[i
].return_type
= NULL
;
2709 component_status_table
[i
].return_value
= NULL
;
2711 component_status_table_size
= new_size
;
2712 component_status_table_offset
= component_reference
;
2717 alt_status
TTCN_Runtime::get_killed_status(component component_reference
)
2719 return component_status_table
2720 [get_component_status_table_index(component_reference
)].killed_status
;
2723 boolean
TTCN_Runtime::in_component_status_table(component component_reference
)
2725 return component_reference
>= component_status_table_offset
&&
2726 component_reference
<
2727 component_status_table_size
+ component_status_table_offset
;
2730 void TTCN_Runtime::clear_component_status_table()
2732 for (component i
= 0; i
< component_status_table_size
; i
++) {
2733 Free(component_status_table
[i
].return_type
);
2734 delete component_status_table
[i
].return_value
;
2736 Free(component_status_table
);
2737 component_status_table
= NULL
;
2738 component_status_table_size
= 0;
2739 component_status_table_offset
= FIRST_PTC_COMPREF
;
2742 #define HASHTABLE_SIZE 97
2744 void TTCN_Runtime::initialize_component_process_tables()
2746 components_by_compref
= new component_process_struct
*[HASHTABLE_SIZE
];
2747 components_by_pid
= new component_process_struct
*[HASHTABLE_SIZE
];
2748 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2749 components_by_compref
[i
] = NULL
;
2750 components_by_pid
[i
] = NULL
;
2754 void TTCN_Runtime::add_component(component component_reference
,
2757 if (component_reference
!= MTC_COMPREF
&&
2758 get_component_by_compref(component_reference
) != NULL
)
2759 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2760 "duplicated component reference (%d)", component_reference
);
2761 if (get_component_by_pid(process_id
) != NULL
)
2762 TTCN_error("Internal error: TTCN_Runtime::add_component: "
2763 "duplicated pid (%ld)", (long)process_id
);
2765 component_process_struct
*new_comp
= new component_process_struct
;
2766 new_comp
->component_reference
= component_reference
;
2767 new_comp
->process_id
= process_id
;
2768 new_comp
->process_killed
= FALSE
;
2770 new_comp
->prev_by_compref
= NULL
;
2771 component_process_struct
*& head_by_compref
=
2772 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2773 new_comp
->next_by_compref
= head_by_compref
;
2774 if (head_by_compref
!= NULL
) head_by_compref
->prev_by_compref
= new_comp
;
2775 head_by_compref
= new_comp
;
2777 new_comp
->prev_by_pid
= NULL
;
2778 component_process_struct
*& head_by_pid
=
2779 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2780 new_comp
->next_by_pid
= head_by_pid
;
2781 if (head_by_pid
!= NULL
) head_by_pid
->prev_by_pid
= new_comp
;
2782 head_by_pid
= new_comp
;
2785 void TTCN_Runtime::remove_component(component_process_struct
*comp
)
2787 if (comp
->next_by_compref
!= NULL
)
2788 comp
->next_by_compref
->prev_by_compref
= comp
->prev_by_compref
;
2789 if (comp
->prev_by_compref
!= NULL
)
2790 comp
->prev_by_compref
->next_by_compref
= comp
->next_by_compref
;
2791 else components_by_compref
[comp
->component_reference
% HASHTABLE_SIZE
] =
2792 comp
->next_by_compref
;
2793 if (comp
->next_by_pid
!= NULL
)
2794 comp
->next_by_pid
->prev_by_pid
= comp
->prev_by_pid
;
2795 if (comp
->prev_by_pid
!= NULL
)
2796 comp
->prev_by_pid
->next_by_pid
= comp
->next_by_pid
;
2797 else components_by_pid
[comp
->process_id
% HASHTABLE_SIZE
] =
2802 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_compref(
2803 component component_reference
)
2805 component_process_struct
*iter
=
2806 components_by_compref
[component_reference
% HASHTABLE_SIZE
];
2807 while (iter
!= NULL
) {
2808 if (iter
->component_reference
== component_reference
) break;
2809 iter
= iter
->next_by_compref
;
2814 TTCN_Runtime::component_process_struct
*TTCN_Runtime::get_component_by_pid(
2817 component_process_struct
*iter
=
2818 components_by_pid
[process_id
% HASHTABLE_SIZE
];
2819 while (iter
!= NULL
) {
2820 if (iter
->process_id
== process_id
) break;
2821 iter
= iter
->next_by_pid
;
2826 void TTCN_Runtime::clear_component_process_tables()
2828 if (components_by_compref
== NULL
) return;
2829 for (unsigned int i
= 0; i
< HASHTABLE_SIZE
; i
++) {
2830 while (components_by_compref
[i
] != NULL
)
2831 remove_component(components_by_compref
[i
]);
2832 while (components_by_pid
[i
] != NULL
)
2833 remove_component(components_by_pid
[i
]);
2835 delete [] components_by_compref
;
2836 components_by_compref
= NULL
;
2837 delete [] components_by_pid
;
2838 components_by_pid
= NULL
;
2841 void TTCN_Runtime::successful_process_creation()
2843 if (is_overloaded()) {
2844 TTCN_Communication::send_hc_ready();
2845 TTCN_Communication::disable_periodic_call();
2846 executor_state
= HC_ACTIVE
;
2850 void TTCN_Runtime::failed_process_creation()
2852 if (executor_state
== HC_ACTIVE
) {
2853 TTCN_Communication::enable_periodic_call();
2854 executor_state
= HC_OVERLOADED
;
2858 void TTCN_Runtime::wait_terminated_processes()
2860 // this function might be called from TCs too while returning from
2861 // TTCN_Communication::process_all_messages_hc() after fork()
2862 if (!is_hc()) return;
2866 struct rusage r_usage
= {{0,0},{0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2868 pid_t child_pid
= waitpid(-1, &statuscode
, WNOHANG
);
2869 getrusage(RUSAGE_CHILDREN
, &r_usage
);
2871 pid_t child_pid
= wait3(&statuscode
, WNOHANG
, &r_usage
);
2873 if (child_pid
<= 0) {
2881 TTCN_error("System call wait3() failed when waiting for "
2882 "terminated test component processes.");
2885 component_process_struct
*comp
= get_component_by_pid(child_pid
);
2888 const char *comp_name
= NULL
;
2889 if (comp
->component_reference
== MTC_COMPREF
) {
2890 reason
= API::ParallelPTC_reason::mtc__finished
;
2893 reason
= API::ParallelPTC_reason::ptc__finished
;
2894 comp_name
= COMPONENT::get_component_name(comp
->component_reference
);
2896 char *rusage
= NULL
;
2898 "user time: %ld.%06ld s, system time: %ld.%06ld s, "
2899 "maximum resident set size: %ld, "
2900 "integral resident set size: %ld, "
2901 "page faults not requiring physical I/O: %ld, "
2902 "page faults requiring physical I/O: %ld, "
2904 "block input operations: %ld, block output operations: %ld, "
2905 "messages sent: %ld, messages received: %ld, "
2906 "signals received: %ld, "
2907 "voluntary context switches: %ld, "
2908 "involuntary context switches: %ld }",
2909 (long)r_usage
.ru_utime
.tv_sec
, r_usage
.ru_utime
.tv_usec
,
2910 (long)r_usage
.ru_stime
.tv_sec
, r_usage
.ru_stime
.tv_usec
,
2911 r_usage
.ru_maxrss
, r_usage
.ru_idrss
,
2912 r_usage
.ru_minflt
, r_usage
.ru_majflt
, r_usage
.ru_nswap
,
2913 r_usage
.ru_inblock
, r_usage
.ru_oublock
,
2914 r_usage
.ru_msgsnd
, r_usage
.ru_msgrcv
, r_usage
.ru_nsignals
,
2915 r_usage
.ru_nvcsw
, r_usage
.ru_nivcsw
);
2916 // There are too many different integer types in the rusage structure.
2917 // Just format them into a string and and pass that to the logger.
2918 TTCN_Logger::log_par_ptc(reason
, NULL
, NULL
,
2919 comp
->component_reference
, comp_name
, rusage
, child_pid
, statuscode
);
2921 remove_component(comp
);
2923 TTCN_warning("wait3() system call returned unknown process id %ld.",
2929 void TTCN_Runtime::check_overload()
2931 if (!is_hc()) TTCN_error("Internal error: TTCN_Runtime::check_overload() "
2932 "can be used on HCs only.");
2933 if (!is_overloaded()) return;
2934 TTCN_Logger::log_executor_runtime(
2935 API::ExecutorRuntime_reason::overload__check
);
2936 pid_t child_pid
= fork();
2937 if (child_pid
< 0) {
2938 // fork failed, the host is still overloaded
2939 TTCN_Logger::log_executor_runtime(
2940 API::ExecutorRuntime_reason::overload__check__fail
);
2941 //TODO TTCN_Logger::OS_error();
2942 if (executor_state
== HC_OVERLOADED_TIMEOUT
) {
2943 // increase the call interval if the function was called because of
2945 TTCN_Communication::increase_call_interval();
2946 executor_state
= HC_OVERLOADED
;
2948 } else if (child_pid
> 0) {
2949 // fork was successful, this code runs on the parent process (HC)
2951 // wait until the dummy child terminates
2952 pid_t result_pid
= waitpid(child_pid
, &statuscode
, 0);
2953 if (result_pid
!= child_pid
) TTCN_error("System call waitpid() "
2954 "returned unexpected status code %ld when waiting for the dummy "
2955 "child process with PID %ld.", (long)result_pid
, (long)child_pid
);
2956 successful_process_creation();
2957 TTCN_Logger::log_executor_runtime(
2958 API::ExecutorRuntime_reason::overloaded__no__more
);
2959 // FIXME pid is not logged; it would need a separate function
2961 // analyze the status code and issue a warning if something strange
2963 if (WIFEXITED(statuscode
)) {
2964 int exitstatus
= WEXITSTATUS(statuscode
);
2965 if (exitstatus
!= EXIT_SUCCESS
) TTCN_warning("Dummy child process "
2966 "with PID %ld returned unsuccessful exit status (%d).",
2967 (long)child_pid
, exitstatus
);
2968 } else if (WIFSIGNALED(statuscode
)) {
2969 int signum
= WTERMSIG(statuscode
);
2970 TTCN_warning("Dummy child process with PID %ld was terminated by "
2971 "signal %d (%s).", (long)child_pid
, signum
,
2972 get_signal_name(signum
));
2974 TTCN_warning("Dummy child process with PID %ld was terminated by "
2975 "an unknown reason (return status: %d).", (long)child_pid
,
2978 // try to clean up some more zombies if possible
2979 wait_terminated_processes();
2981 // fork was successful, this code runs on the dummy child process
2982 // the dummy child process shall exit immediately