1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-01 04:19:55 +00:00

Make some improvements and add os/proc-kill as well.

This commit is contained in:
Calvin Rose 2020-09-01 21:36:49 -05:00
parent e7fca0051e
commit 7079cc43c9
2 changed files with 60 additions and 8 deletions

View File

@ -2,7 +2,11 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## Unreleased - ??? ## Unreleased - ???
- Add `os/proc-wait` and `os/proc-kill` for interacting with processes.
- Add `janet_getjfile` to C API. - Add `janet_getjfile` to C API.
- Allow redirection of stdin, stdout, and stderr by passing keywords in the env table.
- Add `:a` flag to `os/execute` to get a core/process back instead of an exit code.
When called like this, `os/execute` returns immediately.
- Add `:x` flag to os/execute to raise error when exit code is non-zero. - Add `:x` flag to os/execute to raise error when exit code is non-zero.
- Don't run `main` when flychecking. - Don't run `main` when flychecking.
- Add `:n` flag to `file/open` to raise an error if file cannot be opened. - Add `:n` flag to `file/open` to raise an error if file cannot be opened.

View File

@ -315,7 +315,10 @@ static JanetBuffer *os_exec_escape(JanetView args) {
/* Process type for when running a subprocess and not immediately waiting */ /* Process type for when running a subprocess and not immediately waiting */
static const JanetAbstractType ProcAT; static const JanetAbstractType ProcAT;
#define JANET_PROC_CLOSED 1
#define JANET_PROC_WAITED 2
typedef struct { typedef struct {
int flags;
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
HANDLE pid; HANDLE pid;
#else #else
@ -336,20 +339,54 @@ static int janet_proc_mark(void *p, size_t s) {
return 0; return 0;
} }
static Janet os_proc_wait(int32_t argc, Janet *argv) { static Janet os_proc_wait_impl(JanetProc *proc) {
janet_fixarity(argc, 1); if (proc->flags & JANET_PROC_WAITED) {
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT); janet_panicf("cannot wait on process that has already finished");
if (proc->return_code != -1) {
janet_panicf("can't wait on process that has already finished");
} }
proc->flags |= JANET_PROC_WAITED;
int status = 0; int status = 0;
#ifdef JANET_WINDOWS
WaitForSingleObject(proc->pid, INFINITE);
GetExitCodeProcess(proc->pid, &status);
#else
waitpid(proc->pid, &status, 0); waitpid(proc->pid, &status, 0);
#endif
proc->return_code = (int32_t) status; proc->return_code = (int32_t) status;
return janet_wrap_integer(proc->return_code); return janet_wrap_integer(proc->return_code);
} }
static Janet os_proc_wait(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
return os_proc_wait_impl(proc);
}
static Janet os_proc_kill(int32_t argc, Janet *argv) {
janet_arity(argc, 1, 2);
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
#ifdef JANET_WINDOWS
if (proc->flags & JANET_PROC_CLOSED) {
janet_panicf("cannot close process handle that is already closed");
}
proc->flags |= JANET_PROC_CLOSED;
int status = CloseHandle(proc->pid);
#else
int status = kill(proc->pid, SIGKILL);
#endif
if (status) {
janet_panic(strerror(errno));
}
/* After killing process we wait on it. */
if (argc > 1 && janet_truthy(argv[1])) {
return os_proc_wait_impl(proc);
} else {
return argv[0];
}
}
static const JanetMethod proc_methods[] = { static const JanetMethod proc_methods[] = {
{"wait", os_proc_wait}, {"wait", os_proc_wait},
{"kill", os_proc_kill},
{NULL, NULL} {NULL, NULL}
}; };
@ -538,6 +575,7 @@ static Janet os_execute(int32_t argc, Janet *argv) {
proc->in = new_in; proc->in = new_in;
proc->out = new_out; proc->out = new_out;
proc->err = new_err; proc->err = new_err;
proc->flags = 0;
return janet_wrap_abstract(proc); return janet_wrap_abstract(proc);
} else if (janet_flag_at(flags, 2) && status) { } else if (janet_flag_at(flags, 2) && status) {
janet_panicf("command failed with non-zero exit code %d", status); janet_panicf("command failed with non-zero exit code %d", status);
@ -1459,9 +1497,12 @@ static const JanetReg os_cfuns[] = {
"current environment is inherited.\n" "current environment is inherited.\n"
"\t:p - allows searching the current PATH for the binary to execute. " "\t:p - allows searching the current PATH for the binary to execute. "
"Without this flag, binaries must use absolute paths.\n" "Without this flag, binaries must use absolute paths.\n"
"\t:x - raise error if exit code is non-zero.\n\n" "\t:x - raise error if exit code is non-zero.\n"
"env is a table or struct mapping environment variables to values. " "\t:a - Runs the process asynchronously and returns a core/process.\n\n"
"Returns the exit status of the program.") "env is a table or struct mapping environment variables to values. It can also "
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
"These arguments should be core/file values. "
"Returns the exit status of the program, or a core/process object if the :a flag is given.")
}, },
{ {
"os/shell", os_shell, "os/shell", os_shell,
@ -1558,6 +1599,13 @@ static const JanetReg os_cfuns[] = {
JDOC("(os/proc-wait proc)\n\n" JDOC("(os/proc-wait proc)\n\n"
"Block until the subprocess completes. Returns the subprocess return code.") "Block until the subprocess completes. Returns the subprocess return code.")
}, },
{
"os/proc-kill", os_proc_kill,
JDOC("(os/proc-kill proc &opt wait)\n\n"
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
"handle on windows. If wait is truthy, will wait for the process to finsih and "
"returns the exit code. Otherwise, returns proc.")
},
#endif #endif
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };