1 : /*
2 : * This file is part of MIN Test Framework. Copyright © 2008 Nokia Corporation
3 : * and/or its subsidiary(-ies).
4 : * Contact: Konrad Marek Zapalowicz
5 : * Contact e-mail: DG.MIN-Support@nokia.com
6 : *
7 : * This program is free software: you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the Free
9 : * Software Foundation, version 2 of the License.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details. You should have received a copy of the GNU General Public
15 : * License along with this program. If not, see
16 : * <http://www.gnu.org/licenses/>.
17 : */
18 :
19 :
20 : /**
21 : * @file tmc_msghnd.c
22 : * @version 0.1
23 : * @brief This file contains implementation of the TMC message handling.
24 : */
25 :
26 : /* ------------------------------------------------------------------------- */
27 : /* INCLUDE FILES */
28 : #include <tmc.h>
29 : #include <tmc_msghnd.h>
30 : #include <min_common.h>
31 :
32 : /* ------------------------------------------------------------------------- */
33 : /* EXTERNAL DATA STRUCTURES */
34 : /* None */
35 :
36 : /* ------------------------------------------------------------------------- */
37 : /* EXTERNAL GLOBAL VARIABLES */
38 : /** pointer to global TMC structure. Needed in signal handlers */
39 : extern TMC_t *ptmc;
40 : extern TestCaseResult globaltcr;
41 : /* ------------------------------------------------------------------------- */
42 : /* EXTERNAL FUNCTION PROTOTYPES */
43 : /* None */
44 :
45 : /* ------------------------------------------------------------------------- */
46 : /* GLOBAL VARIABLES */
47 : TSBool tp_exit_flag = ESFalse;
48 : /* ------------------------------------------------------------------------- */
49 : /* CONSTANTS */
50 : /* None */
51 :
52 : /* ------------------------------------------------------------------------- */
53 : /* MACROS */
54 : /* None */
55 :
56 : /* ------------------------------------------------------------------------- */
57 : /* LOCAL GLOBAL VARIABLES */
58 : /* None */
59 :
60 : /* ------------------------------------------------------------------------- */
61 : /* LOCAL CONSTANTS AND MACROS */
62 : /* None */
63 :
64 : /* ------------------------------------------------------------------------- */
65 : /* MODULE DATA STRUCTURES */
66 : /* None */
67 :
68 : /* ------------------------------------------------------------------------- */
69 : /* LOCAL FUNCTION PROTOTYPES */
70 : /* ------------------------------------------------------------------------- */
71 : /** MSG_GTC handler
72 : * @param tmc adress of the TMC entity.
73 : *
74 : * Sends MSG_TCD messages to the engine.
75 : */
76 : void gu_handle_gtc (TMC_t * tmc, TSBool send);
77 : /* ------------------------------------------------------------------------- */
78 : /** MSG_EXE handler
79 : * @param tmc adress of the TMC entity.
80 : * @param id test case id
81 : * @param cfg_file name of the configuration file.
82 : *
83 : * Executes a test case of a given id.
84 : */
85 : LOCAL void gu_handle_exe (TMC_t * tmc, int id, const char *cfg_file);
86 : /* ------------------------------------------------------------------------- */
87 : /** MSG_END handler
88 : * @param tmc adress of the TMC entity.
89 : *
90 : * Exits from the main event loop.
91 : */
92 : LOCAL void gu_handle_end (TMC_t * tmc);
93 : /* ------------------------------------------------------------------------- */
94 : /** MSG_PAUSE handler
95 : * @param tmc adress of the TMC entity.
96 : *
97 : * Pauses Test Process - if any.
98 : */
99 : LOCAL void gu_handle_pause (TMC_t * tmc);
100 : /* ------------------------------------------------------------------------- */
101 : /** MSG_RESUME handler
102 : * @param tmc adress of the TMC entity.
103 : *
104 : * Resumes Test Process - if paused.
105 : */
106 : LOCAL void gu_handle_resume (TMC_t * tmc);
107 : /* ------------------------------------------------------------------------- */
108 : /** MSG_STOP handler
109 : * @param tmc adress of the TMC entity.
110 : *
111 : * Abort Test Process - if any.
112 : */
113 : LOCAL void gu_handle_stop (TMC_t * tmc);
114 : /* ------------------------------------------------------------------------- */
115 : /** MSG_USR handler
116 : * @param tmc adress of the TMC entity.
117 : * @param msg recieved message from test process which is forwarded to engine.
118 : *
119 : * Forwards message to the engine.
120 : */
121 : void gu_handle_usr (TMC_t * tmc, const MsgBuffer * msg);
122 : /* ------------------------------------------------------------------------- */
123 : /** MSG_EVENT handler
124 : * @param tmc adress of the TMC entity.
125 : *
126 : * Forwards message to the engine.
127 : */
128 : LOCAL void gu_handle_event (TMC_t * tmc, const MsgBuffer * msg);
129 : /* ------------------------------------------------------------------------- */
130 : /** SIGCHLD handler
131 : * @param sig number of the signal
132 : *
133 : * Handles Test Process termination event. Called async. by the system.
134 : */
135 : void gu_handle_sigchld (int sig);
136 : /* ------------------------------------------------------------------------- */
137 : /** SIGSEGV handler
138 : * @param sig number of the signal
139 : *
140 : * Handles Test Process crashing event. Called async. by the system.
141 : */
142 : void gu_handle_sigsegv (int sig);
143 : /* ------------------------------------------------------------------------- */
144 : /** SIGUSR2 handler
145 : * @param sig number of the signal
146 : *
147 : * Handles SIGUSR2 sent by the TMC. The SIGUSR2 is used instead of SIGKILL
148 : * for killing the Test Process, because SIGKILL is not always received
149 : * by the TP (FFS).
150 : */
151 : void gu_handle_sigusr2 (int sig);
152 : /* ------------------------------------------------------------------------- */
153 : /** Creates a test process
154 : * @param tmc adress of the test module controller
155 : * @param id id of the test case to be executed
156 : * @param cfg_file config file
157 : */
158 : LOCAL void gu_create_tp (TMC_t * tmc, int id, const char *cfg_file);
159 : /* ------------------------------------------------------------------------- */
160 : /** MSG_EXT handler
161 : * @param tmc adress of the test module controller
162 : * @param msg [in] message that came through IPC
163 : */
164 : LOCAL void gu_handle_extif (TMC_t * tmc, const MsgBuffer * msg);
165 : /* ------------------------------------------------------------------------- */
166 : /** MSG_SNDRCV handler
167 : * @param tmc adress of the test module controller
168 : * @param msg [in] message that came through IPC
169 : */
170 : LOCAL void gu_handle_sndrcv (TMC_t * tmc, const MsgBuffer * msg);
171 : /* ------------------------------------------------------------------------- */
172 : /** Dummy sigchld handler*/
173 : void dummy_handler (int sig);
174 : /* ------------------------------------------------------------------------- */
175 : /* FORWARD DECLARATIONS */
176 : /* None */
177 :
178 : /* ------------------------------------------------------------------------- */
179 : /* ==================== LOCAL FUNCTIONS ==================================== */
180 : /* ------------------------------------------------------------------------- */
181 : LOCAL void gu_handle_exe (TMC_t * tmc, int id, const char *cfg_file)
182 98 : {
183 98 : long tmp = -1;
184 : MsgBuffer msg;
185 :
186 98 : /*if( id == 2 ) */ tp_set_timeout (&tmc->tpc_, 0);
187 98 : tp_set_timeout_handler ();
188 98 : tmp = fork ();
189 182 : if (tmp == 0) {
190 94 : min_log_open ("TestProcess", 3);
191 94 : sl_set_sighandler (SIGCHLD, dummy_handler);
192 94 : usleep (50000);
193 94 : gu_create_tp (tmc, id, cfg_file);
194 88 : } else if (tmp > 0) {
195 88 : MIN_INFO ("Test Process created [%d]", tmp);
196 88 : tp_set_pid (&tmc->tpc_, tmp);
197 88 : msg.sender_ = getpid();
198 88 : msg.receiver_ = getppid();
199 88 : msg.type_ = MSG_RUN_ID;
200 88 : msg.param_ = tmp;
201 88 : msg.desc_[0] = '\0';
202 88 : mq_send_message (tmc->tmcipi_.mqid_, &msg);
203 88 : tp_set_status (&tmc->tpc_, TP_RUNNING);
204 88 : tp_start_timeout (&tmc->tpc_);
205 : } else {
206 0 : MIN_ERROR ("Test Process not created");
207 : }
208 88 : }
209 :
210 :
211 : /* ------------------------------------------------------------------------- */
212 : LOCAL void gu_handle_end (TMC_t * tmc)
213 90 : {
214 90 : if (tp_status (&tmc->tpc_) == TP_ENDED) {
215 0 : tp_set_status (&tmc->tpc_, TP_NONE);
216 90 : } else if (tp_status (&tmc->tpc_) != TP_NONE) {
217 8 : tp_abort (&tmc->tpc_);
218 8 : tp_set_status (&tmc->tpc_, TP_NONE);
219 : }
220 180 : while (!(tp_status (&tmc->tpc_) == TP_NONE)) {
221 0 : usleep (50000);
222 : }
223 90 : tmc->run_ = 0;
224 90 : }
225 :
226 : /* ------------------------------------------------------------------------- */
227 : LOCAL void gu_handle_pause (TMC_t * tmc)
228 3 : {
229 3 : tp_pause (&tmc->tpc_);
230 3 : }
231 :
232 : /* ------------------------------------------------------------------------- */
233 : LOCAL void gu_handle_resume (TMC_t * tmc)
234 1 : {
235 1 : tp_resume (&tmc->tpc_);
236 1 : }
237 :
238 : /* ------------------------------------------------------------------------- */
239 : LOCAL void gu_handle_stop (TMC_t * tmc)
240 2 : {
241 2 : tp_abort (&tmc->tpc_);
242 2 : }
243 :
244 : /* ------------------------------------------------------------------------- */
245 : LOCAL void gu_handle_event (TMC_t * tmc, const MsgBuffer * msg)
246 7 : {
247 7 : int retval = -1;
248 7 : MsgBuffer *tmp = (MsgBuffer *) msg;
249 7 : tmp->receiver_ = getppid ();
250 7 : tmp->sender_ = getpid ();
251 7 : retval = mq_send_message (tmc->tmcipi_.mqid_, tmp);
252 7 : if (retval == -1)
253 0 : MIN_WARN ("EVENT: Cannot send message");
254 7 : }
255 :
256 : /* ------------------------------------------------------------------------- */
257 : LOCAL void gu_handle_extif (TMC_t * tmc, const MsgBuffer * msg)
258 19 : {
259 : MsgBuffer send_msg;
260 :
261 19 : if (msg == INITPTR) {
262 0 : return;
263 : }
264 19 : memcpy (&send_msg,msg, sizeof (MsgBuffer));
265 :
266 19 : send_msg.sender_ = getpid ();
267 :
268 : /* Action depends on type of external controller command */
269 19 : switch (msg->extif_msg_type_) {
270 : case EAllocateSlave:
271 : case EFreeSlave:
272 : case ERemoteSlave:
273 9 : MIN_DEBUG ("EXTIF command: Scripter --> Engine: [%d]",
274 : msg->extif_msg_type_);
275 9 : send_msg.receiver_ = getppid ();
276 9 : mq_send_message (tmc->tmcipi_.mqid_, &send_msg);
277 9 : break;
278 : case EResponseSlave:
279 : case ERemoteSlaveResponse:
280 10 : MIN_DEBUG ("EXTIF command: Engine --> Scripter: [%d]",
281 : msg->extif_msg_type_);
282 10 : send_msg.receiver_ = tmc->tpc_.tp_pid_;
283 10 : mq_send_message (tmc->tmcipi_.mqid_, &send_msg);
284 10 : break;
285 : default:
286 0 : MIN_WARN ("Unknown type of EXTIF command: [%d]",
287 : msg->extif_msg_type_);
288 : }
289 : }
290 :
291 : /* ------------------------------------------------------------------------- */
292 : LOCAL void gu_handle_sndrcv (TMC_t * tmc, const MsgBuffer * msg)
293 1 : {
294 1 : int retval = -1;
295 1 : MsgBuffer *tmp = (MsgBuffer *) msg;
296 1 : if (msg->sender_ == tmc->tpc_.tp_pid_)
297 0 : tmp->receiver_ = getppid ();
298 : else
299 1 : tmp->receiver_ = tmc->tpc_.tp_pid_;
300 1 : tmp->sender_ = getpid ();
301 1 : retval = mq_send_message (tmc->tmcipi_.mqid_, tmp);
302 1 : if (retval == -1)
303 0 : MIN_WARN ("SNDRCV: Cannot send message");
304 1 : }
305 :
306 : /* ------------------------------------------------------------------------- */
307 : void gu_handle_sigchld (int sig)
308 88 : {
309 : int status;
310 88 : int reason = TP_NONE;
311 : int pid;
312 264 : while ((pid = waitpid (-1, &status, 0)) > 0) {
313 88 : tp_set_pid (&ptmc->tpc_, 0);
314 88 : reason = tp_status (&ptmc->tpc_);
315 88 : tp_set_status (&ptmc->tpc_, TP_NONE);
316 : }
317 88 : if (reason == TP_TIMEOUT) {
318 0 : globaltcr.result_ = TP_TIMEOUTED;
319 0 : strcpy (globaltcr.desc_, "Timeouted");
320 88 : } else if (reason == TP_ABORTED) {
321 2 : globaltcr.result_ = TP_NC;
322 2 : strcpy (globaltcr.desc_, "Aborted");
323 : }
324 88 : ptmc->send_ret_ = ESTrue;
325 :
326 : return;
327 : }
328 :
329 : /* ------------------------------------------------------------------------- */
330 : void dummy_handler (int sig)
331 0 : {
332 : ;
333 0 : }
334 :
335 : /* ------------------------------------------------------------------------- */
336 : void gu_handle_sigsegv (int sig)
337 0 : {
338 0 : ip_send_ret (&ptmc->tmcipi_, TP_CRASHED, "Crashed");
339 0 : sleep (1);
340 0 : exit (TP_EXIT_FAILURE);
341 : return;
342 : }
343 :
344 : /* ------------------------------------------------------------------------- */
345 : void gu_handle_sigusr2 (int sig)
346 79 : {
347 79 : tp_exit_flag = ESTrue;
348 : return;
349 : }
350 :
351 : /* ------------------------------------------------------------------------- */
352 : LOCAL void gu_create_tp (TMC_t * tmc, int id, const char *cfg_file)
353 94 : {
354 : TestCaseResult tcr;
355 94 : ip_init (&tmc->tmcipi_, getppid ());
356 :
357 94 : sl_set_sighandler (SIGSEGV, gu_handle_sigsegv);
358 94 : sl_set_sighandler (SIGUSR2, gu_handle_sigusr2);
359 94 : tmc->lib_loader_.run_case_fun_ (id, cfg_file, &tcr);
360 :
361 79 : ip_send_ret (&tmc->tmcipi_, tcr.result_, tcr.desc_);
362 79 : mq_resend_buffered ();
363 344 : while (tp_exit_flag == ESFalse) {
364 186 : usleep (50000);
365 : }
366 79 : mq_flush_msg_buffer ();
367 79 : exit (TP_EXIT_SUCCESS);
368 : }
369 :
370 : /* ------------------------------------------------------------------------- */
371 : /* ======================== FUNCTIONS ====================================== */
372 : /* ------------------------------------------------------------------------- */
373 :
374 : /** Message queue listener.
375 : * @param tmc adress of the TMC entity.
376 : * @param input_buffer output parameter for the recieved message.
377 : */
378 : void gu_read_message (TMC_t * tmc, MsgBuffer * input_buffer)
379 470 : {
380 470 : int retval = 0;
381 470 : TSBool reported = ESFalse;
382 :
383 : while (1) {
384 470 : retval = mq_read_message (tmc->tmcipi_.mqid_, getpid ()
385 : , input_buffer);
386 470 : if (retval == -1) {
387 0 : switch (errno) {
388 : case EINTR:
389 0 : MIN_DEBUG
390 : ("Reading MQ interrupted by signal");
391 0 : break;
392 :
393 : case EIDRM:
394 0 : if (reported == ESFalse) {
395 0 : reported = ESTrue;
396 0 : MIN_ERROR ("MQ id removed");
397 : }
398 0 : break;
399 :
400 : case E2BIG:
401 0 : if (reported == ESFalse) {
402 0 : reported = ESTrue;
403 0 : MIN_DEBUG ("Recieved message "
404 : "too big");
405 : }
406 0 : break;
407 :
408 : case EINVAL:
409 0 : if (reported == ESFalse) {
410 0 : reported = ESTrue;
411 0 : MIN_WARN ("Invalid value: "
412 : "mq_read_message");
413 : }
414 : break;
415 : }
416 470 : } else if (retval < 8) {
417 : /*ignore too short messages */
418 0 : MIN_DEBUG ("Recieved message is too small");
419 : } else {
420 470 : break;
421 : }
422 0 : }
423 : return;
424 : }
425 :
426 : /* ------------------------------------------------------------------------- */
427 : /** Main message handler
428 : * @param tmc adress of the TMC entity.
429 : * @param msg recieved message.
430 : *
431 : * It calls appropiate handler for each type of message.
432 : */
433 : void gu_handle_message (TMC_t * tmc, const MsgBuffer * msg)
434 470 : {
435 : int retval;
436 470 : switch (msg->type_) {
437 : case MSG_GTC:
438 100 : gu_handle_gtc (tmc, msg->special_);
439 100 : break;
440 :
441 : case MSG_EXE:
442 : /*
443 : ** Initialize to not complete
444 : */
445 98 : globaltcr.result_ = TP_NC;
446 98 : strcpy (globaltcr.desc_, "Test Case Not completed");
447 98 : gu_handle_exe (tmc, msg->param_, msg->message_);
448 88 : break;
449 :
450 : case MSG_RET:
451 78 : globaltcr.result_ = msg->param_;
452 78 : STRCPY (globaltcr.desc_, msg->message_,
453 : MaxTestResultDescription + 1);
454 78 : if (tp_pid (&tmc->tpc_)) {
455 78 : retval = kill (tp_pid (&tmc->tpc_), SIGUSR2);
456 78 : if (retval == -1)
457 0 : MIN_ERROR ("RET: Cannot kill child process");
458 : else
459 78 : MIN_DEBUG ("RET: Killed child process");
460 : } else
461 0 : MIN_DEBUG ("RET: already killed child process");
462 78 : break;
463 :
464 : case MSG_END:
465 90 : gu_handle_end (tmc);
466 90 : break;
467 :
468 : case MSG_PAUSE:
469 3 : gu_handle_pause (tmc);
470 3 : break;
471 :
472 : case MSG_RESUME:
473 1 : gu_handle_resume (tmc);
474 1 : break;
475 :
476 : case MSG_STOP:
477 2 : gu_handle_stop (tmc);
478 2 : break;
479 :
480 : case MSG_USR:
481 71 : gu_handle_usr (tmc, msg);
482 71 : break;
483 :
484 : case MSG_EVENT:
485 7 : gu_handle_event (tmc, msg);
486 7 : break;
487 :
488 : case MSG_EXTIF:
489 19 : gu_handle_extif (tmc, msg);
490 19 : break;
491 :
492 : case MSG_SNDRCV:
493 1 : gu_handle_sndrcv (tmc, msg);
494 1 : break;
495 :
496 : default:
497 0 : MIN_WARN ("Unhandled message from %d: to %d, type: %d",
498 : msg->sender_, msg->receiver_, msg->type_);
499 : }
500 460 : }
501 :
502 : /* ------------------------------------------------------------------------- */
503 : void gu_handle_gtc (TMC_t * tmc, TSBool send)
504 100 : {
505 100 : DLList *list = INITPTR;
506 100 : DLListIterator cfgit = DLListNULLIterator;
507 100 : DLListIterator it = DLListNULLIterator;
508 100 : char *cfgfile = "";
509 :
510 100 : cfgit = dl_list_head (tmc->config_list_);
511 300 : while (cfgit != DLListNULLIterator) {
512 100 : cfgfile = (char *)dl_list_data (cfgit);
513 100 : list = dl_list_create ();
514 100 : if (list != INITPTR) {
515 100 : tmc->lib_loader_.get_cases_fun_ (cfgfile, &list);
516 100 : it = dl_list_head (list);
517 100 : if (send == ESTrue) {
518 95 : ip_send_tcd (&tmc->tmcipi_, cfgfile, it);
519 : }
520 100 : dl_list_foreach (dl_list_head (list),
521 : dl_list_tail (list), free);
522 100 : dl_list_free (&list);
523 : }
524 100 : cfgit = dl_list_next (cfgit);
525 : }
526 :
527 100 : ip_send_eotcd (&tmc->tmcipi_);
528 100 : }
529 :
530 : /* ------------------------------------------------------------------------- */
531 : void gu_handle_usr (TMC_t * tmc, const MsgBuffer * msg)
532 71 : {
533 71 : int retval = -1;
534 71 : MsgBuffer *tmp = (MsgBuffer *) msg;
535 71 : tmp->receiver_ = getppid ();
536 71 : tmp->sender_ = getpid ();
537 71 : retval = mq_send_message (tmc->tmcipi_.mqid_, tmp);
538 71 : if (retval == -1)
539 0 : MIN_WARN ("USR: Cannot send message");
540 71 : }
541 :
542 : /* ------------------------------------------------------------------------- */
543 : /* ================= OTHER EXPORTED FUNCTIONS ============================== */
544 : /* None */
545 :
546 : /* ------------------------------------------------------------------------- */
547 : /* ================= TESTS FOR LOCAL FUNCTIONS ============================= */
548 : /* None */
549 :
550 : /* ------------------------------------------------------------------------- */
551 : /* End of file */
|