diff options
Diffstat (limited to 'miscutils/time.c')
-rw-r--r-- | miscutils/time.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/miscutils/time.c b/miscutils/time.c index 77d35a832..9a1039be9 100644 --- a/miscutils/time.c +++ b/miscutils/time.c | |||
@@ -22,10 +22,17 @@ | |||
22 | //kbuild:lib-$(CONFIG_TIME) += time.o | 22 | //kbuild:lib-$(CONFIG_TIME) += time.o |
23 | 23 | ||
24 | //usage:#define time_trivial_usage | 24 | //usage:#define time_trivial_usage |
25 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
25 | //usage: "[-vpa] [-o FILE] PROG ARGS" | 26 | //usage: "[-vpa] [-o FILE] PROG ARGS" |
27 | //usage: ) | ||
28 | //usage: IF_PLATFORM_MINGW32( | ||
29 | //usage: "[-pa] [-f FMT] [-o FILE] PROG ARGS" | ||
30 | //usage: ) | ||
26 | //usage:#define time_full_usage "\n\n" | 31 | //usage:#define time_full_usage "\n\n" |
27 | //usage: "Run PROG, display resource usage when it exits\n" | 32 | //usage: "Run PROG, display resource usage when it exits\n" |
33 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
28 | //usage: "\n -v Verbose" | 34 | //usage: "\n -v Verbose" |
35 | //usage: ) | ||
29 | //usage: "\n -p POSIX output format" | 36 | //usage: "\n -p POSIX output format" |
30 | //usage: "\n -f FMT Custom format" | 37 | //usage: "\n -f FMT Custom format" |
31 | //usage: "\n -o FILE Write result to FILE" | 38 | //usage: "\n -o FILE Write result to FILE" |
@@ -57,6 +64,7 @@ static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T"; | |||
57 | /* The output format for the -p option .*/ | 64 | /* The output format for the -p option .*/ |
58 | static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; | 65 | static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; |
59 | 66 | ||
67 | #if !ENABLE_PLATFORM_MINGW32 | ||
60 | /* Format string for printing all statistics verbosely. | 68 | /* Format string for printing all statistics verbosely. |
61 | Keep this output to 24 lines so users on terminals can see it all.*/ | 69 | Keep this output to 24 lines so users on terminals can see it all.*/ |
62 | static const char long_format[] ALIGN1 = | 70 | static const char long_format[] ALIGN1 = |
@@ -83,6 +91,7 @@ static const char long_format[] ALIGN1 = | |||
83 | "\tSignals delivered: %k\n" | 91 | "\tSignals delivered: %k\n" |
84 | "\tPage size (bytes): %Z\n" | 92 | "\tPage size (bytes): %Z\n" |
85 | "\tExit status: %x"; | 93 | "\tExit status: %x"; |
94 | #endif | ||
86 | 95 | ||
87 | /* Wait for and fill in data on child process PID. | 96 | /* Wait for and fill in data on child process PID. |
88 | Return 0 on error, 1 if ok. */ | 97 | Return 0 on error, 1 if ok. */ |
@@ -93,7 +102,11 @@ static void resuse_end(pid_t pid, resource_t *resp) | |||
93 | 102 | ||
94 | /* Ignore signals, but don't ignore the children. When wait3 | 103 | /* Ignore signals, but don't ignore the children. When wait3 |
95 | * returns the child process, set the time the command finished. */ | 104 | * returns the child process, set the time the command finished. */ |
105 | #if !ENABLE_PLATFORM_MINGW32 | ||
96 | while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { | 106 | while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { |
107 | #else | ||
108 | while ((caught=mingw_wait3(pid, &resp->waitstatus, 0, &resp->ru)) != pid) { | ||
109 | #endif | ||
97 | if (caught == -1 && errno != EINTR) { | 110 | if (caught == -1 && errno != EINTR) { |
98 | bb_simple_perror_msg("wait"); | 111 | bb_simple_perror_msg("wait"); |
99 | return; | 112 | return; |
@@ -189,9 +202,11 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages) | |||
189 | 202 | ||
190 | static void summarize(const char *fmt, char **command, resource_t *resp) | 203 | static void summarize(const char *fmt, char **command, resource_t *resp) |
191 | { | 204 | { |
205 | #if !ENABLE_PLATFORM_MINGW32 | ||
192 | unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ | 206 | unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ |
193 | unsigned cpu_ticks; /* Same, in "CPU ticks" */ | 207 | unsigned cpu_ticks; /* Same, in "CPU ticks" */ |
194 | unsigned pagesize = bb_getpagesize(); | 208 | unsigned pagesize = bb_getpagesize(); |
209 | #endif | ||
195 | 210 | ||
196 | /* Impossible: we do not use WUNTRACED flag in wait()... | 211 | /* Impossible: we do not use WUNTRACED flag in wait()... |
197 | if (WIFSTOPPED(resp->waitstatus)) | 212 | if (WIFSTOPPED(resp->waitstatus)) |
@@ -205,6 +220,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
205 | printf("Command exited with non-zero status %u\n", | 220 | printf("Command exited with non-zero status %u\n", |
206 | WEXITSTATUS(resp->waitstatus)); | 221 | WEXITSTATUS(resp->waitstatus)); |
207 | 222 | ||
223 | #if !ENABLE_PLATFORM_MINGW32 | ||
208 | vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 | 224 | vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 |
209 | + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; | 225 | + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; |
210 | 226 | ||
@@ -215,6 +231,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
215 | cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; | 231 | cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; |
216 | #endif | 232 | #endif |
217 | if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ | 233 | if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ |
234 | #endif | ||
218 | 235 | ||
219 | while (*fmt) { | 236 | while (*fmt) { |
220 | /* Handle leading literal part */ | 237 | /* Handle leading literal part */ |
@@ -242,6 +259,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
242 | case 'C': /* The command that got timed. */ | 259 | case 'C': /* The command that got timed. */ |
243 | printargv(command); | 260 | printargv(command); |
244 | break; | 261 | break; |
262 | #if !ENABLE_PLATFORM_MINGW32 | ||
245 | case 'D': /* Average unshared data size. */ | 263 | case 'D': /* Average unshared data size. */ |
246 | /* (linux kernel sets ru_idrss/isrss/ixrss to 0, | 264 | /* (linux kernel sets ru_idrss/isrss/ixrss to 0, |
247 | * docs say the value is in kbytes, so ptok() is wrong) */ | 265 | * docs say the value is in kbytes, so ptok() is wrong) */ |
@@ -251,6 +269,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
251 | ) / cpu_ticks | 269 | ) / cpu_ticks |
252 | ); | 270 | ); |
253 | break; | 271 | break; |
272 | #endif | ||
254 | case 'E': { /* Elapsed real (wall clock) time. */ | 273 | case 'E': { /* Elapsed real (wall clock) time. */ |
255 | unsigned seconds = resp->elapsed_ms / 1000; | 274 | unsigned seconds = resp->elapsed_ms / 1000; |
256 | if (seconds >= 3600) /* One hour -> h:m:s. */ | 275 | if (seconds >= 3600) /* One hour -> h:m:s. */ |
@@ -265,6 +284,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
265 | (unsigned)(resp->elapsed_ms / 10) % 100); | 284 | (unsigned)(resp->elapsed_ms / 10) % 100); |
266 | break; | 285 | break; |
267 | } | 286 | } |
287 | #if !ENABLE_PLATFORM_MINGW32 | ||
268 | case 'F': /* Major page faults. */ | 288 | case 'F': /* Major page faults. */ |
269 | printf("%lu", resp->ru.ru_majflt); | 289 | printf("%lu", resp->ru.ru_majflt); |
270 | break; | 290 | break; |
@@ -297,6 +317,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
297 | case 'R': /* Minor page faults (reclaims). */ | 317 | case 'R': /* Minor page faults (reclaims). */ |
298 | printf("%lu", resp->ru.ru_minflt); | 318 | printf("%lu", resp->ru.ru_minflt); |
299 | break; | 319 | break; |
320 | #endif | ||
300 | case 'S': /* System time. */ | 321 | case 'S': /* System time. */ |
301 | printf("%u.%02u", | 322 | printf("%u.%02u", |
302 | (unsigned)resp->ru.ru_stime.tv_sec, | 323 | (unsigned)resp->ru.ru_stime.tv_sec, |
@@ -331,6 +352,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
331 | (unsigned)(resp->ru.ru_utime.tv_sec % 60), | 352 | (unsigned)(resp->ru.ru_utime.tv_sec % 60), |
332 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); | 353 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); |
333 | break; | 354 | break; |
355 | #if !ENABLE_PLATFORM_MINGW32 | ||
334 | case 'W': /* Times swapped out. */ | 356 | case 'W': /* Times swapped out. */ |
335 | printf("%lu", resp->ru.ru_nswap); | 357 | printf("%lu", resp->ru.ru_nswap); |
336 | break; | 358 | break; |
@@ -343,11 +365,13 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
343 | case 'c': /* Involuntary context switches. */ | 365 | case 'c': /* Involuntary context switches. */ |
344 | printf("%lu", resp->ru.ru_nivcsw); | 366 | printf("%lu", resp->ru.ru_nivcsw); |
345 | break; | 367 | break; |
368 | #endif | ||
346 | case 'e': /* Elapsed real time in seconds. */ | 369 | case 'e': /* Elapsed real time in seconds. */ |
347 | printf("%u.%02u", | 370 | printf("%u.%02u", |
348 | (unsigned)resp->elapsed_ms / 1000, | 371 | (unsigned)resp->elapsed_ms / 1000, |
349 | (unsigned)(resp->elapsed_ms / 10) % 100); | 372 | (unsigned)(resp->elapsed_ms / 10) % 100); |
350 | break; | 373 | break; |
374 | #if !ENABLE_PLATFORM_MINGW32 | ||
351 | case 'k': /* Signals delivered. */ | 375 | case 'k': /* Signals delivered. */ |
352 | printf("%lu", resp->ru.ru_nsignals); | 376 | printf("%lu", resp->ru.ru_nsignals); |
353 | break; | 377 | break; |
@@ -366,6 +390,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
366 | case 'w': /* Voluntary context switches. */ | 390 | case 'w': /* Voluntary context switches. */ |
367 | printf("%lu", resp->ru.ru_nvcsw); | 391 | printf("%lu", resp->ru.ru_nvcsw); |
368 | break; | 392 | break; |
393 | #endif | ||
369 | case 'x': /* Exit status. */ | 394 | case 'x': /* Exit status. */ |
370 | printf("%u", WEXITSTATUS(resp->waitstatus)); | 395 | printf("%u", WEXITSTATUS(resp->waitstatus)); |
371 | break; | 396 | break; |
@@ -409,6 +434,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
409 | static void run_command(char *const *cmd, resource_t *resp) | 434 | static void run_command(char *const *cmd, resource_t *resp) |
410 | { | 435 | { |
411 | pid_t pid; | 436 | pid_t pid; |
437 | #if !ENABLE_PLATFORM_MINGW32 | ||
412 | void (*interrupt_signal)(int); | 438 | void (*interrupt_signal)(int); |
413 | void (*quit_signal)(int); | 439 | void (*quit_signal)(int); |
414 | 440 | ||
@@ -429,6 +455,13 @@ static void run_command(char *const *cmd, resource_t *resp) | |||
429 | /* Re-enable signals. */ | 455 | /* Re-enable signals. */ |
430 | signal(SIGINT, interrupt_signal); | 456 | signal(SIGINT, interrupt_signal); |
431 | signal(SIGQUIT, quit_signal); | 457 | signal(SIGQUIT, quit_signal); |
458 | #else | ||
459 | resp->elapsed_ms = monotonic_ms(); | ||
460 | if ((pid=spawn((char **)cmd)) == -1) | ||
461 | bb_perror_msg_and_die("can't execute %s", cmd[0]); | ||
462 | |||
463 | resuse_end(pid, resp); | ||
464 | #endif | ||
432 | } | 465 | } |
433 | 466 | ||
434 | int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 467 | int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -442,20 +475,35 @@ int time_main(int argc UNUSED_PARAM, char **argv) | |||
442 | int opt; | 475 | int opt; |
443 | int ex; | 476 | int ex; |
444 | enum { | 477 | enum { |
478 | #if !ENABLE_PLATFORM_MINGW32 | ||
445 | OPT_v = (1 << 0), | 479 | OPT_v = (1 << 0), |
446 | OPT_p = (1 << 1), | 480 | OPT_p = (1 << 1), |
447 | OPT_a = (1 << 2), | 481 | OPT_a = (1 << 2), |
448 | OPT_o = (1 << 3), | 482 | OPT_o = (1 << 3), |
449 | OPT_f = (1 << 4), | 483 | OPT_f = (1 << 4), |
484 | #else | ||
485 | OPT_p = (1 << 0), | ||
486 | OPT_a = (1 << 1), | ||
487 | OPT_o = (1 << 2), | ||
488 | OPT_f = (1 << 3), | ||
489 | #endif | ||
450 | }; | 490 | }; |
451 | 491 | ||
452 | /* "+": stop on first non-option */ | 492 | /* "+": stop on first non-option */ |
493 | #if !ENABLE_PLATFORM_MINGW32 | ||
453 | opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, | 494 | opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, |
454 | &output_filename, &output_format | 495 | &output_filename, &output_format |
455 | ); | 496 | ); |
497 | #else | ||
498 | opt = getopt32(argv, "^+" "pao:f:" "\0" "-1"/*at least one arg*/, | ||
499 | &output_filename, &output_format | ||
500 | ); | ||
501 | #endif | ||
456 | argv += optind; | 502 | argv += optind; |
503 | #if !ENABLE_PLATFORM_MINGW32 | ||
457 | if (opt & OPT_v) | 504 | if (opt & OPT_v) |
458 | output_format = long_format; | 505 | output_format = long_format; |
506 | #endif | ||
459 | if (opt & OPT_p) | 507 | if (opt & OPT_p) |
460 | output_format = posix_format; | 508 | output_format = posix_format; |
461 | output_fd = STDERR_FILENO; | 509 | output_fd = STDERR_FILENO; |
@@ -476,6 +524,9 @@ int time_main(int argc UNUSED_PARAM, char **argv) | |||
476 | 524 | ||
477 | /* Cheat. printf's are shorter :) */ | 525 | /* Cheat. printf's are shorter :) */ |
478 | xdup2(output_fd, STDOUT_FILENO); | 526 | xdup2(output_fd, STDOUT_FILENO); |
527 | #if ENABLE_PLATFORM_MINGW32 | ||
528 | setvbuf(stdout, NULL, _IOFBF, 256); | ||
529 | #endif | ||
479 | summarize(output_format, argv, &res); | 530 | summarize(output_format, argv, &res); |
480 | 531 | ||
481 | ex = WEXITSTATUS(res.waitstatus); | 532 | ex = WEXITSTATUS(res.waitstatus); |