aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-04-06 09:03:52 +0100
committerRon Yorston <rmy@pobox.com>2020-04-06 09:03:52 +0100
commit9181e1363f09f80ba822175886450b751e408f14 (patch)
tree000415bab289dd387e9217db9c1da7b0c2bf8549
parent4ecfc9fc115221ec66769915bf02ac37c40ffcd5 (diff)
downloadbusybox-w32-9181e1363f09f80ba822175886450b751e408f14.tar.gz
busybox-w32-9181e1363f09f80ba822175886450b751e408f14.tar.bz2
busybox-w32-9181e1363f09f80ba822175886450b751e408f14.zip
time: WIN32 port
Port the time applet to WIN32. This requires the implemntation of a replacement for wait3(2). Only elapsed, user and system times are supported, not the memory and i/o statistics reported by GNU time.
-rw-r--r--configs/mingw32_defconfig4
-rw-r--r--configs/mingw64_defconfig4
-rw-r--r--include/mingw.h3
-rw-r--r--miscutils/time.c55
-rw-r--r--win32/process.c41
-rw-r--r--win32/sys/resource.h11
6 files changed, 106 insertions, 12 deletions
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index 5616851f6..a86be37ea 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.32.0.git 3# Busybox version: 1.32.0.git
4# Sun Apr 5 09:22:18 2020 4# Mon Apr 6 08:34:52 2020
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -832,7 +832,7 @@ CONFIG_MAN=y
832# CONFIG_SETFATTR is not set 832# CONFIG_SETFATTR is not set
833# CONFIG_SETSERIAL is not set 833# CONFIG_SETSERIAL is not set
834CONFIG_STRINGS=y 834CONFIG_STRINGS=y
835# CONFIG_TIME is not set 835CONFIG_TIME=y
836CONFIG_TS=y 836CONFIG_TS=y
837CONFIG_TTYSIZE=y 837CONFIG_TTYSIZE=y
838# CONFIG_UBIRENAME is not set 838# CONFIG_UBIRENAME is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index 92daa7839..2c60d22ac 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.32.0.git 3# Busybox version: 1.32.0.git
4# Sun Apr 5 09:22:18 2020 4# Mon Apr 6 08:34:52 2020
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -832,7 +832,7 @@ CONFIG_MAN=y
832# CONFIG_SETFATTR is not set 832# CONFIG_SETFATTR is not set
833# CONFIG_SETSERIAL is not set 833# CONFIG_SETSERIAL is not set
834CONFIG_STRINGS=y 834CONFIG_STRINGS=y
835# CONFIG_TIME is not set 835CONFIG_TIME=y
836CONFIG_TS=y 836CONFIG_TS=y
837CONFIG_TTYSIZE=y 837CONFIG_TTYSIZE=y
838# CONFIG_UBIRENAME is not set 838# CONFIG_UBIRENAME is not set
diff --git a/include/mingw.h b/include/mingw.h
index 3d0daee38..3516cd31c 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -347,7 +347,8 @@ int mingw_fstat(int fd, struct mingw_stat *buf);
347 */ 347 */
348#define WNOHANG 1 348#define WNOHANG 1
349#define WUNTRACED 2 349#define WUNTRACED 2
350int waitpid(pid_t pid, int *status, int options); 350pid_t waitpid(pid_t pid, int *status, int options);
351pid_t mingw_wait3(pid_t pid, int *status, int options, struct rusage *rusage);
351 352
352/* 353/*
353 * time.h 354 * time.h
diff --git a/miscutils/time.c b/miscutils/time.c
index d15d363f3..eace390e6 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -22,12 +22,21 @@
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] [-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"
37//usage: IF_NOT_PLATFORM_MINGW32(
30//usage: "\n -f FMT Custom format" 38//usage: "\n -f FMT Custom format"
39//usage: )
31//usage: "\n -o FILE Write result to FILE" 40//usage: "\n -o FILE Write result to FILE"
32//usage: "\n -a Append (else overwrite)" 41//usage: "\n -a Append (else overwrite)"
33 42
@@ -50,6 +59,7 @@ static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T";
50/* The output format for the -p option .*/ 59/* The output format for the -p option .*/
51static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; 60static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S";
52 61
62#if !ENABLE_PLATFORM_MINGW32
53/* Format string for printing all statistics verbosely. 63/* Format string for printing all statistics verbosely.
54 Keep this output to 24 lines so users on terminals can see it all.*/ 64 Keep this output to 24 lines so users on terminals can see it all.*/
55static const char long_format[] ALIGN1 = 65static const char long_format[] ALIGN1 =
@@ -76,6 +86,7 @@ static const char long_format[] ALIGN1 =
76 "\tSignals delivered: %k\n" 86 "\tSignals delivered: %k\n"
77 "\tPage size (bytes): %Z\n" 87 "\tPage size (bytes): %Z\n"
78 "\tExit status: %x"; 88 "\tExit status: %x";
89#endif
79 90
80/* Wait for and fill in data on child process PID. 91/* Wait for and fill in data on child process PID.
81 Return 0 on error, 1 if ok. */ 92 Return 0 on error, 1 if ok. */
@@ -86,7 +97,11 @@ static void resuse_end(pid_t pid, resource_t *resp)
86 97
87 /* Ignore signals, but don't ignore the children. When wait3 98 /* Ignore signals, but don't ignore the children. When wait3
88 * returns the child process, set the time the command finished. */ 99 * returns the child process, set the time the command finished. */
100#if !ENABLE_PLATFORM_MINGW32
89 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { 101 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) {
102#else
103 while ((caught=mingw_wait3(pid, &resp->waitstatus, 0, &resp->ru)) != pid) {
104#endif
90 if (caught == -1 && errno != EINTR) { 105 if (caught == -1 && errno != EINTR) {
91 bb_simple_perror_msg("wait"); 106 bb_simple_perror_msg("wait");
92 return; 107 return;
@@ -95,6 +110,7 @@ static void resuse_end(pid_t pid, resource_t *resp)
95 resp->elapsed_ms = monotonic_ms() - resp->elapsed_ms; 110 resp->elapsed_ms = monotonic_ms() - resp->elapsed_ms;
96} 111}
97 112
113#if !ENABLE_PLATFORM_MINGW32
98static void printargv(char *const *argv) 114static void printargv(char *const *argv)
99{ 115{
100 const char *fmt = " %s" + 1; 116 const char *fmt = " %s" + 1;
@@ -124,6 +140,7 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
124 tmp = pages * pagesize; /* Larger first, */ 140 tmp = pages * pagesize; /* Larger first, */
125 return tmp / 1024; /* then smaller. */ 141 return tmp / 1024; /* then smaller. */
126} 142}
143#endif
127 144
128/* summarize: Report on the system use of a command. 145/* summarize: Report on the system use of a command.
129 146
@@ -173,11 +190,17 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
173#define TICKS_PER_SEC 100 190#define TICKS_PER_SEC 100
174#endif 191#endif
175 192
193#if ENABLE_PLATFORM_MINGW32
194#define summarize(f, c, r) summarize(f, r)
195#endif
196
176static void summarize(const char *fmt, char **command, resource_t *resp) 197static void summarize(const char *fmt, char **command, resource_t *resp)
177{ 198{
199#if !ENABLE_PLATFORM_MINGW32
178 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ 200 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
179 unsigned cpu_ticks; /* Same, in "CPU ticks" */ 201 unsigned cpu_ticks; /* Same, in "CPU ticks" */
180 unsigned pagesize = getpagesize(); 202 unsigned pagesize = getpagesize();
203#endif
181 204
182 /* Impossible: we do not use WUNTRACED flag in wait()... 205 /* Impossible: we do not use WUNTRACED flag in wait()...
183 if (WIFSTOPPED(resp->waitstatus)) 206 if (WIFSTOPPED(resp->waitstatus))
@@ -191,6 +214,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
191 printf("Command exited with non-zero status %u\n", 214 printf("Command exited with non-zero status %u\n",
192 WEXITSTATUS(resp->waitstatus)); 215 WEXITSTATUS(resp->waitstatus));
193 216
217#if !ENABLE_PLATFORM_MINGW32
194 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 218 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
195 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; 219 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
196 220
@@ -201,6 +225,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
201 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; 225 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000;
202#endif 226#endif
203 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ 227 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
228#endif
204 229
205 while (*fmt) { 230 while (*fmt) {
206 /* Handle leading literal part */ 231 /* Handle leading literal part */
@@ -234,6 +259,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
234 bb_putchar(*fmt); 259 bb_putchar(*fmt);
235 break; 260 break;
236#endif 261#endif
262#if !ENABLE_PLATFORM_MINGW32
237 case 'C': /* The command that got timed. */ 263 case 'C': /* The command that got timed. */
238 printargv(command); 264 printargv(command);
239 break; 265 break;
@@ -242,6 +268,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
242 (ptok(pagesize, (UL) resp->ru.ru_idrss) + 268 (ptok(pagesize, (UL) resp->ru.ru_idrss) +
243 ptok(pagesize, (UL) resp->ru.ru_isrss)) / cpu_ticks); 269 ptok(pagesize, (UL) resp->ru.ru_isrss)) / cpu_ticks);
244 break; 270 break;
271#endif
245 case 'E': { /* Elapsed real (wall clock) time. */ 272 case 'E': { /* Elapsed real (wall clock) time. */
246 unsigned seconds = resp->elapsed_ms / 1000; 273 unsigned seconds = resp->elapsed_ms / 1000;
247 if (seconds >= 3600) /* One hour -> h:m:s. */ 274 if (seconds >= 3600) /* One hour -> h:m:s. */
@@ -256,6 +283,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
256 (unsigned)(resp->elapsed_ms / 10) % 100); 283 (unsigned)(resp->elapsed_ms / 10) % 100);
257 break; 284 break;
258 } 285 }
286#if !ENABLE_PLATFORM_MINGW32
259 case 'F': /* Major page faults. */ 287 case 'F': /* Major page faults. */
260 printf("%lu", resp->ru.ru_majflt); 288 printf("%lu", resp->ru.ru_majflt);
261 break; 289 break;
@@ -284,6 +312,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
284 case 'R': /* Minor page faults (reclaims). */ 312 case 'R': /* Minor page faults (reclaims). */
285 printf("%lu", resp->ru.ru_minflt); 313 printf("%lu", resp->ru.ru_minflt);
286 break; 314 break;
315#endif
287 case 'S': /* System time. */ 316 case 'S': /* System time. */
288 printf("%u.%02u", 317 printf("%u.%02u",
289 (unsigned)resp->ru.ru_stime.tv_sec, 318 (unsigned)resp->ru.ru_stime.tv_sec,
@@ -318,6 +347,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
318 (unsigned)(resp->ru.ru_utime.tv_sec % 60), 347 (unsigned)(resp->ru.ru_utime.tv_sec % 60),
319 (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); 348 (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
320 break; 349 break;
350#if !ENABLE_PLATFORM_MINGW32
321 case 'W': /* Times swapped out. */ 351 case 'W': /* Times swapped out. */
322 printf("%lu", resp->ru.ru_nswap); 352 printf("%lu", resp->ru.ru_nswap);
323 break; 353 break;
@@ -330,11 +360,13 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
330 case 'c': /* Involuntary context switches. */ 360 case 'c': /* Involuntary context switches. */
331 printf("%lu", resp->ru.ru_nivcsw); 361 printf("%lu", resp->ru.ru_nivcsw);
332 break; 362 break;
363#endif
333 case 'e': /* Elapsed real time in seconds. */ 364 case 'e': /* Elapsed real time in seconds. */
334 printf("%u.%02u", 365 printf("%u.%02u",
335 (unsigned)resp->elapsed_ms / 1000, 366 (unsigned)resp->elapsed_ms / 1000,
336 (unsigned)(resp->elapsed_ms / 10) % 100); 367 (unsigned)(resp->elapsed_ms / 10) % 100);
337 break; 368 break;
369#if !ENABLE_PLATFORM_MINGW32
338 case 'k': /* Signals delivered. */ 370 case 'k': /* Signals delivered. */
339 printf("%lu", resp->ru.ru_nsignals); 371 printf("%lu", resp->ru.ru_nsignals);
340 break; 372 break;
@@ -356,6 +388,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
356 case 'x': /* Exit status. */ 388 case 'x': /* Exit status. */
357 printf("%u", WEXITSTATUS(resp->waitstatus)); 389 printf("%u", WEXITSTATUS(resp->waitstatus));
358 break; 390 break;
391#endif
359 } 392 }
360 break; 393 break;
361 394
@@ -390,6 +423,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
390static void run_command(char *const *cmd, resource_t *resp) 423static void run_command(char *const *cmd, resource_t *resp)
391{ 424{
392 pid_t pid; 425 pid_t pid;
426#if !ENABLE_PLATFORM_MINGW32
393 void (*interrupt_signal)(int); 427 void (*interrupt_signal)(int);
394 void (*quit_signal)(int); 428 void (*quit_signal)(int);
395 429
@@ -410,6 +444,13 @@ static void run_command(char *const *cmd, resource_t *resp)
410 /* Re-enable signals. */ 444 /* Re-enable signals. */
411 signal(SIGINT, interrupt_signal); 445 signal(SIGINT, interrupt_signal);
412 signal(SIGQUIT, quit_signal); 446 signal(SIGQUIT, quit_signal);
447#else
448 resp->elapsed_ms = monotonic_ms();
449 if ((pid=spawn((char **)cmd)) == -1)
450 bb_perror_msg_and_die("can't execute %s", cmd[0]);
451
452 resuse_end(pid, resp);
453#endif
413} 454}
414 455
415int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 456int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -423,20 +464,34 @@ int time_main(int argc UNUSED_PARAM, char **argv)
423 int opt; 464 int opt;
424 int ex; 465 int ex;
425 enum { 466 enum {
467#if ENABLE_PLATFORM_MINGW32
426 OPT_v = (1 << 0), 468 OPT_v = (1 << 0),
427 OPT_p = (1 << 1), 469 OPT_p = (1 << 1),
428 OPT_a = (1 << 2), 470 OPT_a = (1 << 2),
429 OPT_o = (1 << 3), 471 OPT_o = (1 << 3),
430 OPT_f = (1 << 4), 472 OPT_f = (1 << 4),
473#else
474 OPT_p = (1 << 0),
475 OPT_a = (1 << 1),
476 OPT_o = (1 << 2),
477#endif
431 }; 478 };
432 479
433 /* "+": stop on first non-option */ 480 /* "+": stop on first non-option */
481#if !ENABLE_PLATFORM_MINGW32
434 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, 482 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/,
435 &output_filename, &output_format 483 &output_filename, &output_format
436 ); 484 );
485#else
486 opt = getopt32(argv, "^+" "pao:" "\0" "-1"/*at least one arg*/,
487 &output_filename
488 );
489#endif
437 argv += optind; 490 argv += optind;
491#if !ENABLE_PLATFORM_MINGW32
438 if (opt & OPT_v) 492 if (opt & OPT_v)
439 output_format = long_format; 493 output_format = long_format;
494#endif
440 if (opt & OPT_p) 495 if (opt & OPT_p)
441 output_format = posix_format; 496 output_format = posix_format;
442 output_fd = STDERR_FILENO; 497 output_fd = STDERR_FILENO;
diff --git a/win32/process.c b/win32/process.c
index 67ce3c100..28df33c23 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -3,21 +3,48 @@
3#include <psapi.h> 3#include <psapi.h>
4#include "lazyload.h" 4#include "lazyload.h"
5 5
6int waitpid(pid_t pid, int *status, int options) 6pid_t waitpid(pid_t pid, int *status, int options)
7#if ENABLE_TIME
8{
9 return mingw_wait3(pid, status, options, NULL);
10}
11#endif
12
13#if ENABLE_TIME
14pid_t mingw_wait3(pid_t pid, int *status, int options, struct rusage *rusage)
15#endif
7{ 16{
8 HANDLE proc; 17 HANDLE proc;
9 intptr_t ret; 18 DWORD code;
10 19
11 /* Windows does not understand parent-child */ 20 /* Windows does not understand parent-child */
12 if (pid > 0 && options == 0) { 21 if (pid > 0 && options == 0) {
13 if ( (proc=OpenProcess(SYNCHRONIZE|PROCESS_QUERY_INFORMATION, 22 if ( (proc=OpenProcess(SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
14 FALSE, pid)) != NULL ) { 23 FALSE, pid)) != NULL ) {
15 ret = _cwait(status, (intptr_t)proc, 0); 24 WaitForSingleObject(proc, INFINITE);
16 CloseHandle(proc); 25 GetExitCodeProcess(proc, &code);
17 if (ret == -1) { 26#if ENABLE_TIME
18 return -1; 27 if (rusage != NULL) {
28 FILETIME crTime, exTime, keTime, usTime;
29
30 memset(rusage, 0, sizeof(*rusage));
31 if (GetProcessTimes(proc, &crTime, &exTime, &keTime, &usTime)) {
32 uint64_t kernel_usec =
33 (((uint64_t)keTime.dwHighDateTime << 32)
34 | (uint64_t)keTime.dwLowDateTime)/10;
35 uint64_t user_usec =
36 (((uint64_t)usTime.dwHighDateTime << 32)
37 | (uint64_t)usTime.dwLowDateTime)/10;
38
39 rusage->ru_utime.tv_sec = user_usec / 1000000U;
40 rusage->ru_utime.tv_usec = user_usec % 1000000U;
41 rusage->ru_stime.tv_sec = kernel_usec / 1000000U;
42 rusage->ru_stime.tv_usec = kernel_usec % 1000000U;
43 }
19 } 44 }
20 *status <<= 8; 45#endif
46 CloseHandle(proc);
47 *status = code << 8;
21 return pid; 48 return pid;
22 } 49 }
23 } 50 }
diff --git a/win32/sys/resource.h b/win32/sys/resource.h
index e69de29bb..3220d8112 100644
--- a/win32/sys/resource.h
+++ b/win32/sys/resource.h
@@ -0,0 +1,11 @@
1#ifndef _SYS_RESOURCE_H
2#define _SYS_RESOURCE_H 1
3
4#include <time.h>
5
6struct rusage {
7 struct timeval ru_utime;
8 struct timeval ru_stime;
9};
10
11#endif