blob: e78b412cbd9b6bc2a03fc887cef3c32482b5b1bb [file] [log] [blame]
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +01001/*
2 * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <stdio.h>
19#include <stdarg.h>
20#include <unistd.h>
21#include <string.h>
22#include <stdlib.h>
23#include <errno.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <sys/time.h>
27
28#define TST_NO_DEFAULT_MAIN
29#include "tst_test.h"
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010030#include "tst_device.h"
31#include "lapi/futex.h"
Petr Vorela7f61332017-01-24 20:47:30 +010032#include "tst_ansi_colors.h"
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010033
34#include "old_resource.h"
35#include "old_device.h"
36#include "old_tmpdir.h"
37
38struct tst_test *tst_test;
39
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010040static int iterations = 1;
41static float duration = -1;
Jan Stanceke0bfa7d2016-06-08 15:27:55 +020042static pid_t main_pid, lib_pid;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010043
44struct results {
Jan Stancekc54ca052016-04-13 12:31:13 +020045 int passed;
46 int skipped;
47 int failed;
48 int warnings;
Cyril Hrubis2ad59b72016-08-03 15:53:55 +020049 unsigned int timeout;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010050};
51
52static struct results *results;
53
54static int ipc_fd;
55
56extern void *tst_futexes;
57extern unsigned int tst_max_futexes;
58
59#define IPC_ENV_VAR "LTP_IPC_PATH"
60
61static char ipc_path[1024];
62const char *tst_ipc_path = ipc_path;
63char *const tst_ipc_envp[] = {ipc_path, NULL};
64
65static char shm_path[1024];
66
Jan Stancek332540e2016-06-08 16:48:22 +020067static void do_cleanup(void);
Cyril Hrubisfa495172016-06-08 16:06:35 +020068static void do_exit(int ret) __attribute__ ((noreturn));
Jan Stanceke0bfa7d2016-06-08 15:27:55 +020069
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010070static void setup_ipc(void)
71{
72 size_t size = getpagesize();
73
Steven Jackson9f41dcf2016-12-21 20:09:01 +000074 if (access("/dev/shm", F_OK) == 0) {
75 snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
76 tst_test->tid, getpid());
77 } else {
78 char *tmpdir;
79
80 if (!tst_tmpdir_created())
81 tst_tmpdir();
82
83 tmpdir = tst_get_tmpdir();
84 snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
85 tmpdir, tst_test->tid, getpid());
86 free(tmpdir);
87 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010088
89 ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
90 if (ipc_fd < 0)
91 tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
92
93 SAFE_FTRUNCATE(ipc_fd, size);
94
95 results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
96
97 /* Checkpoints needs to be accessible from processes started by exec() */
98 if (tst_test->needs_checkpoints)
99 sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
100 else
101 SAFE_UNLINK(shm_path);
102
103 SAFE_CLOSE(ipc_fd);
104
105 if (tst_test->needs_checkpoints) {
106 tst_futexes = (char*)results + sizeof(struct results);
107 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
108 }
109}
110
111static void cleanup_ipc(void)
112{
113 size_t size = getpagesize();
114
115 if (ipc_fd > 0 && close(ipc_fd))
116 tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
117
118 if (!access(shm_path, F_OK) && unlink(shm_path))
119 tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
120
121 msync((void*)results, size, MS_SYNC);
122 munmap((void*)results, size);
123}
124
125void tst_reinit(void)
126{
127 const char *path = getenv("LTP_IPC_PATH");
128 size_t size = getpagesize();
129 int fd;
130 void *ptr;
131
132 if (!path)
133 tst_brk(TBROK, "LTP_IPC_PATH is not defined");
134
135 if (access(path, F_OK))
136 tst_brk(TBROK, "File %s does not exist!", path);
137
138 fd = SAFE_OPEN(path, O_RDWR);
139
140 ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
141 tst_futexes = (char*)ptr + sizeof(struct results);
142 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
143
144 SAFE_CLOSE(fd);
145}
146
147static void update_results(const char *file, unsigned int lineno, int ttype)
148{
149 if (!results) {
150 tst_brk(TBROK,
151 "%s: %d: Results IPC not initialized!", file, lineno);
152 }
153
154 switch (ttype) {
155 case TCONF:
156 tst_atomic_inc(&results->skipped);
157 break;
158 case TPASS:
159 tst_atomic_inc(&results->passed);
160 break;
161 case TWARN:
162 tst_atomic_inc(&results->warnings);
163 break;
164 case TFAIL:
165 tst_atomic_inc(&results->failed);
166 break;
167 }
168}
169
170static void print_result(const char *file, const int lineno, int ttype,
171 const char *fmt, va_list va)
172{
173 char buf[1024];
174 char *str = buf;
175 int ret, size = sizeof(buf);
176 const char *str_errno = NULL;
177 const char *res;
178
179 switch (TTYPE_RESULT(ttype)) {
180 case TPASS:
181 res = "PASS";
182 break;
183 case TFAIL:
184 res = "FAIL";
185 break;
186 case TBROK:
187 res = "BROK";
188 break;
189 case TCONF:
190 res = "CONF";
191 break;
192 case TWARN:
193 res = "WARN";
194 break;
195 case TINFO:
196 res = "INFO";
197 break;
198 default:
199 tst_brk(TBROK, "Invalid ttype value %i", ttype);
200 }
201
202 if (ttype & TERRNO)
203 str_errno = tst_strerrno(errno);
204
205 if (ttype & TTERRNO)
206 str_errno = tst_strerrno(TEST_ERRNO);
207
Petr Vorela7f61332017-01-24 20:47:30 +0100208 ret = snprintf(str, size, "%s:%i: ", file, lineno);
209 str += ret;
210 size -= ret;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100211
Petr Vorela7f61332017-01-24 20:47:30 +0100212 if (tst_color_enabled())
213 ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
214 res, ANSI_COLOR_RESET);
215 else
216 ret = snprintf(str, size, "%s: ", res);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100217 str += ret;
218 size -= ret;
219
220 ret = vsnprintf(str, size, fmt, va);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100221 str += ret;
222 size -= ret;
223
Petr Vorela7f61332017-01-24 20:47:30 +0100224 if (str_errno) {
225 ret = snprintf(str, size, ": %s", str_errno);
226 str += ret;
227 size -= ret;
228 }
229
230 snprintf(str, size, "\n");
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100231
232 fputs(buf, stderr);
233}
234
235void tst_vres_(const char *file, const int lineno, int ttype,
236 const char *fmt, va_list va)
237{
238 print_result(file, lineno, ttype, fmt, va);
239
240 update_results(file, lineno, TTYPE_RESULT(ttype));
241}
242
243void tst_vbrk_(const char *file, const int lineno, int ttype,
244 const char *fmt, va_list va) __attribute__((noreturn));
245
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200246static void do_test_cleanup(void)
247{
248 if (tst_test->cleanup)
249 tst_test->cleanup();
250}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100251
252void tst_vbrk_(const char *file, const int lineno, int ttype,
253 const char *fmt, va_list va)
254{
255 print_result(file, lineno, ttype, fmt, va);
256
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200257 if (getpid() == main_pid)
258 do_test_cleanup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100259
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200260 if (getpid() == lib_pid)
Cyril Hrubisfa495172016-06-08 16:06:35 +0200261 do_exit(TTYPE_RESULT(ttype));
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200262
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100263 exit(TTYPE_RESULT(ttype));
264}
265
266void tst_res_(const char *file, const int lineno, int ttype,
267 const char *fmt, ...)
268{
269 va_list va;
270
271 va_start(va, fmt);
272 tst_vres_(file, lineno, ttype, fmt, va);
273 va_end(va);
274}
275
276void tst_brk_(const char *file, const int lineno, int ttype,
277 const char *fmt, ...)
278{
279 va_list va;
280
281 va_start(va, fmt);
282 tst_vbrk_(file, lineno, ttype, fmt, va);
283 va_end(va);
284}
285
286static void check_child_status(pid_t pid, int status)
287{
288 int ret;
289
290 if (WIFSIGNALED(status)) {
291 tst_brk(TBROK, "Child (%i) killed by signal %s",
292 pid, tst_strsig(WTERMSIG(status)));
293 }
294
295 if (!(WIFEXITED(status)))
296 tst_brk(TBROK, "Child (%i) exitted abnormaly", pid);
297
298 ret = WEXITSTATUS(status);
299 switch (ret) {
300 case TPASS:
301 break;
302 case TBROK:
303 case TCONF:
304 tst_brk(ret, "Reported by child (%i)", pid);
305 default:
306 tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
307 }
308}
309
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300310void tst_reap_children(void)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100311{
312 int status;
313 pid_t pid;
314
315 for (;;) {
316 pid = wait(&status);
317
318 if (pid > 0) {
319 check_child_status(pid, status);
320 continue;
321 }
322
323 if (errno == ECHILD)
324 break;
325
326 if (errno == EINTR)
327 continue;
328
329 tst_brk(TBROK | TERRNO, "wait() failed");
330 }
331}
332
333
334pid_t safe_fork(const char *filename, unsigned int lineno)
335{
336 pid_t pid;
337
338 if (!tst_test->forks_child)
339 tst_brk(TBROK, "test.forks_child must be set!");
340
341 fflush(stdout);
342
343 pid = fork();
344 if (pid < 0)
345 tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
346
347 return pid;
348}
349
350static struct option {
351 char *optstr;
352 char *help;
353} options[] = {
Cyril Hrubisb819c222016-08-03 14:36:07 +0200354 {"h", "-h Prints this help"},
355 {"i:", "-i n Execute test n times"},
356 {"I:", "-I x Execute test for n seconds"},
357 {"C:", "-C ARG Run child process with ARG arguments (used internally)"},
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100358};
359
360static void print_help(void)
361{
362 unsigned int i;
363
364 for (i = 0; i < ARRAY_SIZE(options); i++)
365 fprintf(stderr, "%s\n", options[i].help);
366
367 if (!tst_test->options)
368 return;
369
370 for (i = 0; tst_test->options[i].optstr; i++)
Cyril Hrubisb819c222016-08-03 14:36:07 +0200371 fprintf(stderr, "%s\n", tst_test->options[i].help);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100372}
373
374static void check_option_collision(void)
375{
376 unsigned int i, j;
377 struct tst_option *toptions = tst_test->options;
378
379 if (!toptions)
380 return;
381
382 for (i = 0; toptions[i].optstr; i++) {
383 for (j = 0; j < ARRAY_SIZE(options); j++) {
384 if (toptions[i].optstr[0] == options[j].optstr[0]) {
385 tst_brk(TBROK, "Option collision '%s'",
386 options[j].help);
387 }
388 }
389 }
390}
391
392static unsigned int count_options(void)
393{
394 unsigned int i;
395
396 if (!tst_test->options)
397 return 0;
398
399 for (i = 0; tst_test->options[i].optstr; i++);
400
401 return i;
402}
403
404static void parse_topt(unsigned int topts_len, int opt, char *optarg)
405{
406 unsigned int i;
407 struct tst_option *toptions = tst_test->options;
408
409 for (i = 0; i < topts_len; i++) {
410 if (toptions[i].optstr[0] == opt)
411 break;
412 }
413
414 if (i >= topts_len)
415 tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
416
Jan Stancekc07d36c2016-08-01 11:44:55 +0200417 *(toptions[i].arg) = optarg ? optarg : "";
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100418}
419
420/* see self_exec.c */
421#ifdef UCLINUX
422extern char *child_args;
423#endif
424
425static void parse_opts(int argc, char *argv[])
426{
427 unsigned int i, topts_len = count_options();
428 char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
429 int opt;
430
431 check_option_collision();
432
433 optstr[0] = 0;
434
435 for (i = 0; i < ARRAY_SIZE(options); i++)
436 strcat(optstr, options[i].optstr);
437
438 for (i = 0; i < topts_len; i++)
439 strcat(optstr, tst_test->options[i].optstr);
440
441 while ((opt = getopt(argc, argv, optstr)) > 0) {
442 switch (opt) {
443 case '?':
444 print_help();
445 tst_brk(TBROK, "Invalid option");
446 case 'h':
447 print_help();
448 exit(0);
449 case 'i':
450 iterations = atoi(optarg);
451 break;
452 case 'I':
453 duration = atof(optarg);
454 break;
455 case 'C':
456#ifdef UCLINUX
457 child_args = optarg;
458#endif
459 break;
460 default:
461 parse_topt(topts_len, opt, optarg);
462 }
463 }
464}
465
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200466int tst_parse_int(const char *str, int *val, int min, int max)
467{
468 long rval;
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300469
470 if (!str)
471 return 0;
472
473 int ret = tst_parse_long(str, &rval, min, max);
474
475 if (ret)
476 return ret;
477
478 *val = (int)rval;
479 return 0;
480}
481
482int tst_parse_long(const char *str, long *val, long min, long max)
483{
484 long rval;
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200485 char *end;
486
487 if (!str)
488 return 0;
489
490 errno = 0;
491 rval = strtol(str, &end, 10);
492
493 if (str == end || *end != '\0')
494 return EINVAL;
495
496 if (errno)
497 return errno;
498
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300499 if (rval > max || rval < min)
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200500 return ERANGE;
501
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300502 *val = rval;
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200503 return 0;
504}
505
506int tst_parse_float(const char *str, float *val, float min, float max)
507{
508 double rval;
509 char *end;
510
511 if (!str)
512 return 0;
513
514 errno = 0;
515 rval = strtod(str, &end);
516
517 if (str == end || *end != '\0')
518 return EINVAL;
519
520 if (errno)
521 return errno;
522
523 if (rval > (double)max || rval < (double)min)
524 return ERANGE;
525
526 *val = (float)rval;
527 return 0;
528}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100529
Cyril Hrubisfa495172016-06-08 16:06:35 +0200530static void do_exit(int ret)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100531{
Xiao Yang11dfc322016-06-16 15:52:04 +0800532 if (results) {
533 printf("\nSummary:\n");
534 printf("passed %d\n", results->passed);
535 printf("failed %d\n", results->failed);
536 printf("skipped %d\n", results->skipped);
537 printf("warnings %d\n", results->warnings);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100538
Xiao Yang11dfc322016-06-16 15:52:04 +0800539 if (results->failed)
540 ret |= TFAIL;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100541
Xiao Yang11dfc322016-06-16 15:52:04 +0800542 if (results->skipped)
543 ret |= TCONF;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100544
Xiao Yang11dfc322016-06-16 15:52:04 +0800545 if (results->warnings)
546 ret |= TWARN;
547 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100548
Jan Stancek332540e2016-06-08 16:48:22 +0200549 do_cleanup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100550
551 exit(ret);
552}
553
554void check_kver(void)
555{
556 int v1, v2, v3;
557
Cyril Hrubis4dcfd282016-11-01 15:07:12 +0100558 if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
559 tst_res(TWARN,
560 "Invalid kernel version %s, expected %%d.%%d.%%d",
561 tst_test->min_kver);
562 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100563
564 if (tst_kvercmp(v1, v2, v3) < 0) {
565 tst_brk(TCONF, "The test requires kernel %s or newer",
566 tst_test->min_kver);
567 }
568}
569
570static int results_equal(struct results *a, struct results *b)
571{
572 if (a->passed != b->passed)
573 return 0;
574
575 if (a->failed != b->failed)
576 return 0;
577
578 if (a->skipped != b->skipped)
579 return 0;
580
581 return 1;
582}
583
584static int needs_tmpdir(void)
585{
586 return tst_test->needs_tmpdir ||
587 tst_test->needs_device ||
588 tst_test->resource_files ||
589 tst_test->needs_checkpoints;
590}
591
592static void copy_resources(void)
593{
594 unsigned int i;
595
596 for (i = 0; tst_test->resource_files[i]; i++)
597 TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
598}
599
600static struct tst_device tdev;
601struct tst_device *tst_device;
602
603static void do_setup(int argc, char *argv[])
604{
605 if (!tst_test)
606 tst_brk(TBROK, "No tests to run");
607
Cyril Hrubisf5f208b2016-08-04 16:10:21 +0200608 if (!tst_test->tid)
609 tst_brk(TBROK, "No tid set in test structure");
610
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100611 if (!tst_test->test && !tst_test->test_all)
612 tst_brk(TBROK, "No test function speficied");
613
614 if (tst_test->test && tst_test->test_all)
615 tst_brk(TBROK, "You can define either test() or test_all()");
616
617 if (tst_test->test && !tst_test->tcnt)
618 tst_brk(TBROK, "Number of tests (tcnt) must not be > 0");
619
620 if (tst_test->test_all && tst_test->tcnt)
621 tst_brk(TBROK, "You can't define tcnt for test_all()");
622
623 if (tst_test->needs_root && geteuid() != 0)
624 tst_brk(TCONF, "Test needs to be run as root");
625
626 if (tst_test->min_kver)
627 check_kver();
628
629 parse_opts(argc, argv);
630
631 setup_ipc();
632
Steven Jackson9f41dcf2016-12-21 20:09:01 +0000633 if (needs_tmpdir() && !tst_tmpdir_created())
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100634 tst_tmpdir();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100635
636 if (tst_test->needs_device) {
Li Wangd47bb552016-09-27 14:51:23 +0800637 tdev.dev = tst_acquire_device_(NULL, tst_test->device_min_size);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100638 tdev.fs_type = tst_dev_fs_type();
639
640 if (!tdev.dev)
641 tst_brk(TCONF, "Failed to acquire device");
642
643 tst_device = &tdev;
644 }
645
646 if (tst_test->resource_files)
647 copy_resources();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200648}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100649
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200650static void do_test_setup(void)
651{
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100652 main_pid = getpid();
653
654 if (tst_test->setup)
655 tst_test->setup();
656
657 if (main_pid != getpid())
658 tst_brk(TBROK, "Runaway child in setup()!");
659}
660
661static void do_cleanup(void)
662{
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100663 if (tst_test->needs_device && tdev.dev)
664 tst_release_device(tdev.dev);
665
Steven Jackson9f41dcf2016-12-21 20:09:01 +0000666 if (tst_tmpdir_created()) {
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100667 /* avoid munmap() on wrong pointer in tst_rmdir() */
668 tst_futexes = NULL;
669 tst_rmdir();
670 }
Jan Stancek332540e2016-06-08 16:48:22 +0200671
672 cleanup_ipc();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100673}
674
675static void run_tests(void)
676{
677 unsigned int i;
678 struct results saved_results;
679
680 if (!tst_test->test) {
681 saved_results = *results;
682 tst_test->test_all();
683
684 if (getpid() != main_pid) {
685 exit(0);
686 }
687
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300688 tst_reap_children();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100689
690 if (results_equal(&saved_results, results))
691 tst_brk(TBROK, "Test haven't reported results!");
692 return;
693 }
694
695 for (i = 0; i < tst_test->tcnt; i++) {
696 saved_results = *results;
697 tst_test->test(i);
698
699 if (getpid() != main_pid) {
700 exit(0);
701 }
702
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300703 tst_reap_children();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100704
705 if (results_equal(&saved_results, results))
706 tst_brk(TBROK, "Test %i haven't reported results!", i);
707 }
708}
709
710static unsigned long long get_time_ms(void)
711{
712 struct timeval tv;
713
714 gettimeofday(&tv, NULL);
715
716 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
717}
718
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200719static void testrun(void)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100720{
721 unsigned int i = 0;
722 unsigned long long stop_time = 0;
723 int cont = 1;
724
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200725 do_test_setup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100726
727 if (duration > 0)
728 stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
729
730 for (;;) {
731 cont = 0;
732
733 if (i < (unsigned int)iterations) {
734 i++;
735 cont = 1;
736 }
737
738 if (stop_time && get_time_ms() < stop_time)
739 cont = 1;
740
741 if (!cont)
742 break;
743
744 run_tests();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200745
746 kill(getppid(), SIGUSR1);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100747 }
748
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200749 do_test_cleanup();
750 exit(0);
751}
752
753static pid_t test_pid;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200754
755static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
756{
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200757 kill(-test_pid, SIGKILL);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200758}
759
760static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
761{
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200762 alarm(results->timeout);
763}
764
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200765#define SIGINT_MSG "Sending SIGKILL to test process...\n"
766
767static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
768{
769 if (test_pid > 0) {
770 if (write(2, SIGINT_MSG, sizeof(SIGINT_MSG) - 1)) {
771 /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */
772 }
773 kill(-test_pid, SIGKILL);
774 }
775}
776
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200777void tst_set_timeout(unsigned int timeout)
778{
779 char *mul = getenv("LTP_TIMEOUT_MUL");
780
781 results->timeout = timeout;
782
783 if (mul) {
784 float m = atof(mul);
785
786 if (m < 1)
787 tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul);
788
789 results->timeout = results->timeout * m + 0.5;
790 }
791
792 tst_res(TINFO, "Timeout per run is %uh %02um %02us",
793 results->timeout/3600, (results->timeout%3600)/60,
794 results->timeout % 60);
795
796 if (getpid() == lib_pid)
797 alarm(results->timeout);
798 else
799 kill(getppid(), SIGUSR1);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200800}
801
802void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
803{
804 int status;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200805
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200806 lib_pid = getpid();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200807 tst_test = self;
808 TCID = tst_test->tid;
809
810 do_setup(argc, argv);
811
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200812 SAFE_SIGNAL(SIGALRM, alarm_handler);
813 SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
814
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200815 if (tst_test->timeout)
816 tst_set_timeout(tst_test->timeout);
817 else
818 tst_set_timeout(300);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200819
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200820 SAFE_SIGNAL(SIGINT, sigint_handler);
821
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200822 test_pid = fork();
823 if (test_pid < 0)
824 tst_brk(TBROK | TERRNO, "fork()");
825
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200826 if (!test_pid) {
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200827 SAFE_SIGNAL(SIGALRM, SIG_DFL);
828 SAFE_SIGNAL(SIGUSR1, SIG_DFL);
829 SAFE_SIGNAL(SIGINT, SIG_DFL);
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200830 SAFE_SETPGID(0, 0);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200831 testrun();
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200832 }
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200833
834 SAFE_WAITPID(test_pid, &status, 0);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200835 alarm(0);
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200836 SAFE_SIGNAL(SIGINT, SIG_DFL);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200837
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200838 if (WIFEXITED(status) && WEXITSTATUS(status))
Cyril Hrubisfa495172016-06-08 16:06:35 +0200839 do_exit(WEXITSTATUS(status));
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200840
841 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
842 tst_res(TINFO, "If you are running on slow machine, "
843 "try exporting LTP_TIMEOUT_MUL > 1");
844 tst_brk(TBROK, "Test killed! (timeout?)");
845 }
846
847 if (WIFSIGNALED(status))
848 tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
849
Cyril Hrubisfa495172016-06-08 16:06:35 +0200850 do_exit(0);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100851}