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