Add functionality for running external programs to the std lib
See lib/run_program.rs.
This commit is contained in:
parent
441697ab35
commit
ea5dc54c3f
10 changed files with 280 additions and 9 deletions
|
@ -255,6 +255,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
|
||||||
rt/sync/lock_and_signal.cpp \
|
rt/sync/lock_and_signal.cpp \
|
||||||
rt/rust.cpp \
|
rt/rust.cpp \
|
||||||
rt/rust_builtin.cpp \
|
rt/rust_builtin.cpp \
|
||||||
|
rt/rust_run_program.cpp \
|
||||||
rt/rust_crate.cpp \
|
rt/rust_crate.cpp \
|
||||||
rt/rust_crate_cache.cpp \
|
rt/rust_crate_cache.cpp \
|
||||||
rt/rust_crate_reader.cpp \
|
rt/rust_crate_reader.cpp \
|
||||||
|
|
|
@ -17,6 +17,8 @@ type reader =
|
||||||
impure fn read_bytes(uint len) -> vec[u8];
|
impure fn read_bytes(uint len) -> vec[u8];
|
||||||
impure fn read_char() -> int;
|
impure fn read_char() -> int;
|
||||||
impure fn unread_char(int i);
|
impure fn unread_char(int i);
|
||||||
|
impure fn eof() -> bool;
|
||||||
|
impure fn read_line() -> str;
|
||||||
impure fn read_c_str() -> str;
|
impure fn read_c_str() -> str;
|
||||||
impure fn read_le_uint(uint size) -> uint;
|
impure fn read_le_uint(uint size) -> uint;
|
||||||
impure fn read_le_int(uint size) -> int;
|
impure fn read_le_int(uint size) -> int;
|
||||||
|
@ -31,7 +33,7 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
|
||||||
impure fn read_bytes(uint len) -> vec[u8] {
|
impure fn read_bytes(uint len) -> vec[u8] {
|
||||||
auto buf = _vec.alloc[u8](len);
|
auto buf = _vec.alloc[u8](len);
|
||||||
auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f);
|
auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f);
|
||||||
check(read == len);
|
_vec.len_set[u8](buf, read);
|
||||||
ret buf;
|
ret buf;
|
||||||
}
|
}
|
||||||
impure fn read_char() -> int {
|
impure fn read_char() -> int {
|
||||||
|
@ -40,6 +42,21 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
|
||||||
impure fn unread_char(int ch) {
|
impure fn unread_char(int ch) {
|
||||||
os.libc.ungetc(ch, f);
|
os.libc.ungetc(ch, f);
|
||||||
}
|
}
|
||||||
|
impure fn eof() -> bool {
|
||||||
|
auto ch = os.libc.fgetc(f);
|
||||||
|
if (ch == -1) {ret true;}
|
||||||
|
os.libc.ungetc(ch, f);
|
||||||
|
ret false;
|
||||||
|
}
|
||||||
|
impure fn read_line() -> str {
|
||||||
|
auto buf = "";
|
||||||
|
while (true) {
|
||||||
|
auto ch = os.libc.fgetc(f);
|
||||||
|
if (ch == -1) {break;} if (ch == 10) {break;}
|
||||||
|
buf += _str.unsafe_from_bytes(vec(ch as u8));
|
||||||
|
}
|
||||||
|
ret buf;
|
||||||
|
}
|
||||||
impure fn read_c_str() -> str {
|
impure fn read_c_str() -> str {
|
||||||
auto buf = "";
|
auto buf = "";
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import _str.sbuf;
|
import _str.sbuf;
|
||||||
import _vec.vbuf;
|
import _vec.vbuf;
|
||||||
|
|
||||||
|
// FIXE Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
|
||||||
|
// by https://github.com/graydon/rust/issues#issue/268
|
||||||
|
|
||||||
native mod libc = "libc.so.6" {
|
native mod libc = "libc.so.6" {
|
||||||
|
|
||||||
fn open(sbuf s, int flags, uint mode) -> int;
|
fn open(sbuf s, int flags, uint mode) -> int;
|
||||||
|
@ -10,6 +13,7 @@ native mod libc = "libc.so.6" {
|
||||||
|
|
||||||
type FILE;
|
type FILE;
|
||||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||||
|
fn fdopen(int fd, sbuf mode) -> FILE;
|
||||||
fn fclose(FILE f);
|
fn fclose(FILE f);
|
||||||
fn fgetc(FILE f) -> int;
|
fn fgetc(FILE f) -> int;
|
||||||
fn ungetc(int c, FILE f);
|
fn ungetc(int c, FILE f);
|
||||||
|
@ -25,6 +29,9 @@ native mod libc = "libc.so.6" {
|
||||||
fn getenv(sbuf n) -> sbuf;
|
fn getenv(sbuf n) -> sbuf;
|
||||||
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
||||||
fn unsetenv(sbuf n) -> int;
|
fn unsetenv(sbuf n) -> int;
|
||||||
|
|
||||||
|
fn pipe(vbuf buf) -> int;
|
||||||
|
fn waitpid(int pid, vbuf status, int options) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod libc_constants {
|
mod libc_constants {
|
||||||
|
@ -50,6 +57,22 @@ fn target_os() -> str {
|
||||||
ret "linux";
|
ret "linux";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pipe() -> tup(int, int) {
|
||||||
|
let vec[mutable int] fds = vec(mutable 0, 0);
|
||||||
|
check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
|
||||||
|
ret tup(fds.(0), fds.(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fd_FILE(int fd) -> libc.FILE {
|
||||||
|
ret libc.fdopen(fd, _str.buf("r"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn waitpid(int pid) -> int {
|
||||||
|
let vec[mutable int] status = vec(mutable 0);
|
||||||
|
check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
|
||||||
|
ret status.(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust;
|
// mode: rust;
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
|
@ -9,6 +9,7 @@ native mod libc = "libc.dylib" {
|
||||||
|
|
||||||
type FILE;
|
type FILE;
|
||||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||||
|
fn fdopen(int fd, sbuf mode) -> FILE;
|
||||||
fn fclose(FILE f);
|
fn fclose(FILE f);
|
||||||
fn fgetc(FILE f) -> int;
|
fn fgetc(FILE f) -> int;
|
||||||
fn ungetc(int c, FILE f);
|
fn ungetc(int c, FILE f);
|
||||||
|
@ -24,6 +25,9 @@ native mod libc = "libc.dylib" {
|
||||||
fn getenv(sbuf n) -> sbuf;
|
fn getenv(sbuf n) -> sbuf;
|
||||||
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
|
||||||
fn unsetenv(sbuf n) -> int;
|
fn unsetenv(sbuf n) -> int;
|
||||||
|
|
||||||
|
fn pipe(vbuf buf) -> int;
|
||||||
|
fn waitpid(int pid, vbuf status, int options) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod libc_constants {
|
mod libc_constants {
|
||||||
|
@ -49,6 +53,22 @@ fn target_os() -> str {
|
||||||
ret "macos";
|
ret "macos";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pipe() -> tup(int, int) {
|
||||||
|
let vec[mutable int] fds = vec(mutable 0, 0);
|
||||||
|
check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
|
||||||
|
ret tup(fds.(0), fds.(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fd_FILE(int fd) -> libc.FILE {
|
||||||
|
ret libc.fdopen(fd, _str.buf("r"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn waitpid(int pid) -> int {
|
||||||
|
let vec[mutable int] status = vec(mutable 0);
|
||||||
|
check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
|
||||||
|
ret status.(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust;
|
// mode: rust;
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
96
src/lib/run_program.rs
Normal file
96
src/lib/run_program.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import _str.sbuf;
|
||||||
|
import _vec.vbuf;
|
||||||
|
|
||||||
|
native "rust" mod rustrt {
|
||||||
|
fn rust_run_program(vbuf argv, int in_fd, int out_fd, int err_fd) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argvec(str prog, vec[str] args) -> vec[sbuf] {
|
||||||
|
auto argptrs = vec(_str.buf(prog));
|
||||||
|
for (str arg in args) {
|
||||||
|
argptrs = _vec.push[sbuf](argptrs, _str.buf(arg));
|
||||||
|
}
|
||||||
|
argptrs = _vec.push[sbuf](argptrs, 0 as sbuf);
|
||||||
|
ret argptrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
impure fn run_program(str prog, vec[str] args) -> int {
|
||||||
|
auto pid = rustrt.rust_run_program(_vec.buf[sbuf](argvec(prog, args)),
|
||||||
|
0, 0, 0);
|
||||||
|
ret os.waitpid(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
type program =
|
||||||
|
state obj {
|
||||||
|
fn get_id() -> int;
|
||||||
|
fn input() -> io.writer;
|
||||||
|
fn output() -> io.reader;
|
||||||
|
impure fn close_input();
|
||||||
|
impure fn finish() -> int;
|
||||||
|
};
|
||||||
|
|
||||||
|
impure fn start_program(str prog, vec[str] args) -> @program {
|
||||||
|
auto pipe_input = os.pipe();
|
||||||
|
auto pipe_output = os.pipe();
|
||||||
|
auto pid = rustrt.rust_run_program
|
||||||
|
(_vec.buf[sbuf](argvec(prog, args)),
|
||||||
|
pipe_input._0, pipe_output._1, 0);
|
||||||
|
if (pid == -1) {fail;}
|
||||||
|
os.libc.close(pipe_input._0);
|
||||||
|
os.libc.close(pipe_output._1);
|
||||||
|
|
||||||
|
state obj new_program(int pid,
|
||||||
|
int in_fd,
|
||||||
|
os.libc.FILE out_file,
|
||||||
|
mutable bool finished) {
|
||||||
|
fn get_id() -> int {ret pid;}
|
||||||
|
fn input() -> io.writer {
|
||||||
|
ret io.new_writer(io.fd_buf_writer(in_fd, false));
|
||||||
|
}
|
||||||
|
fn output() -> io.reader {
|
||||||
|
ret io.FILE_reader(out_file, false);
|
||||||
|
}
|
||||||
|
impure fn close_input() {
|
||||||
|
os.libc.close(in_fd);
|
||||||
|
}
|
||||||
|
impure fn finish() -> int {
|
||||||
|
if (finished) {ret 0;}
|
||||||
|
finished = true;
|
||||||
|
os.libc.close(in_fd);
|
||||||
|
ret os.waitpid(pid);
|
||||||
|
}
|
||||||
|
drop {
|
||||||
|
if (!finished) {
|
||||||
|
os.libc.close(in_fd);
|
||||||
|
os.waitpid(pid);
|
||||||
|
}
|
||||||
|
os.libc.fclose(out_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret @new_program(pid, pipe_input._1,
|
||||||
|
os.fd_FILE(pipe_output._0),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
impure fn program_output(str prog, vec[str] args)
|
||||||
|
-> rec(int status, str out) {
|
||||||
|
auto pr = start_program(prog, args);
|
||||||
|
pr.close_input();
|
||||||
|
auto out = pr.output();
|
||||||
|
auto buf = "";
|
||||||
|
while (!out.eof()) {
|
||||||
|
auto bytes = out.read_bytes(4096u);
|
||||||
|
buf += _str.unsafe_from_bytes(bytes);
|
||||||
|
}
|
||||||
|
ret rec(status=pr.finish(), out=buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: rust
|
||||||
|
// fill-column: 78;
|
||||||
|
// indent-tabs-mode: nil
|
||||||
|
// c-basic-offset: 4
|
||||||
|
// buffer-file-coding-system: utf-8-unix
|
||||||
|
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||||
|
// End:
|
|
@ -27,7 +27,9 @@ mod util;
|
||||||
|
|
||||||
auth io = unsafe;
|
auth io = unsafe;
|
||||||
auth fs = unsafe;
|
auth fs = unsafe;
|
||||||
|
auth os = unsafe;
|
||||||
auth os_fs = unsafe;
|
auth os_fs = unsafe;
|
||||||
|
auth run = unsafe;
|
||||||
auth _str = unsafe;
|
auth _str = unsafe;
|
||||||
auth _vec = unsafe;
|
auth _vec = unsafe;
|
||||||
auth _task = unsafe;
|
auth _task = unsafe;
|
||||||
|
@ -52,9 +54,9 @@ alt (target_os) {
|
||||||
mod os_fs = "posix_fs.rs";
|
mod os_fs = "posix_fs.rs";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mod run = "run_program.rs";
|
||||||
mod fs;
|
mod fs;
|
||||||
|
|
||||||
|
|
||||||
// FIXME: parametric
|
// FIXME: parametric
|
||||||
mod map;
|
mod map;
|
||||||
mod deque;
|
mod deque;
|
||||||
|
|
|
@ -9,11 +9,14 @@ native mod libc = "msvcrt.dll" {
|
||||||
|
|
||||||
type FILE;
|
type FILE;
|
||||||
fn fopen(sbuf path, sbuf mode) -> FILE;
|
fn fopen(sbuf path, sbuf mode) -> FILE;
|
||||||
|
fn _fdopen(int fd, sbuf mode) -> FILE;
|
||||||
fn fclose(FILE f);
|
fn fclose(FILE f);
|
||||||
fn fgetc(FILE f) -> int;
|
fn fgetc(FILE f) -> int;
|
||||||
fn ungetc(int c, FILE f);
|
fn ungetc(int c, FILE f);
|
||||||
fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
|
fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
|
||||||
fn fseek(FILE f, int offset, int whence) -> int;
|
fn fseek(FILE f, int offset, int whence) -> int;
|
||||||
|
|
||||||
|
fn _pipe(vbuf fds, uint size, int mode) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod libc_constants {
|
mod libc_constants {
|
||||||
|
@ -39,6 +42,25 @@ fn target_os() -> str {
|
||||||
ret "win32";
|
ret "win32";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pipe() -> tup(int, int) {
|
||||||
|
let vec[mutable int] fds = vec(mutable 0, 0);
|
||||||
|
check(os.libc._pipe(_vec.buf[mutable int](fds), 1024u,
|
||||||
|
libc_constants.O_BINARY()) == 0);
|
||||||
|
ret tup(fds.(0), fds.(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fd_FILE(int fd) -> libc.FILE {
|
||||||
|
ret libc._fdopen(fd, _str.buf("r"));
|
||||||
|
}
|
||||||
|
|
||||||
|
native "rust" mod rustrt {
|
||||||
|
fn rust_process_wait(int handle) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn waitpid(int pid) -> int {
|
||||||
|
ret rustrt.rust_process_wait(pid);
|
||||||
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust;
|
// mode: rust;
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "rust_internal.h"
|
#include "rust_internal.h"
|
||||||
|
|
||||||
/* Native builtins. */
|
/* Native builtins. */
|
||||||
|
|
|
@ -11,9 +11,12 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "rust.h"
|
#include "rust.h"
|
||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
@ -26,12 +29,10 @@ extern "C" {
|
||||||
}
|
}
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
#else
|
#else
|
||||||
#error "Platform not supported."
|
#error "Platform not supported."
|
||||||
#endif
|
#endif
|
||||||
|
|
92
src/rt/rust_run_program.cpp
Normal file
92
src/rt/rust_run_program.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#include "rust_internal.h"
|
||||||
|
|
||||||
|
#if defined(__WIN32__)
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
extern "C" CDECL int
|
||||||
|
rust_run_program(void* task, const char* argv[],
|
||||||
|
int in_fd, int out_fd, int err_fd) {
|
||||||
|
STARTUPINFO si;
|
||||||
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
||||||
|
si.cb = sizeof(STARTUPINFO);
|
||||||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
si.hStdInput = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
|
||||||
|
si.hStdOutput = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
|
||||||
|
si.hStdError = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
|
||||||
|
|
||||||
|
size_t cmd_len = 0;
|
||||||
|
for (const char** arg = argv; *arg; arg++) {
|
||||||
|
cmd_len += strlen(*arg);
|
||||||
|
cmd_len++; // Space or \0
|
||||||
|
}
|
||||||
|
char* cmd = (char*)malloc(cmd_len);
|
||||||
|
char* pos = cmd;
|
||||||
|
for (const char** arg = argv; *arg; arg++) {
|
||||||
|
strcpy(pos, *arg);
|
||||||
|
pos += strlen(*arg);
|
||||||
|
if (*(arg+1)) *(pos++) = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
|
||||||
|
0, NULL, NULL, &si, &pi);
|
||||||
|
free(cmd);
|
||||||
|
|
||||||
|
if (!created) return -1;
|
||||||
|
return (int)pi.hProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL int
|
||||||
|
rust_process_wait(void* task, int proc) {
|
||||||
|
DWORD status;
|
||||||
|
while (true) {
|
||||||
|
if (GetExitCodeProcess((HANDLE)proc, &status) &&
|
||||||
|
status != STILL_ACTIVE)
|
||||||
|
return (int)status;
|
||||||
|
WaitForSingleObject((HANDLE)proc, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
extern "C" CDECL int
|
||||||
|
rust_run_program(rust_task* task, char* argv[],
|
||||||
|
int in_fd, int out_fd, int err_fd) {
|
||||||
|
int pid = fork();
|
||||||
|
if (pid != 0) return pid;
|
||||||
|
|
||||||
|
sigset_t sset;
|
||||||
|
sigemptyset(&sset);
|
||||||
|
sigprocmask(SIG_SETMASK, &sset, NULL);
|
||||||
|
|
||||||
|
if (in_fd) dup2(in_fd, 0);
|
||||||
|
if (out_fd) dup2(out_fd, 1);
|
||||||
|
if (err_fd) dup2(err_fd, 2);
|
||||||
|
/* Close all other fds. */
|
||||||
|
for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd);
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Platform not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local Variables:
|
||||||
|
// mode: C++
|
||||||
|
// fill-column: 78;
|
||||||
|
// indent-tabs-mode: nil
|
||||||
|
// c-basic-offset: 4
|
||||||
|
// buffer-file-coding-system: utf-8-unix
|
||||||
|
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||||
|
// End:
|
||||||
|
//
|
Loading…
Reference in a new issue