1 /* $OpenBSD: nanosleep.c,v 1.5 2003/08/02 01:24:36 david Exp $ */ 2 /* 3 * Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain. 4 */ 5 #include <sys/types.h> 6 #include <sys/time.h> 7 #include <sys/wait.h> 8 9 #include <stdlib.h> 10 #include <stdio.h> 11 #include <unistd.h> 12 #include <time.h> 13 #include <err.h> 14 #include <signal.h> 15 16 int trivial(void); 17 int with_signal(void); 18 int time_elapsed(void); 19 int time_elapsed_with_signal(void); 20 21 int short_time(void); 22 23 void sighandler(int); 24 25 int 26 main(int argc, char **argv) 27 { 28 int ch, ret; 29 30 ret = 0; 31 32 while ((ch = getopt(argc, argv, "tseES")) != -1) { 33 switch (ch) { 34 case 't': 35 ret |= trivial(); 36 break; 37 case 's': 38 ret |= with_signal(); 39 break; 40 case 'e': 41 ret |= time_elapsed(); 42 break; 43 case 'E': 44 ret |= time_elapsed_with_signal(); 45 break; 46 case 'S': 47 ret |= short_time(); 48 default: 49 fprintf(stderr, "Usage: nanosleep [-tse]\n"); 50 exit(1); 51 } 52 } 53 54 return (ret); 55 } 56 57 void 58 sighandler(int signum) 59 { 60 } 61 62 int 63 trivial(void) 64 { 65 struct timespec ts, rts; 66 67 ts.tv_sec = 0; 68 ts.tv_nsec = 30000000; 69 rts.tv_sec = 4711; /* Just add to the confusion */ 70 rts.tv_nsec = 4711; 71 if (nanosleep(&ts, &rts) < 0) { 72 warn("trivial: nanosleep"); 73 return 1; 74 } 75 76 /* 77 * Just check that we don't get any leftover time if we sleep the 78 * amount of time we want to sleep. 79 * If we receive any signal, something is wrong anyway. 80 */ 81 if (rts.tv_sec != 0 || rts.tv_nsec != 0) { 82 warnx("trivial: non-zero time? %d/%d", rts.tv_sec, 83 rts.tv_nsec); 84 return 1; 85 } 86 87 return 0; 88 } 89 90 int 91 with_signal(void) 92 { 93 struct timespec ts, rts; 94 pid_t pid; 95 int status; 96 97 signal(SIGUSR1, sighandler); 98 99 pid = getpid(); 100 101 switch(fork()) { 102 case -1: 103 err(1, "fork"); 104 default: 105 ts.tv_sec = 1; 106 ts.tv_nsec = 0; 107 nanosleep(&ts, NULL); 108 kill(pid, SIGUSR1); 109 exit(0); 110 } 111 112 ts.tv_sec = 10; 113 ts.tv_nsec = 0; 114 rts.tv_sec = 0; 115 rts.tv_nsec = 0; 116 if (nanosleep(&ts, &rts) == 0) { 117 warnx("with-signal: nanosleep"); 118 return 1; 119 } 120 if (rts.tv_sec == 0 && rts.tv_nsec == 0) { 121 warnx("with-signal: zero time"); 122 return 1; 123 } 124 125 if (wait(&status) < 0) 126 err(1, "wait"); 127 128 return 0; 129 } 130 131 int 132 time_elapsed(void) 133 { 134 struct timespec ts; 135 struct timeval stv, etv; 136 137 ts.tv_sec = 0; 138 ts.tv_nsec = 500000000; 139 140 if (gettimeofday(&stv, NULL) < 0) { 141 warn("gettimeofday"); 142 return 1; 143 } 144 145 if (nanosleep(&ts, NULL) < 0) { 146 warn("nanosleep"); 147 return 1; 148 } 149 150 if (gettimeofday(&etv, NULL) < 0) { 151 warn("gettimeofday"); 152 return 1; 153 } 154 155 timersub(&etv, &stv, &stv); 156 157 if (stv.tv_sec == 0 && stv.tv_usec < 500000) { 158 warnx("slept less than 0.5 sec"); 159 return 1; 160 } 161 162 return 0; 163 } 164 165 int 166 time_elapsed_with_signal(void) 167 { 168 struct timespec ts, rts; 169 struct timeval stv, etv; 170 pid_t pid; 171 int status; 172 173 signal(SIGUSR1, sighandler); 174 175 pid = getpid(); 176 177 switch(fork()) { 178 case -1: 179 err(1, "fork"); 180 default: 181 ts.tv_sec = 1; 182 ts.tv_nsec = 0; 183 nanosleep(&ts, NULL); 184 kill(pid, SIGUSR1); 185 exit(0); 186 } 187 188 ts.tv_sec = 10; 189 ts.tv_nsec = 0; 190 rts.tv_sec = 0; 191 rts.tv_nsec = 0; 192 193 if (gettimeofday(&stv, NULL) < 0) { 194 warn("gettimeofday"); 195 return 1; 196 } 197 198 if (nanosleep(&ts, &rts) == 0) { 199 warnx("nanosleep"); 200 return 1; 201 } 202 203 if (gettimeofday(&etv, NULL) < 0) { 204 warn("gettimeofday"); 205 return 1; 206 } 207 208 timersub(&etv, &stv, &stv); 209 210 etv.tv_sec = rts.tv_sec; 211 etv.tv_usec = rts.tv_nsec / 1000 + 1; /* the '+ 1' is a "roundup" */ 212 213 timeradd(&etv, &stv, &stv); 214 215 if (stv.tv_sec < 10) { 216 warnx("slept time + leftover time < 10 sec"); 217 return 1; 218 } 219 220 221 if (wait(&status) < 0) 222 err(1, "wait"); 223 224 return 0; 225 } 226 227 int 228 short_time(void) 229 { 230 struct timespec ts, rts; 231 pid_t pid; 232 int status; 233 234 signal(SIGUSR1, sighandler); 235 236 pid = getpid(); 237 238 switch(fork()) { 239 case -1: 240 err(1, "fork"); 241 default: 242 /* Sleep two seconds, then shoot parent. */ 243 ts.tv_sec = 2; 244 ts.tv_nsec = 0; 245 nanosleep(&ts, NULL); 246 kill(pid, SIGUSR1); 247 exit(0); 248 } 249 250 ts.tv_sec = 0; 251 ts.tv_nsec = 1; 252 if (nanosleep(&ts, NULL) <= 0) { 253 warn("short_time: nanosleep"); 254 return 1; 255 } 256 257 if (wait(&status) < 0) 258 err(1, "wait"); 259 260 return 0; 261 } 262