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