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