| 1 | /****************************************************************************** |
| 2 | * Copyright (c) 2000-2016 Ericsson Telecom AB |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * Baji, Laszlo |
| 10 | * Balasko, Jeno |
| 11 | * Baranyi, Botond |
| 12 | * Delic, Adam |
| 13 | * Forstner, Matyas |
| 14 | * Kovacs, Ferenc |
| 15 | * Raduly, Csaba |
| 16 | * Szabados, Kristof |
| 17 | * Szabo, Janos Zoltan – initial implementation |
| 18 | * Zalanyi, Balazs Andor |
| 19 | * |
| 20 | ******************************************************************************/ |
| 21 | #ifndef RUNTIME_HH |
| 22 | #define RUNTIME_HH |
| 23 | |
| 24 | #include <sys/types.h> |
| 25 | #include "Types.h" |
| 26 | |
| 27 | class Text_Buf; |
| 28 | class COMPONENT; |
| 29 | class VERDICTTYPE; |
| 30 | class CHARSTRING; |
| 31 | |
| 32 | extern "C" { |
| 33 | typedef void (*signal_handler_type)(int); |
| 34 | } |
| 35 | |
| 36 | /** @brief |
| 37 | */ |
| 38 | class TTCN_Runtime { |
| 39 | public: |
| 40 | enum executor_state_enum { |
| 41 | UNDEFINED_STATE, // 0 |
| 42 | |
| 43 | SINGLE_CONTROLPART, SINGLE_TESTCASE, // 1,2 |
| 44 | |
| 45 | HC_INITIAL, HC_IDLE, HC_CONFIGURING, HC_ACTIVE, HC_OVERLOADED, // 3-7 |
| 46 | HC_OVERLOADED_TIMEOUT, HC_EXIT, // 8-9 |
| 47 | |
| 48 | MTC_INITIAL, MTC_IDLE, MTC_CONTROLPART, MTC_TESTCASE, // 10-13 |
| 49 | MTC_TERMINATING_TESTCASE, MTC_TERMINATING_EXECUTION, MTC_PAUSED, // 14-16 |
| 50 | MTC_CREATE, MTC_START, MTC_STOP, MTC_KILL, MTC_RUNNING, MTC_ALIVE, // 17-22 |
| 51 | MTC_DONE, MTC_KILLED, MTC_CONNECT, MTC_DISCONNECT, MTC_MAP, MTC_UNMAP, // 23-28 |
| 52 | MTC_EXIT, // 29 |
| 53 | |
| 54 | PTC_INITIAL, PTC_IDLE, PTC_FUNCTION, PTC_CREATE, PTC_START, PTC_STOP, // 30-35 |
| 55 | PTC_KILL, PTC_RUNNING, PTC_ALIVE, PTC_DONE, PTC_KILLED, PTC_CONNECT, // 36-41 |
| 56 | PTC_DISCONNECT, PTC_MAP, PTC_UNMAP, PTC_STOPPED, PTC_EXIT // 42-46 |
| 57 | }; |
| 58 | private: |
| 59 | static executor_state_enum executor_state; |
| 60 | |
| 61 | static qualified_name component_type; |
| 62 | static char *component_name; |
| 63 | static boolean is_alive; |
| 64 | |
| 65 | static const char *control_module_name; |
| 66 | static qualified_name testcase_name; |
| 67 | |
| 68 | static char *host_name; |
| 69 | |
| 70 | static verdicttype local_verdict; |
| 71 | static unsigned int verdict_count[5], control_error_count; |
| 72 | static CHARSTRING verdict_reason; |
| 73 | |
| 74 | /** TTCN_TryBlock uses the private member in_ttcn_try_block */ |
| 75 | friend class TTCN_TryBlock; |
| 76 | /** true if execution is currently inside a TTCN-3 try{} */ |
| 77 | static boolean in_ttcn_try_block; |
| 78 | |
| 79 | static char *begin_controlpart_command, *end_controlpart_command, |
| 80 | *begin_testcase_command, *end_testcase_command; |
| 81 | |
| 82 | static component create_done_killed_compref; |
| 83 | static boolean running_alive_result; |
| 84 | |
| 85 | static alt_status any_component_done_status, all_component_done_status, |
| 86 | any_component_killed_status, all_component_killed_status; |
| 87 | static int component_status_table_size; |
| 88 | static component component_status_table_offset; |
| 89 | struct component_status_table_struct; |
| 90 | static component_status_table_struct *component_status_table; |
| 91 | |
| 92 | struct component_process_struct; |
| 93 | static component_process_struct **components_by_compref, |
| 94 | **components_by_pid; |
| 95 | |
| 96 | public: |
| 97 | inline static executor_state_enum get_state() { return executor_state; } |
| 98 | inline static void set_state(executor_state_enum new_state) |
| 99 | { executor_state = new_state; } |
| 100 | |
| 101 | /** @name Identifying the type |
| 102 | * @{ |
| 103 | */ |
| 104 | inline static boolean is_hc() |
| 105 | { return executor_state >= HC_INITIAL && executor_state <= HC_EXIT; } |
| 106 | inline static boolean is_mtc() |
| 107 | { return executor_state >= MTC_INITIAL && executor_state <= MTC_EXIT; } |
| 108 | inline static boolean is_ptc() |
| 109 | { return executor_state >= PTC_INITIAL && executor_state <= PTC_EXIT; } |
| 110 | inline static boolean is_tc() |
| 111 | { return executor_state >= MTC_INITIAL && executor_state <= PTC_EXIT; } |
| 112 | inline static boolean is_single() |
| 113 | { return executor_state >= SINGLE_CONTROLPART && |
| 114 | executor_state <= SINGLE_TESTCASE; } |
| 115 | inline static boolean is_undefined() /* e.g.: when listing test cases (<EXE> -l) */ |
| 116 | { return executor_state == UNDEFINED_STATE; } |
| 117 | static boolean is_idle(); |
| 118 | inline static boolean is_overloaded() |
| 119 | { return executor_state == HC_OVERLOADED || |
| 120 | executor_state == HC_OVERLOADED_TIMEOUT; } |
| 121 | /** @} */ |
| 122 | |
| 123 | static boolean is_in_ttcn_try_block() { return in_ttcn_try_block; } |
| 124 | |
| 125 | private: |
| 126 | inline static boolean in_controlpart() |
| 127 | { return executor_state == SINGLE_CONTROLPART || |
| 128 | executor_state == MTC_CONTROLPART; } |
| 129 | /** Whether verdict operations are allowed */ |
| 130 | static boolean verdict_enabled(); |
| 131 | static void wait_for_state_change(); |
| 132 | static void clear_qualified_name(qualified_name& q_name); |
| 133 | static void clean_up(); |
| 134 | |
| 135 | static void initialize_component_type(); |
| 136 | static void terminate_component_type(); |
| 137 | |
| 138 | public: |
| 139 | static void set_component_type(const char *component_type_module, |
| 140 | const char *component_type_name); |
| 141 | static void set_component_name(const char *new_component_name); |
| 142 | inline static void set_alive_flag(boolean par_is_alive) |
| 143 | { is_alive = par_is_alive; } |
| 144 | static void set_testcase_name(const char *par_module_name, |
| 145 | const char *par_testcase_name); |
| 146 | |
| 147 | inline static const char *get_component_type() |
| 148 | { return component_type.definition_name; } |
| 149 | inline static const char *get_component_name() |
| 150 | { return component_name; } |
| 151 | inline static const char *get_testcase_name() |
| 152 | { return testcase_name.definition_name; } |
| 153 | |
| 154 | /// Returns a string which must not be freed. |
| 155 | static const char *get_host_name(); |
| 156 | |
| 157 | static CHARSTRING get_testcase_id_macro(); |
| 158 | static CHARSTRING get_testcasename(); |
| 159 | |
| 160 | static void load_logger_plugins(); |
| 161 | static void set_logger_parameters(); |
| 162 | |
| 163 | static const char *get_signal_name(int signal_number); |
| 164 | private: |
| 165 | static void set_signal_handler(int signal_number, const char *signal_name, |
| 166 | signal_handler_type signal_handler); |
| 167 | static void restore_default_handler(int signal_number, |
| 168 | const char *signal_name); |
| 169 | static void ignore_signal(int signal_number, const char *signal_name); |
| 170 | static void enable_interrupt_handler(); |
| 171 | static void disable_interrupt_handler(); |
| 172 | public: |
| 173 | static void install_signal_handlers(); |
| 174 | static void restore_signal_handlers(); |
| 175 | |
| 176 | public: |
| 177 | static int hc_main(const char *local_addr, const char *MC_addr, |
| 178 | unsigned short MC_port); |
| 179 | static int mtc_main(); |
| 180 | static int ptc_main(); |
| 181 | |
| 182 | static component create_component(const char *created_component_type_module, |
| 183 | const char *created_component_type_name, |
| 184 | const char *created_component_name, |
| 185 | const char *created_component_location, |
| 186 | boolean created_component_alive); |
| 187 | static void prepare_start_component(const COMPONENT& component_reference, |
| 188 | const char *module_name, const char *function_name, |
| 189 | Text_Buf& text_buf); |
| 190 | static void send_start_component(Text_Buf& text_buf); |
| 191 | static void start_function(const char *module_name, |
| 192 | const char *function_name, Text_Buf& text_buf); |
| 193 | static void function_started(Text_Buf& text_buf); |
| 194 | static void prepare_function_finished(const char *return_type, |
| 195 | Text_Buf& text_buf); |
| 196 | static void send_function_finished(Text_Buf& text_buf); |
| 197 | static void function_finished(const char *function_name); |
| 198 | |
| 199 | static alt_status component_done(component component_reference); |
| 200 | static alt_status component_done(component component_reference, |
| 201 | const char *return_type, Text_Buf*& text_buf); |
| 202 | static alt_status component_killed(component component_reference); |
| 203 | static boolean component_running(component component_reference); |
| 204 | static boolean component_alive(component component_reference); |
| 205 | static void stop_component(component component_reference); |
| 206 | static void stop_execution() |
| 207 | __attribute__ ((__noreturn__)); |
| 208 | static void kill_component(component component_reference); |
| 209 | static void kill_execution() |
| 210 | __attribute__ ((__noreturn__)); |
| 211 | |
| 212 | private: |
| 213 | static alt_status ptc_done(component component_reference); |
| 214 | static alt_status any_component_done(); |
| 215 | static alt_status all_component_done(); |
| 216 | static alt_status ptc_killed(component component_reference); |
| 217 | static alt_status any_component_killed(); |
| 218 | static alt_status all_component_killed(); |
| 219 | static boolean ptc_running(component component_reference); |
| 220 | static boolean any_component_running(); |
| 221 | static boolean all_component_running(); |
| 222 | static boolean ptc_alive(component component_reference); |
| 223 | static boolean any_component_alive(); |
| 224 | static boolean all_component_alive(); |
| 225 | static void stop_mtc() |
| 226 | __attribute__ ((__noreturn__)); |
| 227 | static void stop_ptc(component component_reference); |
| 228 | static void stop_all_component(); |
| 229 | static void kill_ptc(component component_reference); |
| 230 | static void kill_all_component(); |
| 231 | |
| 232 | static void check_port_name(const char *port_name, |
| 233 | const char *operation_name, const char *which_argument); |
| 234 | public: |
| 235 | static void connect_port( |
| 236 | const COMPONENT& src_compref, const char *src_port, |
| 237 | const COMPONENT& dst_compref, const char *dst_port); |
| 238 | static void disconnect_port( |
| 239 | const COMPONENT& src_compref, const char *src_port, |
| 240 | const COMPONENT& dst_compref, const char *dst_port); |
| 241 | static void map_port( |
| 242 | const COMPONENT& src_compref, const char *src_port, |
| 243 | const COMPONENT& dst_compref, const char *dst_port); |
| 244 | static void unmap_port( |
| 245 | const COMPONENT& src_compref, const char *src_port, |
| 246 | const COMPONENT& dst_compref, const char *dst_port); |
| 247 | |
| 248 | static void begin_controlpart(const char *module_name); |
| 249 | static void end_controlpart(); |
| 250 | static void check_begin_testcase(boolean has_timer, double timer_value); |
| 251 | static void begin_testcase( |
| 252 | const char *par_module_name, const char *par_testcase_name, |
| 253 | const char *mtc_comptype_module, const char *mtc_comptype_name, |
| 254 | const char *system_comptype_module, const char *system_comptype_name, |
| 255 | boolean has_timer, double timer_value); |
| 256 | static verdicttype end_testcase(); |
| 257 | static void log_verdict_statistics(); |
| 258 | |
| 259 | static void begin_action(); |
| 260 | static void end_action(); |
| 261 | |
| 262 | static void setverdict(verdicttype new_value, const char* reason = ""); |
| 263 | static void setverdict(const VERDICTTYPE& new_value, |
| 264 | const char* reason = ""); |
| 265 | static void set_error_verdict(); |
| 266 | static verdicttype getverdict(); |
| 267 | private: |
| 268 | static void setverdict_internal(verdicttype new_value, |
| 269 | const char* reason = ""); |
| 270 | |
| 271 | public: |
| 272 | /** @name Manipulating external commands |
| 273 | * @{ |
| 274 | */ |
| 275 | static void set_begin_controlpart_command(const char *new_command); |
| 276 | static void set_end_controlpart_command(const char *new_command); |
| 277 | static void set_begin_testcase_command(const char *new_command); |
| 278 | static void set_end_testcase_command(const char *new_command); |
| 279 | static void clear_external_commands(); |
| 280 | /** @} */ |
| 281 | private: |
| 282 | static char *shell_escape(const char *command_str); |
| 283 | static void execute_command(const char *command_name, |
| 284 | const char *argument_string); |
| 285 | |
| 286 | public: |
| 287 | static void process_create_mtc(); |
| 288 | static void process_create_ptc(component component_reference, |
| 289 | const char *component_type_module, const char *component_type_name, |
| 290 | const char *par_component_name, boolean par_is_alive, |
| 291 | const char *current_testcase_module, const char *current_testcase_name); |
| 292 | |
| 293 | static void process_create_ack(component new_component); |
| 294 | static void process_running(boolean result_value); |
| 295 | static void process_alive(boolean result_value); |
| 296 | static void process_done_ack(boolean done_status, |
| 297 | const char *return_type, int return_value_len, |
| 298 | const void *return_value); |
| 299 | static void process_killed_ack(boolean killed_status); |
| 300 | static void process_ptc_verdict(Text_Buf& text_buf); |
| 301 | static void process_kill(); |
| 302 | static void process_kill_process(component component_reference); |
| 303 | |
| 304 | static void set_component_done(component component_reference, |
| 305 | const char *return_type, int return_value_len, |
| 306 | const void *return_value); |
| 307 | static void set_component_killed(component component_reference); |
| 308 | static void cancel_component_done(component component_reference); |
| 309 | |
| 310 | private: |
| 311 | static int get_component_status_table_index(component component_reference); |
| 312 | static alt_status get_killed_status(component component_reference); |
| 313 | static boolean in_component_status_table(component component_reference); |
| 314 | static void clear_component_status_table(); |
| 315 | |
| 316 | static void initialize_component_process_tables(); |
| 317 | static void add_component(component component_reference, pid_t process_id); |
| 318 | static void remove_component(component_process_struct *comp); |
| 319 | static component_process_struct *get_component_by_compref(component |
| 320 | component_reference); |
| 321 | static component_process_struct *get_component_by_pid(pid_t process_id); |
| 322 | static void clear_component_process_tables(); |
| 323 | |
| 324 | static void successful_process_creation(); |
| 325 | static void failed_process_creation(); |
| 326 | |
| 327 | public: |
| 328 | static void wait_terminated_processes(); |
| 329 | static void check_overload(); |
| 330 | }; |
| 331 | |
| 332 | /** TTCN_TryBlock must be used only as a local variable of a TTCN-3 try{} block. |
| 333 | It handles the value of TTCN_Runtime::in_ttcn_try_block using C++'s RAII feature */ |
| 334 | class TTCN_TryBlock { |
| 335 | boolean outmost_try; |
| 336 | public: |
| 337 | TTCN_TryBlock() { |
| 338 | if (TTCN_Runtime::in_ttcn_try_block) { |
| 339 | outmost_try = FALSE; |
| 340 | } else { |
| 341 | outmost_try = TRUE; |
| 342 | TTCN_Runtime::in_ttcn_try_block = TRUE; |
| 343 | } |
| 344 | } |
| 345 | ~TTCN_TryBlock() { |
| 346 | if (outmost_try) { |
| 347 | TTCN_Runtime::in_ttcn_try_block = FALSE; |
| 348 | } |
| 349 | } |
| 350 | }; |
| 351 | |
| 352 | #endif |