Merge pull request #63 from BenceJanosSzabo/master
[deliverable/titan.core.git] / core / Runtime.cc
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
19 * Szabo, Bence Janos
20 * Szabo, Janos Zoltan – initial implementation
21 * Zalanyi, Balazs Andor
22 * Pandi, Krisztian
23 *
24 ******************************************************************************/
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>
61 #include "Profiler.hh"
62
63 namespace API = TitanLoggerApi;
64
65 #ifndef MAXHOSTNAMELEN
66 # define MAXHOSTNAMELEN 256
67 #endif
68
69 #include "../common/dbgnew.hh"
70
71 TTCN_Runtime::executor_state_enum
72 TTCN_Runtime::executor_state = UNDEFINED_STATE;
73
74 qualified_name TTCN_Runtime::component_type = { NULL, NULL };
75 char *TTCN_Runtime::component_name = NULL;
76 boolean TTCN_Runtime::is_alive = FALSE;
77
78 const char *TTCN_Runtime::control_module_name = NULL;
79 qualified_name TTCN_Runtime::testcase_name = { NULL, NULL };
80
81 char *TTCN_Runtime::host_name = NULL;
82
83 verdicttype TTCN_Runtime::local_verdict = NONE;
84 unsigned int TTCN_Runtime::verdict_count[5] = { 0, 0, 0, 0, 0 },
85 TTCN_Runtime::control_error_count = 0;
86 CHARSTRING TTCN_Runtime::verdict_reason(0, ""); // empty string
87
88 boolean TTCN_Runtime::in_ttcn_try_block = FALSE;
89
90 char *TTCN_Runtime::begin_controlpart_command = NULL,
91 *TTCN_Runtime::end_controlpart_command = NULL,
92 *TTCN_Runtime::begin_testcase_command = NULL,
93 *TTCN_Runtime::end_testcase_command = NULL;
94
95 component TTCN_Runtime::create_done_killed_compref = NULL_COMPREF;
96 boolean TTCN_Runtime::running_alive_result = FALSE;
97
98 alt_status TTCN_Runtime::any_component_done_status = ALT_UNCHECKED,
99 TTCN_Runtime::all_component_done_status = ALT_UNCHECKED,
100 TTCN_Runtime::any_component_killed_status = ALT_UNCHECKED,
101 TTCN_Runtime::all_component_killed_status = ALT_UNCHECKED;
102 int TTCN_Runtime::component_status_table_size = 0;
103 component TTCN_Runtime::component_status_table_offset = FIRST_PTC_COMPREF;
104 struct TTCN_Runtime::component_status_table_struct {
105 alt_status done_status, killed_status;
106 char *return_type;
107 Text_Buf *return_value;
108 } *TTCN_Runtime::component_status_table = NULL;
109
110 struct 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
119 boolean 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
134 boolean 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
141 void 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
149 void 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
157 void 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
169 void 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
187 void 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
208 void 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
225 void 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
233 void 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
250 const 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
285 CHARSTRING 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 }
304 }
305 if (type == "Ipv6") {
306 #if defined(LINUX) || defined(CYGWIN17)
307 const IPv6Address * ipv6 = dynamic_cast<const IPv6Address*>(address);
308 if (ipv6 == NULL)
309 #endif // LINUX || CYGWIN17
310 return CHARSTRING("");
311 }
312 // Return the string representation of the address
313 return CHARSTRING(address->get_addr_str());
314 }
315
316 CHARSTRING 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
327 CHARSTRING TTCN_Runtime::get_testcasename()
328 {
329 if (in_controlpart() || is_hc()) return CHARSTRING(""); // No error here.
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
338 void TTCN_Runtime::load_logger_plugins()
339 {
340 TTCN_Logger::load_plugins((component)self, component_name);
341 }
342
343 void TTCN_Runtime::set_logger_parameters()
344 {
345 TTCN_Logger::set_plugin_parameters((component)self, component_name);
346 }
347
348 const 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
355 static 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
379 void 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
393 void 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
407 void 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
420 void TTCN_Runtime::enable_interrupt_handler()
421 {
422 set_signal_handler(SIGINT, "SIGINT", sigint_handler);
423 }
424
425 void TTCN_Runtime::disable_interrupt_handler()
426 {
427 ignore_signal(SIGINT, "SIGINT");
428 }
429
430 void TTCN_Runtime::install_signal_handlers()
431 {
432 if (is_single()) set_signal_handler(SIGINT, "SIGINT", sigint_handler);
433 ignore_signal(SIGPIPE, "SIGPIPE");
434 }
435
436 void TTCN_Runtime::restore_signal_handlers()
437 {
438 if (is_single()) restore_default_handler(SIGINT, "SIGINT");
439 restore_default_handler(SIGPIPE, "SIGPIPE");
440 }
441
442 int 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();
455 Module_List::send_versions();
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
483 int 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
509 int 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) {
537 if (ttcn3_debugger.is_activated()) {
538 ttcn3_debugger.open_output_file();
539 }
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
572 component TTCN_Runtime::create_component(
573 const char *created_component_type_module,
574 const char *created_component_type_name, const char *created_component_name,
575 const char *created_component_location, boolean created_component_alive)
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
643 void 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
685 void 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
709 void 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
762 void 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
771 void 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
792 void 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
806 void 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
815 alt_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
838 alt_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
916 alt_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
939 boolean 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
962 boolean 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
985 void 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
1011 void 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
1029 void 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
1056 void 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
1064 alt_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
1108 alt_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
1151 alt_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
1182 alt_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
1223 alt_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
1263 alt_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
1292 boolean 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
1332 boolean 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
1354 boolean 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
1375 boolean 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
1410 boolean 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
1430 boolean 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
1457 void 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
1464 void 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
1507 void 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
1534 void 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
1576 void 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
1602 void 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
1615 void 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
1690 void 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
1765 void 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
1843 void 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
1921 void 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
1928 void 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
1938 void 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
1952 void TTCN_Runtime::begin_testcase(
1953 const char *par_module_name, const char *par_testcase_name,
1954 const char *mtc_comptype_module, const char *mtc_comptype_name,
1955 const char *system_comptype_module, const char *system_comptype_name,
1956 boolean has_timer, double timer_value)
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
1990 verdicttype 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
2062 void 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
2101 void TTCN_Runtime::begin_action()
2102 {
2103 TTCN_Logger::begin_event(TTCN_Logger::ACTION_UNQUALIFIED);
2104 TTCN_Logger::log_event_str("Action: ");
2105 }
2106
2107 void TTCN_Runtime::end_action()
2108 {
2109 TTCN_Logger::end_event();
2110 }
2111
2112 void 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
2125 void 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
2132 void 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
2138 verdicttype 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
2149 void 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 }
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 }
2173 }
2174
2175 void 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
2181 void 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
2187 void 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
2193 void 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
2199 void 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
2211 char *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
2273 void 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
2309 void 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();
2340 // let the HC's TTCN-3 Profiler know of the MTC
2341 ttcn3_prof.add_child_process(mtc_pid);
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
2353 void TTCN_Runtime::process_create_ptc(component component_reference,
2354 const char *component_type_module, const char *component_type_name,
2355 const char *par_component_name, boolean par_is_alive,
2356 const char *current_testcase_module, const char *current_testcase_name)
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();
2391 // let the HC's TTCN-3 Profiler know of this new PTC
2392 ttcn3_prof.add_child_process(ptc_pid);
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
2408 void 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
2425 void 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
2441 void 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
2457 void 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
2477 void 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
2495 void 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 }
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 }
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
2539 void 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
2564 void 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
2593 void 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
2632 void 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
2656 void 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
2682 int 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
2749 alt_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
2755 boolean 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
2762 void 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
2776 void 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
2786 void 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
2817 void 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
2834 TTCN_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
2846 TTCN_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
2858 void 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
2873 void 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
2882 void 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
2890 void 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;
2898 struct rusage r_usage = {{0,0},{0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2899 #ifdef INTERIX
2900 pid_t child_pid = waitpid(-1, &statuscode, WNOHANG);
2901 getrusage(RUSAGE_CHILDREN, &r_usage);
2902 #else
2903 pid_t child_pid = wait3(&statuscode, WNOHANG, &r_usage);
2904 #endif
2905 if (child_pid <= 0) {
2906 switch (errno) {
2907 case ECHILD:
2908 errno = 0;
2909 // no break
2910 case 0:
2911 return;
2912 default:
2913 TTCN_error("System call wait3() failed when waiting for "
2914 "terminated test component processes.");
2915 }
2916 }
2917 component_process_struct *comp = get_component_by_pid(child_pid);
2918 if (comp != NULL) {
2919 int reason;
2920 const char *comp_name = NULL;
2921 if (comp->component_reference == MTC_COMPREF) {
2922 reason = API::ParallelPTC_reason::mtc__finished;
2923 }
2924 else {
2925 reason = API::ParallelPTC_reason::ptc__finished;
2926 comp_name = COMPONENT::get_component_name(comp->component_reference);
2927 }
2928 char *rusage = NULL;
2929 rusage = mprintf(
2930 "user time: %ld.%06ld s, system time: %ld.%06ld s, "
2931 "maximum resident set size: %ld, "
2932 "integral resident set size: %ld, "
2933 "page faults not requiring physical I/O: %ld, "
2934 "page faults requiring physical I/O: %ld, "
2935 "swaps: %ld, "
2936 "block input operations: %ld, block output operations: %ld, "
2937 "messages sent: %ld, messages received: %ld, "
2938 "signals received: %ld, "
2939 "voluntary context switches: %ld, "
2940 "involuntary context switches: %ld }",
2941 (long)r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,
2942 (long)r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec,
2943 r_usage.ru_maxrss, r_usage.ru_idrss,
2944 r_usage.ru_minflt, r_usage.ru_majflt, r_usage.ru_nswap,
2945 r_usage.ru_inblock, r_usage.ru_oublock,
2946 r_usage.ru_msgsnd, r_usage.ru_msgrcv, r_usage.ru_nsignals,
2947 r_usage.ru_nvcsw, r_usage.ru_nivcsw);
2948 // There are too many different integer types in the rusage structure.
2949 // Just format them into a string and and pass that to the logger.
2950 TTCN_Logger::log_par_ptc(reason, NULL, NULL,
2951 comp->component_reference, comp_name, rusage, child_pid, statuscode);
2952 Free(rusage);
2953 remove_component(comp);
2954 } else {
2955 TTCN_warning("wait3() system call returned unknown process id %ld.",
2956 (long)child_pid);
2957 }
2958 }
2959 }
2960
2961 void TTCN_Runtime::check_overload()
2962 {
2963 if (!is_hc()) TTCN_error("Internal error: TTCN_Runtime::check_overload() "
2964 "can be used on HCs only.");
2965 if (!is_overloaded()) return;
2966 TTCN_Logger::log_executor_runtime(
2967 API::ExecutorRuntime_reason::overload__check);
2968 pid_t child_pid = fork();
2969 if (child_pid < 0) {
2970 // fork failed, the host is still overloaded
2971 TTCN_Logger::log_executor_runtime(
2972 API::ExecutorRuntime_reason::overload__check__fail);
2973 //TODO TTCN_Logger::OS_error();
2974 if (executor_state == HC_OVERLOADED_TIMEOUT) {
2975 // increase the call interval if the function was called because of
2976 // a timeout
2977 TTCN_Communication::increase_call_interval();
2978 executor_state = HC_OVERLOADED;
2979 }
2980 } else if (child_pid > 0) {
2981 // fork was successful, this code runs on the parent process (HC)
2982 int statuscode;
2983 // wait until the dummy child terminates
2984 pid_t result_pid = waitpid(child_pid, &statuscode, 0);
2985 if (result_pid != child_pid) TTCN_error("System call waitpid() "
2986 "returned unexpected status code %ld when waiting for the dummy "
2987 "child process with PID %ld.", (long)result_pid, (long)child_pid);
2988 successful_process_creation();
2989 TTCN_Logger::log_executor_runtime(
2990 API::ExecutorRuntime_reason::overloaded__no__more);
2991 // FIXME pid is not logged; it would need a separate function
2992
2993 // analyze the status code and issue a warning if something strange
2994 // happened
2995 if (WIFEXITED(statuscode)) {
2996 int exitstatus = WEXITSTATUS(statuscode);
2997 if (exitstatus != EXIT_SUCCESS) TTCN_warning("Dummy child process "
2998 "with PID %ld returned unsuccessful exit status (%d).",
2999 (long)child_pid, exitstatus);
3000 } else if (WIFSIGNALED(statuscode)) {
3001 int signum = WTERMSIG(statuscode);
3002 TTCN_warning("Dummy child process with PID %ld was terminated by "
3003 "signal %d (%s).", (long)child_pid, signum,
3004 get_signal_name(signum));
3005 } else {
3006 TTCN_warning("Dummy child process with PID %ld was terminated by "
3007 "an unknown reason (return status: %d).", (long)child_pid,
3008 statuscode);
3009 }
3010 // try to clean up some more zombies if possible
3011 wait_terminated_processes();
3012 } else {
3013 // fork was successful, this code runs on the dummy child process
3014 // the dummy child process shall exit immediately
3015 exit(EXIT_SUCCESS);
3016 }
3017 }
This page took 0.092462 seconds and 5 git commands to generate.