1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-29 18:00:26 +00:00

Merge branch 'master' into ev

This commit is contained in:
Calvin Rose 2020-09-13 11:24:27 -05:00
commit 95f4bd8e23
5 changed files with 109 additions and 13 deletions

View File

@ -2,6 +2,8 @@
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Add :pipe option to `os/spawn`.
- Fix docstring typos.
## 1.12.1 - 2020-09-07
- Make `zero?`, `one?`, `pos?`, and `neg?` polymorphic.

View File

@ -799,6 +799,10 @@ FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
return iof->file;
}
JanetFile *janet_makejfile(FILE *f, int flags) {
return makef(f, flags);
}
Janet janet_makefile(FILE *f, int flags) {
return janet_wrap_abstract(makef(f, flags));
}

View File

@ -414,6 +414,36 @@ static Janet os_proc_kill(int32_t argc, Janet *argv) {
}
}
/* Create piped file for os/execute and os/spawn. */
static JanetFile *make_pipes(JanetHandle *handle, int reverse) {
JanetHandle handles[2];
#ifdef JANET_WINDOWS
if (!CreatePipe(handles, handles + 1, NULL, 0)) janet_panic("failed to create pipe");
if (reverse) {
JanetHandle temp = handles[0];
handles[0] = handles[1];
handles[1] = temp;
}
*handle = handles[1];
int fd = _open_osfhandle((intptr_t) handles[0], reverse ? _O_WRONLY : _O_RDONLY);
if (fd == -1) janet_panic("could not create file for piping");
FILE *f = _fdopen(fd, reverse ? "w" : "r");
if (NULL == f) janet_panic(strerror(errno));
return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ);
#else
if (pipe(handles)) janet_panic(strerror(errno));
if (reverse) {
JanetHandle temp = handles[0];
handles[0] = handles[1];
handles[1] = temp;
}
*handle = handles[1];
FILE *f = fdopen(handles[0], reverse ? "w" : "r");
if (NULL == f) janet_panic(strerror(errno));
return janet_makejfile(f, reverse ? JANET_FILE_WRITE : JANET_FILE_READ);
#endif
}
static const JanetMethod proc_methods[] = {
{"wait", os_proc_wait},
{"kill", os_proc_kill},
@ -470,6 +500,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
/* Optional stdio redirections */
JanetFile *new_in = NULL, *new_out = NULL, *new_err = NULL;
JanetHandle pipe_in = JANET_HANDLE_NONE, pipe_out = JANET_HANDLE_NONE, pipe_err = JANET_HANDLE_NONE;
/* Get optional redirections */
if (argc > 2) {
@ -477,9 +508,21 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
Janet maybe_stderr = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("err"));
if (!janet_checktype(maybe_stdin, JANET_NIL)) new_in = janet_getjfile(&maybe_stdin, 0);
if (!janet_checktype(maybe_stdout, JANET_NIL)) new_out = janet_getjfile(&maybe_stdout, 0);
if (!janet_checktype(maybe_stderr, JANET_NIL)) new_err = janet_getjfile(&maybe_stderr, 0);
if (janet_keyeq(maybe_stdin, "pipe")) {
new_in = make_pipes(&pipe_in, 1);
} else if (!janet_checktype(maybe_stdin, JANET_NIL)) {
new_in = janet_getjfile(&maybe_stdin, 0);
}
if (janet_keyeq(maybe_stdout, "pipe")) {
new_out = make_pipes(&pipe_out, 0);
} else if (!janet_checktype(maybe_stdout, JANET_NIL)) {
new_out = janet_getjfile(&maybe_stdout, 0);
}
if (janet_keyeq(maybe_stderr, "err")) {
new_err = make_pipes(&pipe_err, 0);
} else if (!janet_checktype(maybe_stderr, JANET_NIL)) {
new_err = janet_getjfile(&maybe_stderr, 0);
}
}
/* Result */
@ -502,9 +545,24 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
const char *path = (const char *) janet_unwrap_string(exargs.items[0]);
/* Do IO redirection */
startupInfo.hStdInput = (HANDLE) _get_osfhandle((new_in == NULL) ? 0 : _fileno(new_in->file));
startupInfo.hStdOutput = (HANDLE) _get_osfhandle((new_out == NULL) ? 1 : _fileno(new_out->file));
startupInfo.hStdError = (HANDLE) _get_osfhandle((new_err == NULL) ? 2 : _fileno(new_err->file));
if (pipe_in != JANET_HANDLE_NONE) {
startupInfo.hStdInput = pipe_in;
} else if (new_in != NULL) {
startupInfo.hStdInput = (HANDLE) _get_osfhandle(_fileno(new_in->file));
}
if (pipe_out != JANET_HANDLE_NONE) {
startupInfo.hStdInput = pipe_out;
} else if (new_out != NULL) {
startupInfo.hStdOutput = (HANDLE) _get_osfhandle(_fileno(new_out->file));
}
if (pipe_err != JANET_HANDLE_NONE) {
startupInfo.hStdInput = pipe_err;
} else if (new_err != NULL) {
startupInfo.hStdError = (HANDLE) _get_osfhandle(_fileno(new_err->file));
}
/* Use _spawn family of functions. */
/* Windows docs say do this before any spawns. */
@ -524,6 +582,10 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
janet_panic("failed to create process");
}
if (pipe_in != JANET_HANDLE_NONE) CloseHandle(pipe_in);
if (pipe_out != JANET_HANDLE_NONE) CloseHandle(pipe_out);
if (pipe_err != JANET_HANDLE_NONE) CloseHandle(pipe_err);
pHandle = processInfo.hProcess;
tHandle = processInfo.hThread;
@ -559,13 +621,19 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
/* Posix spawn setup */
posix_spawn_file_actions_t actions;
posix_spawn_file_actions_init(&actions);
if (new_in != NULL) {
if (pipe_in != JANET_HANDLE_NONE) {
posix_spawn_file_actions_adddup2(&actions, pipe_in, 0);
} else if (new_in != NULL) {
posix_spawn_file_actions_adddup2(&actions, fileno(new_in->file), 0);
}
if (new_out != NULL) {
if (pipe_out != JANET_HANDLE_NONE) {
posix_spawn_file_actions_adddup2(&actions, pipe_out, 1);
} else if (new_out != NULL) {
posix_spawn_file_actions_adddup2(&actions, fileno(new_out->file), 1);
}
if (new_err != NULL) {
if (pipe_err != JANET_HANDLE_NONE) {
posix_spawn_file_actions_adddup2(&actions, pipe_err, 2);
} else if (new_err != NULL) {
posix_spawn_file_actions_adddup2(&actions, fileno(new_err->file), 2);
}
@ -582,6 +650,10 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
posix_spawn_file_actions_destroy(&actions);
if (pipe_in != JANET_HANDLE_NONE) close(pipe_in);
if (pipe_out != JANET_HANDLE_NONE) close(pipe_out);
if (pipe_err != JANET_HANDLE_NONE) close(pipe_err);
if (use_environ) {
janet_unlock_environ();
}
@ -1554,6 +1626,11 @@ static const JanetReg os_cfuns[] = {
"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. "
"One can also pass in the :pipe keyword "
"for these arguments to create files that will read (for :err and :out) or write (for :in) "
"to the file descriptor of the subprocess. This is only useful in os/spawn, which takes "
"the same parameters as os/execute, but will return an object that contains references to these "
"files via (return-value :in), (return-value :out), and (return-value :err). "
"Returns the exit status of the program.")
},
{

View File

@ -724,15 +724,18 @@ static const JanetReg threadlib_cfuns[] = {
},
{
"thread/send", cfun_thread_send,
JDOC("(thread/send thread msg)\n\n"
"Send a message to the thread. This will never block and returns thread immediately. "
JDOC("(thread/send thread msgi &opt timeout)\n\n"
"Send a message to the thread. By default, the timeout is 1 second, but an optional timeout "
"in seconds can be provided. Use math/inf for no timeout. "
"Will throw an error if there is a problem sending the message.")
},
{
"thread/receive", cfun_thread_receive,
JDOC("(thread/receive &opt timeout)\n\n"
"Get a message sent to this thread. If timeout is provided, an error will be thrown after the timeout has elapsed but "
"no messages are received.")
"Get a message sent to this thread. If timeout (in seconds) is provided, an error "
"will be thrown after the timeout has elapsed but "
"no messages are received. The default timeout is 1 second, and math/inf cam be passed to "
"turn off the timeout.")
},
{
"thread/close", cfun_thread_close,

View File

@ -315,6 +315,15 @@ JANET_API extern const char *const janet_type_names[16];
JANET_API extern const char *const janet_signal_names[14];
JANET_API extern const char *const janet_status_names[16];
/* For various IO routines, we want to use an int on posix and HANDLE on windows */
#ifdef JANET_WINDOWS
typedef void *JanetHandle;
#define JANET_HANDLE_NONE NULL
#else
typedef int JanetHandle;
#define JANET_HANDLE_NONE (-1)
#endif
/* Fiber signals */
typedef enum {
JANET_SIGNAL_OK,
@ -1647,6 +1656,7 @@ extern JANET_API const JanetAbstractType janet_file_type;
#define JANET_FILE_NONIL 512
JANET_API Janet janet_makefile(FILE *f, int32_t flags);
JANET_API JanetFile *janet_makejfile(FILE *f, int32_t flags);
JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags);
JANET_API FILE *janet_dynfile(const char *name, FILE *def);
JANET_API JanetFile *janet_getjfile(const Janet *argv, int32_t n);