Home | History | Annotate | Download | only in nanosleep
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2001
      3  *  07/2001 Ported by Wayne Boyer
      4  * Copyright (C) Cyril Hrubis <chrubis (at) suse.cz>
      5  *
      6  * This program is free software;  you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     14  * the GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program;  if not, write to the Free Software Foundation,
     18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     19  */
     20 
     21 /*
     22  * Test Description:
     23  *  Verify that nanosleep() will be successful to suspend the execution
     24  *  of a process, returns after the receipt of a signal and writes the
     25  *  remaining sleep time into the structure.
     26  */
     27 
     28 #include <errno.h>
     29 #include <unistd.h>
     30 #include <fcntl.h>
     31 #include <signal.h>
     32 #include <time.h>
     33 #include <sys/wait.h>
     34 #include <sys/time.h>
     35 #include <stdint.h>
     36 #include <inttypes.h>
     37 
     38 #include "test.h"
     39 
     40 char *TCID = "nanosleep02";
     41 int TST_TOTAL = 1;
     42 
     43 static void do_child(void);
     44 static void setup(void);
     45 static void sig_handler();
     46 
     47 /*
     48  * Define here the "rem" precision in microseconds,
     49  * Various implementations will provide different
     50  * precisions. The -aa tree provides up to usec precision.
     51  * NOTE: all the trees that don't provide a precision of
     52  * the order of the microseconds are subject to an userspace
     53  * live lock condition with glibc under a flood of signals,
     54  * the "rem" field would never change without the increased
     55  * usec precision in the -aa tree.
     56  */
     57 #define USEC_PRECISION 250000	/* Error margin allowed in usec */
     58 
     59 int main(int ac, char **av)
     60 {
     61 	int lc;
     62 	pid_t cpid;
     63 
     64 	tst_parse_opts(ac, av, NULL, NULL);
     65 
     66 #ifdef UCLINUX
     67 	maybe_run_child(&do_child, "");
     68 #endif
     69 
     70 	setup();
     71 
     72 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     73 
     74 		tst_count = 0;
     75 
     76 		if ((cpid = FORK_OR_VFORK()) == -1) {
     77 			tst_brkm(TBROK, NULL,
     78 				 "fork() failed to create child process");
     79 		}
     80 
     81 		if (cpid == 0) {
     82 #ifdef UCLINUX
     83 			if (self_exec(av[0], "")) {
     84 				tst_brkm(TBROK, NULL, "self_exec failed");
     85 			}
     86 #else
     87 			do_child();
     88 #endif
     89 		}
     90 
     91 		/* wait for child to time slot for execution */
     92 		sleep(1);
     93 
     94 		/* Now send signal to child */
     95 		if (kill(cpid, SIGINT) < 0) {
     96 			tst_brkm(TBROK, NULL,
     97 				 "kill() fails send signal to child");
     98 		}
     99 
    100 		tst_record_childstatus(NULL, cpid);
    101 	}
    102 
    103 	tst_exit();
    104 }
    105 
    106 static void do_child(void)
    107 {
    108 	struct timespec timereq = {.tv_sec = 5, .tv_nsec = 9999};
    109 	struct timespec timerem, exp_rem;
    110 
    111 	tst_timer_start(CLOCK_MONOTONIC);
    112 	TEST(nanosleep(&timereq, &timerem));
    113 	tst_timer_stop();
    114 
    115 	if (tst_timespec_lt(timereq, tst_timer_elapsed())) {
    116 		tst_resm(TFAIL, "nanosleep() slept more than timereq");
    117 		return;
    118 	}
    119 
    120 	exp_rem = tst_timespec_diff(timereq, tst_timer_elapsed());
    121 
    122 	if (tst_timespec_abs_diff_us(timerem, exp_rem) > USEC_PRECISION) {
    123 		tst_resm(TFAIL,
    124 		         "nanosleep() remaining time %llius, expected %llius, diff %llius",
    125 			 tst_timespec_to_us(timerem), tst_timespec_to_us(exp_rem),
    126 			 tst_timespec_abs_diff_us(timerem, exp_rem));
    127 	} else {
    128 		tst_resm(TPASS,
    129 		         "nanosleep() slept for %llius, remaining time difference %llius",
    130 			 tst_timer_elapsed_us(),
    131 		         tst_timespec_abs_diff_us(timerem, exp_rem));
    132 	}
    133 
    134 	tst_exit();
    135 }
    136 
    137 static void setup(void)
    138 {
    139 	tst_sig(FORK, DEF_HANDLER, NULL);
    140 
    141 	tst_timer_check(CLOCK_MONOTONIC);
    142 
    143 	TEST_PAUSE;
    144 
    145 	if (signal(SIGINT, sig_handler) == SIG_ERR) {
    146 		tst_brkm(TBROK, NULL,
    147 			 "signal() fails to setup signal handler");
    148 	}
    149 }
    150 
    151 static void sig_handler(void)
    152 {
    153 }
    154