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