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