From 29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:21:29 +0200 Subject: Adding upstream version 1:0.1.9998svn3589+dfsg. Signed-off-by: Daniel Baumann --- src/misc/Makefile.kmk | 73 ++++++++ src/misc/kmk_time.c | 437 ++++++++++++++++++++++++++++++++++++++++++++ src/misc/win_exec_wrapper.c | 120 ++++++++++++ 3 files changed, 630 insertions(+) create mode 100644 src/misc/Makefile.kmk create mode 100644 src/misc/kmk_time.c create mode 100644 src/misc/win_exec_wrapper.c (limited to 'src/misc') diff --git a/src/misc/Makefile.kmk b/src/misc/Makefile.kmk new file mode 100644 index 0000000..6c863bf --- /dev/null +++ b/src/misc/Makefile.kmk @@ -0,0 +1,73 @@ +# $Id: Makefile.kmk 3538 2021-12-21 12:19:40Z bird $ +## @file +# Sub-makefile for kmk_time. +# + +# +# Copyright (c) 2008-2010 knut st. osmundsen +# +# This file is part of kBuild. +# +# kBuild is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# kBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kBuild. If not, see +# +# + +SUB_DEPTH = ../.. +include $(PATH_KBUILD)/subheader.kmk + +PROGRAMS += kmk_time +kmk_time_TEMPLATE = BIN +kmk_time_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) +kmk_time_SOURCES = kmk_time.c +kmk_time_SOURCES.win = ../lib/quote_argv.c + + +# +# Wrapper stubs for using the kBuild binaries as standard unixy ones on windows. +# +TEMPLATE_EXECWRAPPER = Windows exec wrapper +TEMPLATE_EXECWRAPPER_EXTENDS = BIN +TEMPLATE_EXECWRAPPER_INST = $(TEMPLATE_BIN_INST)wrappers/ +TEMPLATE_EXECWRAPPER_CFLAGS = $(TEMPLATE_BIN_CFLAGS) -GS- +TEMPLATE_EXECWRAPPER_LDFLAGS = $(TEMPLATE_BIN_LDFLAGS) /Entry:BareBoneStart +TEMPLATE_EXECWRAPPER_LIBS = $(NO_SUCH_VARIABLE) +TEMPLATE_EXECWRAPPER_LIBS.x86 = $(NO_SUCH_VARIABLE) +TEMPLATE_EXECWRAPPER_LIBS.amd64 = $(NO_SUCH_VARIABLE) +TEMPLATE_EXECWRAPPER_SOURCES = win_exec_wrapper.c + +define def_WindowsWrapper +PROGRAMS.win += $1 +$1_TEMPLATE = EXECWRAPPER +$1_DEFS = TARGET_EXE_NAME=\"$2.exe\" +endef + +$(evalcall2 def_WindowsWrapper,cat,kmk_cat) +$(evalcall2 def_WindowsWrapper,cp,kmk_cp) +$(evalcall2 def_WindowsWrapper,echo,kmk_echo) +$(evalcall2 def_WindowsWrapper,expr,kmk_expr) +$(evalcall2 def_WindowsWrapper,grep,kmk_grep) +$(evalcall2 def_WindowsWrapper,ln,kmk_ln) +$(evalcall2 def_WindowsWrapper,mkdir,kmk_mkdir) +$(evalcall2 def_WindowsWrapper,mv,kmk_mv) +$(evalcall2 def_WindowsWrapper,kkill,kmk_kill) +$(evalcall2 def_WindowsWrapper,killall,kmk_kill) +$(evalcall2 def_WindowsWrapper,printf,kmk_printf) +$(evalcall2 def_WindowsWrapper,rm,kmk_rm) +$(evalcall2 def_WindowsWrapper,rmdir,kmk_rmdir) +$(evalcall2 def_WindowsWrapper,sed,kmk_sed) +$(evalcall2 def_WindowsWrapper,sleep,kmk_sleep) +$(evalcall2 def_WindowsWrapper,touch,kmk_touch) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/misc/kmk_time.c b/src/misc/kmk_time.c new file mode 100644 index 0000000..8f64fdb --- /dev/null +++ b/src/misc/kmk_time.c @@ -0,0 +1,437 @@ +/* $Id: kmk_time.c 3336 2020-04-22 12:08:35Z bird $ */ +/** @file + * kmk_time - Time program execution. + * + * This is based on kmk/kmkbuiltin/redirect.c. + */ + +/* + * Copyright (c) 2007-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +# include +# include +# include +# include +# include "quote_argv.h" +#else +# include +# include +# include +# include +#endif + +#ifdef __OS2__ +# define INCL_BASE +# include +# ifndef LIBPATHSTRICT +# define LIBPATHSTRICT 3 +# endif +#endif + +#ifndef _MSC_VER +static const char *my_strsignal(int signo) +{ +#define CASE_SIG_RET_STR(sig) if (signo == SIG##sig) return #sig +#ifdef SIGHUP + CASE_SIG_RET_STR(HUP); +#endif +#ifdef SIGINT + CASE_SIG_RET_STR(INT); +#endif +#ifdef SIGQUIT + CASE_SIG_RET_STR(QUIT); +#endif +#ifdef SIGILL + CASE_SIG_RET_STR(ILL); +#endif +#ifdef SIGTRAP + CASE_SIG_RET_STR(TRAP); +#endif +#ifdef SIGABRT + CASE_SIG_RET_STR(ABRT); +#endif +#ifdef SIGIOT + CASE_SIG_RET_STR(IOT); +#endif +#ifdef SIGBUS + CASE_SIG_RET_STR(BUS); +#endif +#ifdef SIGFPE + CASE_SIG_RET_STR(FPE); +#endif +#ifdef SIGKILL + CASE_SIG_RET_STR(KILL); +#endif +#ifdef SIGUSR1 + CASE_SIG_RET_STR(USR1); +#endif +#ifdef SIGSEGV + CASE_SIG_RET_STR(SEGV); +#endif +#ifdef SIGUSR2 + CASE_SIG_RET_STR(USR2); +#endif +#ifdef SIGPIPE + CASE_SIG_RET_STR(PIPE); +#endif +#ifdef SIGALRM + CASE_SIG_RET_STR(ALRM); +#endif +#ifdef SIGTERM + CASE_SIG_RET_STR(TERM); +#endif +#ifdef SIGSTKFLT + CASE_SIG_RET_STR(STKFLT); +#endif +#ifdef SIGCHLD + CASE_SIG_RET_STR(CHLD); +#endif +#ifdef SIGCONT + CASE_SIG_RET_STR(CONT); +#endif +#ifdef SIGSTOP + CASE_SIG_RET_STR(STOP); +#endif +#ifdef SIGTSTP + CASE_SIG_RET_STR(TSTP); +#endif +#ifdef SIGTTIN + CASE_SIG_RET_STR(TTIN); +#endif +#ifdef SIGTTOU + CASE_SIG_RET_STR(TTOU); +#endif +#ifdef SIGURG + CASE_SIG_RET_STR(URG); +#endif +#ifdef SIGXCPU + CASE_SIG_RET_STR(XCPU); +#endif +#ifdef SIGXFSZ + CASE_SIG_RET_STR(XFSZ); +#endif +#ifdef SIGVTALRM + CASE_SIG_RET_STR(VTALRM); +#endif +#ifdef SIGPROF + CASE_SIG_RET_STR(PROF); +#endif +#ifdef SIGWINCH + CASE_SIG_RET_STR(WINCH); +#endif +#ifdef SIGIO + CASE_SIG_RET_STR(IO); +#endif +#ifdef SIGPWR + CASE_SIG_RET_STR(PWR); +#endif +#ifdef SIGSYS + CASE_SIG_RET_STR(SYS); +#endif +#ifdef SIGBREAK + CASE_SIG_RET_STR(BREAK); +#endif +#undef CASE_SIG_RET_STR + return "???"; +} +#endif /* unix */ + +static const char *name(const char *pszName) +{ + const char *psz = strrchr(pszName, '/'); +#if defined(_MSC_VER) || defined(__OS2__) + const char *psz2 = strrchr(pszName, '\\'); + if (!psz2) + psz2 = strrchr(pszName, ':'); + if (psz2 && (!psz || psz2 > psz)) + psz = psz2; +#endif + return psz ? psz + 1 : pszName; +} + + +static int usage(FILE *pOut, const char *argv0) +{ + fprintf(pOut, + "usage: %s [options] [--] [args]\n" + " or: %s --help\n" + " or: %s --version\n" + "\n" + "Options:\n" + " -i , --iteration \n" + " Run the program times and display minium, maximum and average\n" + " run times at the end.\n" + , + argv0, argv0, argv0); +#ifdef _MSC_VER + fprintf(pOut, + " --unquoted\n" + " Windows only: No argument quoting, use them as-is.\n"); +#endif + return 1; +} + + +int main(int argc, char **argv) +{ + int i, j; + int cTimes = 1; +#if defined(_MSC_VER) + int fUnquoted = 0; + FILETIME ftStart, ft; + unsigned _int64 usMin, usMax, usAvg, usTotal, usCur; + unsigned _int64 iStart; + intptr_t rc; +#else + struct timeval tvStart, tv; + unsigned long long usMin, usMax, usAvg, usTotal, usCur; + pid_t pid; + int rc; +#endif + int rcExit = 0; + + /* + * Parse arguments. + */ + if (argc <= 1) + return usage(stderr, name(argv[0])); + for (i = 1; i < argc; i++) + { + char *psz = &argv[i][0]; + if (*psz++ != '-') + break; + + if (*psz == '-') + { + /* '--' ? */ + if (!psz[1]) + { + i++; + break; + } + + /* convert to short. */ + if (!strcmp(psz, "-help")) + psz = "h"; + else if (!strcmp(psz, "-version")) + psz = "V"; + else if (!strcmp(psz, "-iterations")) + psz = "i"; +#if defined(_MSC_VER) + else if (!strcmp(psz, "-unquoted")) + { + fUnquoted = 1; + continue; + } +#endif + } + + switch (*psz) + { + case 'h': + usage(stdout, name(argv[0])); + return 0; + + case 'V': + printf("kmk_time - kBuild version %d.%d.%d (r%u)\n" + "Copyright (C) 2007-2018 knut st. osmundsen\n", + KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, + KBUILD_SVN_REV); + return 0; + + case 'i': + if (i + 1 >= argc) + { + fprintf(stderr, "%s: syntax error: missing iteration count\n", name(argv[0])); + return 1; + } + cTimes = atoi(argv[++i]); + if (cTimes <= 0) + { + fprintf(stderr, "%s: error: invalid interation count '%s'.\n", name(argv[0]), argv[i]); + return 1; + } + break; + + default: + fprintf(stderr, "%s: error: syntax error '%s'\n", name(argv[0]), argv[i]); + return 1; + } + } + + /* + * Make sure there's something to execute. + */ + if (i >= argc) + { + fprintf(stderr, "%s: syntax error: nothing to execute!\n", name(argv[0])); + return usage(stderr, name(argv[0])); + } + + /* + * Execute the program the specified number of times. + */ + usMax = usMin = usTotal = 0; + usMin--; /* wraps to max value */ + for (j = 0; j < cTimes; j++) + { + /* + * Execute the program (it's actually supposed to be a command I think, but wtf). + */ +#if defined(_MSC_VER) + if (!fUnquoted) + { + if (quote_argv(argc - i, &argv[i], 0 /*fWatcomBrainDamage*/, 0 /*fFreeOrLeak*/) != 0) + { + fprintf(stderr, "%s: error: quote_argv failed\n"); + return 8; + } + fUnquoted = 1; /* Don't quote them again in the next iteration. */ + } + + GetSystemTimeAsFileTime(&ftStart); + rc = _spawnvp(_P_WAIT, argv[i], &argv[i]); + if (rc == -1) + { + fprintf(stderr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno)); + return 8; + } + + GetSystemTimeAsFileTime(&ft); + + iStart = ftStart.dwLowDateTime | ((unsigned _int64)ftStart.dwHighDateTime << 32); + usCur = ft.dwLowDateTime | ((unsigned _int64)ft.dwHighDateTime << 32); + usCur -= iStart; + usCur /= 10; /* to usecs */ + + printf("%s: ", name(argv[0])); + if (cTimes != 1) + printf("#%02u ", j + 1); + printf("%um%u.%06us - exit code: %d\n", + (unsigned)(usCur / (60 * 1000000)), + (unsigned)(usCur % (60 * 1000000)) / 1000000, + (unsigned)(usCur % 1000000), + rc); + +#else /* unix: */ + gettimeofday(&tvStart, NULL); + pid = fork(); + if (!pid) + { + /* child */ + execvp(argv[i], &argv[i]); + fprintf(stderr, "%s: error: _execvp(\"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno)); + return 8; + } + if (pid < 0) + { + fprintf(stderr, "%s: error: fork() failed: %s\n", name(argv[0]), strerror(errno)); + return 9; + } + + /* parent, wait for child. */ + rc = 9; + while (waitpid(pid, &rc, 0) == -1 && errno == EINTR) + /* nothing */; + gettimeofday(&tv, NULL); + + /* calc elapsed time */ + tv.tv_sec -= tvStart.tv_sec; + if (tv.tv_usec > tvStart.tv_usec) + tv.tv_usec -= tvStart.tv_usec; + else + { + tv.tv_sec--; + tv.tv_usec = tv.tv_usec + 1000000 - tvStart.tv_usec; + } + usCur = tv.tv_sec * 1000000ULL + + tv.tv_usec; + + printf("%s: ", name(argv[0])); + if (cTimes != 1) + printf("#%02u ", j + 1); + printf("%um%u.%06us", + (unsigned)(tv.tv_sec / 60), + (unsigned)(tv.tv_sec % 60), + (unsigned)tv.tv_usec); + if (WIFEXITED(rc)) + { + printf(" - normal exit: %d\n", WEXITSTATUS(rc)); + rc = WEXITSTATUS(rc); + } +# ifndef __HAIKU__ /**@todo figure how haiku signals that a core was dumped. */ + else if (WIFSIGNALED(rc) && WCOREDUMP(rc)) + { + printf(" - dumped core: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc)); + rc = 10; + } +# endif + else if (WIFSIGNALED(rc)) + { + printf(" - killed by: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc)); + rc = 11; + } + else if (WIFSTOPPED(rc)) + { + printf(" - stopped by: %s (%d)\n", my_strsignal(WSTOPSIG(rc)), WSTOPSIG(rc)); + rc = 12; + } + else + { + printf(" unknown exit status %#x (%d)\n", rc, rc); + rc = 13; + } +#endif /* unix */ + if (rc && !rcExit) + rcExit = (int)rc; + + /* calc min/max/avg */ + usTotal += usCur; + if (usMax < usCur) + usMax = usCur; + if (usMin > usCur) + usMin = usCur; + } + + /* + * Summary if more than one run. + */ + if (cTimes != 1) + { + usAvg = usTotal / cTimes; + + printf("%s: avg %um%u.%06us\n", name(argv[0]), (unsigned)(usAvg / 60000000), (unsigned)(usAvg % 60000000) / 1000000, (unsigned)(usAvg % 1000000)); + printf("%s: min %um%u.%06us\n", name(argv[0]), (unsigned)(usMin / 60000000), (unsigned)(usMin % 60000000) / 1000000, (unsigned)(usMin % 1000000)); + printf("%s: max %um%u.%06us\n", name(argv[0]), (unsigned)(usMax / 60000000), (unsigned)(usMax % 60000000) / 1000000, (unsigned)(usMax % 1000000)); + } + + return rcExit; +} + diff --git a/src/misc/win_exec_wrapper.c b/src/misc/win_exec_wrapper.c new file mode 100644 index 0000000..0e1e851 --- /dev/null +++ b/src/misc/win_exec_wrapper.c @@ -0,0 +1,120 @@ +/* $Id: win_exec_wrapper.c 3528 2021-12-19 16:32:38Z bird $ */ +/** @file + * win_exec_wrapper - Stub for exec'ing a kmk_xxx program. + */ + +/* + * Copyright (c) 2021 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include + + +VOID __stdcall BareBoneStart(VOID) +{ + DWORD dwIgnored; + PROCESS_INFORMATION ProcInfo = { NULL, NULL, 0, 0 }; + WCHAR wszExec[260]; + UINT cwcExec = GetModuleFileNameW(NULL, wszExec, 512); + BOOL fExecOk = FALSE; + WCHAR const * const pwszCommandLine = GetCommandLineW(); + STARTUPINFOW StartInfo = { sizeof(StartInfo), NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}; + GetStartupInfoW(&StartInfo); + + /* + * Make sure we've got the standard handles. + */ + StartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + StartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + StartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + StartInfo.dwFlags |= STARTF_USESTDHANDLES; + + /* + * Construct the executable path. + */ + if (cwcExec > 10) + { + /* Strip the filename. */ +#define IS_SEP(a_wc) ( (a_wc) == '\\' || (a_wc) == ':' || (a_wc) == '\\' ) + while (cwcExec > 3 && !IS_SEP(wszExec[cwcExec - 1])) + cwcExec--; + if (IS_SEP(wszExec[cwcExec - 1])) + { + /* Strip the separator. */ + while (cwcExec > 3 && IS_SEP(wszExec[cwcExec - 1])) + cwcExec--; + if (!IS_SEP(wszExec[cwcExec - 1])) + { + /* Strip the path component: */ + while (cwcExec > 3 && !IS_SEP(wszExec[cwcExec - 1])) + cwcExec--; + if (IS_SEP(wszExec[cwcExec - 1])) + { + /* Insert the target executable name: */ + static char const s_szTargetName[] = TARGET_EXE_NAME; + unsigned off = 0; + while (off < sizeof(s_szTargetName)) + wszExec[cwcExec++] = s_szTargetName[off++]; + fExecOk = cwcExec <= 260; + } + } + } + } + if (fExecOk) + { + /* + * Create the real process. + */ + if (CreateProcessW(wszExec, (WCHAR *)pwszCommandLine, NULL, NULL, TRUE /*bInheritHandles*/, + 0 /*fFlags*/, NULL /*pwszzEnv*/, NULL /*pwszCwd*/, &StartInfo, &ProcInfo)) + { + /* + * Wait for it to complete. + */ + CloseHandle(ProcInfo.hThread); + for (;;) + { + DWORD dwExitCode = 1; + WaitForSingleObject(ProcInfo.hProcess, INFINITE); + if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode)) + for (;;) + ExitProcess(dwExitCode); + Sleep(1); + } + } + else + { + static const char s_szMsg[] = "error: CreateProcessW failed for " TARGET_EXE_NAME "\r\n"; + WriteFile(StartInfo.hStdError, s_szMsg, sizeof(s_szMsg) - 1, &dwIgnored, NULL); + } + } + else + { + static const char s_szMsg[] = "error: path construction failed (" TARGET_EXE_NAME ")\r\n"; + WriteFile(StartInfo.hStdError, s_szMsg, sizeof(s_szMsg) - 1, &dwIgnored, NULL); + } + + for (;;) + ExitProcess(31); +} + -- cgit v1.2.3