tools: Add an "exec" tool.
This utility takes command-strings, e.g. "gcc -c file.c -D...", parses them into an argv, and then execvp()s that. The use-case is Jam, which cannot do this itself, but instead simply calls JAMSHELL (usually just "/bin/sh -c") to do that for it. Shells in general have a large amount of overhead (and bash in particular is especially bad here), so using a utility like this as JAMSHELL in most cases can be a significant speed-up. For example, on Haiku (32-bit): $ time sh -c 'for i in {1..100}; do sh -c "./exec test"; done' real 0m3.335s user 0m1.603s sys 0m1.612s $ time sh -c 'for i in {1..100}; do ./exec test; done' real 0m1.547s user 0m0.597s sys 0m0.867s So this means for every 100 executions, using bash has about 3.3s of overhead, and this tool cuts out over half of that. Probably for longer command strings, the overhead is significantly greater. But that should be clear soon enough...
This commit is contained in:
parent
43895d3147
commit
a5f58aba57
132
src/tools/exec.c
Normal file
132
src/tools/exec.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2019, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Augustin Cavalier <waddlesplash>
|
||||
*/
|
||||
|
||||
/* Pass this tool a string, and it will parse it into an argv and execvp(). */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static void
|
||||
append_char(char c, char** arg, int* argLen, int* argBufferLen)
|
||||
{
|
||||
if ((*argLen + 1) >= *argBufferLen) {
|
||||
*arg = realloc(*arg, *argBufferLen + 32);
|
||||
if (*arg == NULL) {
|
||||
puts("oom");
|
||||
exit(1);
|
||||
}
|
||||
*argBufferLen += 32;
|
||||
}
|
||||
|
||||
(*arg)[*argLen] = c;
|
||||
(*argLen)++;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parse_quoted(const char* str, int* pos, char** currentArg, int* currentArgLen,
|
||||
int* currentArgBufferLen)
|
||||
{
|
||||
char end = str[*pos];
|
||||
while (1) {
|
||||
char c;
|
||||
(*pos)++;
|
||||
c = str[*pos];
|
||||
if (c == '\0') {
|
||||
puts("mismatched quotes");
|
||||
exit(1);
|
||||
}
|
||||
if (c == end)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case '\\':
|
||||
(*pos)++;
|
||||
// fall through
|
||||
default:
|
||||
append_char(str[*pos], currentArg, currentArgLen,
|
||||
currentArgBufferLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char* argv[])
|
||||
{
|
||||
char** args = NULL, *currentArg = NULL;
|
||||
const char* str;
|
||||
int argsLen = 0, argsBufferLen = 0, currentArgLen = 0,
|
||||
currentArgBufferLen = 0, pos;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("usage: %s \"program arg 'arg1' ...\"\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
str = argv[1];
|
||||
pos = 0;
|
||||
while (1) {
|
||||
switch (str[pos]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\0':
|
||||
if (currentArgLen == 0)
|
||||
break; // do nothing
|
||||
|
||||
append_char('\0', ¤tArg, ¤tArgLen,
|
||||
¤tArgBufferLen);
|
||||
|
||||
if ((argsLen + 2) >= argsBufferLen) {
|
||||
args = realloc(args, (argsBufferLen + 8) * sizeof(char*));
|
||||
if (args == NULL) {
|
||||
puts("oom");
|
||||
return 1;
|
||||
}
|
||||
argsBufferLen += 8;
|
||||
}
|
||||
|
||||
args[argsLen] = currentArg;
|
||||
args[argsLen + 1] = NULL;
|
||||
argsLen++;
|
||||
|
||||
currentArg = NULL;
|
||||
currentArgLen = 0;
|
||||
currentArgBufferLen = 0;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
parse_quoted(str, &pos, ¤tArg, ¤tArgLen,
|
||||
¤tArgBufferLen);
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
pos++;
|
||||
// fall through
|
||||
default:
|
||||
append_char(str[pos], ¤tArg, ¤tArgLen,
|
||||
¤tArgBufferLen);
|
||||
break;
|
||||
}
|
||||
if (str[pos] == '\0')
|
||||
break;
|
||||
pos++;
|
||||
}
|
||||
|
||||
pos = execvp(args[0], args);
|
||||
if (pos != 0)
|
||||
printf("exec failed: %s\n", strerror(errno));
|
||||
return pos;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user