1/*
2 * Copyright (c) International Business Machines  Corp., 2001
3 *  07/2001 Ported by Wayne Boyer
4 *
5 * This program is free software;  you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program;  if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * Test Description:
22 *  Verify that nanosleep() will fail to suspend the execution
23 *  of a process for a specified time if interrupted by a non-blocked signal.
24 *
25 * Expected Result:
26 *  nanosleep() should return with -1 value and sets errno to EINTR.
27 */
28
29#include <errno.h>
30#include <unistd.h>
31#include <fcntl.h>
32#include <time.h>
33#include <sys/wait.h>
34
35#include "test.h"
36#include "safe_macros.h"
37
38char *TCID = "nanosleep03";
39int TST_TOTAL = 1;
40
41static void do_child(void);
42static void setup(void);
43static void sig_handler();
44
45int main(int ac, char **av)
46{
47	int lc;
48	pid_t cpid;
49	int status;
50
51	tst_parse_opts(ac, av, NULL, NULL);
52
53#ifdef UCLINUX
54	maybe_run_child(&do_child, "dddd", &timereq.tv_sec, &timereq.tv_nsec,
55			&timerem.tv_sec, &timerem.tv_nsec);
56#endif
57
58	setup();
59
60	for (lc = 0; TEST_LOOPING(lc); lc++) {
61		tst_count = 0;
62
63		/*
64		 * Creat a child process and suspend its
65		 * execution using nanosleep()
66		 */
67		if ((cpid = FORK_OR_VFORK()) == -1)
68			tst_brkm(TBROK, NULL, "fork() failed");
69
70		if (cpid == 0) {
71#ifdef UCLINUX
72			if (self_exec(av[0], "dddd",
73				      timereq.tv_sec, timereq.tv_nsec,
74				      timerem.tv_sec, timerem.tv_nsec) < 0) {
75				tst_brkm(TBROK, NULL, "self_exec failed");
76			}
77#else
78			do_child();
79#endif
80		}
81
82		sleep(1);
83
84		/* Now send signal to child */
85		SAFE_KILL(NULL, cpid, SIGINT);
86
87		/* Wait for child to execute */
88		wait(&status);
89		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
90			tst_resm(TPASS, "nanosleep() failed, interrupted"
91				 " by signal (%d) as expected", EINTR);
92		} else {
93			tst_resm(TFAIL, "child process exited abnormally; "
94				 "status = %d", status);
95		}
96	}
97
98	tst_exit();
99}
100
101static void do_child(void)
102{
103	struct timespec timereq = {.tv_sec = 5, .tv_nsec = 9999};
104	struct timespec timerem;
105
106	/*
107	 * Call nanosleep() to suspend child process
108	 * for specified time 'tv_sec'.
109	 * Call should return before suspending execution
110	 * for the specified time due to receipt of signal
111	 * from Parent.
112	 */
113	TEST(nanosleep(&timereq, &timerem));
114
115	if (TEST_RETURN == -1) {
116
117		/* Check for expected errno is set */
118		if (TEST_ERRNO != EINTR) {
119			tst_resm(TFAIL | TTERRNO,
120				 "nanosleep() failed; expected errno: %d",
121				 EINTR);
122			exit(1);
123		}
124	} else {
125		tst_resm(TFAIL, "nanosleep() returns %ld, "
126			 "expected -1, errno:%d", TEST_RETURN, EINTR);
127		exit(1);
128	}
129
130	exit(0);
131}
132
133static void setup(void)
134{
135	tst_sig(FORK, DEF_HANDLER, NULL);
136
137	TEST_PAUSE;
138
139	if (signal(SIGINT, sig_handler) == SIG_ERR) {
140		tst_brkm(TBROK, NULL,
141			 "signal() fails to setup signal handler");
142	}
143
144}
145
146static void sig_handler(void)
147{
148}
149