This PR removes mutable fields from the serializer and makes the encoder and decoder use INHTWAMA properly (i.e. `&mut self`).
r? @graydon
pub type LPWSTR = *mut WCHAR;
pub type LPSTR = *mut CHAR;
+ pub type LPTSTR = *mut CHAR;
// Not really, but opaque to us.
pub type LPSECURITY_ATTRIBUTES = LPVOID;
pub type LPVOID = *mut c_void;
+ pub type LPBYTE = *mut BYTE;
pub type LPWORD = *mut WORD;
+ pub type LPDWORD = *mut DWORD;
+ pub type LPHANDLE = *mut HANDLE;
pub type LRESULT = LONG_PTR;
pub type PBOOL = *mut BOOL;
pub type time64_t = i64;
pub type int64 = i64;
+
+ pub struct STARTUPINFO {
+ cb: DWORD,
+ lpReserved: LPTSTR,
+ lpDesktop: LPTSTR,
+ lpTitle: LPTSTR,
+ dwX: DWORD,
+ dwY: DWORD,
+ dwXSize: DWORD,
+ dwYSize: DWORD,
+ dwXCountChars: DWORD,
+ dwYCountCharts: DWORD,
+ dwFillAttribute: DWORD,
+ dwFlags: DWORD,
+ wShowWindow: WORD,
+ cbReserved2: WORD,
+ lpReserved2: LPBYTE,
+ hStdInput: HANDLE,
+ hStdOutput: HANDLE,
+ hStdError: HANDLE
+ }
+ pub type LPSTARTUPINFO = *mut STARTUPINFO;
+
+ pub struct PROCESS_INFORMATION {
+ hProcess: HANDLE,
+ hThread: HANDLE,
+ dwProcessId: DWORD,
+ dwThreadId: DWORD
+ }
+ pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
}
}
}
pub mod bsd44 {
}
pub mod extra {
+ use libc::types::os::arch::extra::{DWORD, BOOL};
+
+ pub static TRUE : BOOL = 1;
+ pub static FALSE : BOOL = 0;
+
pub static O_TEXT : int = 16384;
pub static O_BINARY : int = 32768;
pub static O_NOINHERIT: int = 128;
pub static ERROR_SUCCESS : int = 0;
pub static ERROR_INSUFFICIENT_BUFFER : int = 122;
pub static INVALID_HANDLE_VALUE: int = -1;
+
+ pub static DELETE : DWORD = 0x00010000;
+ pub static READ_CONTROL : DWORD = 0x00020000;
+ pub static SYNCHRONIZE : DWORD = 0x00100000;
+ pub static WRITE_DAC : DWORD = 0x00040000;
+ pub static WRITE_OWNER : DWORD = 0x00080000;
+
+ pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080;
+ pub static PROCESS_CREATE_THREAD : DWORD = 0x0002;
+ pub static PROCESS_DUP_HANDLE : DWORD = 0x0040;
+ pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400;
+ pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000;
+ pub static PROCESS_SET_INFORMATION : DWORD = 0x0200;
+ pub static PROCESS_SET_QUOTA : DWORD = 0x0100;
+ pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800;
+ pub static PROCESS_TERMINATE : DWORD = 0x0001;
+ pub static PROCESS_VM_OPERATION : DWORD = 0x0008;
+ pub static PROCESS_VM_READ : DWORD = 0x0010;
+ pub static PROCESS_VM_WRITE : DWORD = 0x0020;
+
+ pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040;
+ pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080;
+ pub static STARTF_PREVENTPINNING : DWORD = 0x00002000;
+ pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020;
+ pub static STARTF_TITLEISAPPID : DWORD = 0x00001000;
+ pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800;
+ pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008;
+ pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010;
+ pub static STARTF_USEHOTKEY : DWORD = 0x00000200;
+ pub static STARTF_USEPOSITION : DWORD = 0x00000004;
+ pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001;
+ pub static STARTF_USESIZE : DWORD = 0x00000002;
+ pub static STARTF_USESTDHANDLES : DWORD = 0x00000100;
+
+ pub static WAIT_ABANDONED : DWORD = 0x00000080;
+ pub static WAIT_OBJECT_0 : DWORD = 0x00000000;
+ pub static WAIT_TIMEOUT : DWORD = 0x00000102;
+ pub static WAIT_FAILED : DWORD = -1;
+
+ pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
+ pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
+
+ pub static INFINITE : DWORD = -1;
+ pub static STILL_ACTIVE : DWORD = 259;
}
}
unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int,
sizep: *mut size_t) -> c_int;
+
+ unsafe fn getdtablesize() -> c_int;
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
+ pub mod bsd44 {
+ use libc::types::os::arch::c95::{c_int};
+
+ #[abi = "cdecl"]
+ pub extern {
+ unsafe fn getdtablesize() -> c_int;
+ }
+ }
+
+
#[cfg(target_os = "win32")]
pub mod bsd44 {
}
pub mod kernel32 {
use libc::types::os::arch::c95::{c_uint};
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
- use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
- use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
- use libc::types::os::arch::extra::{HANDLE};
+ use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR,
+ LPTSTR, LPTCH, LPDWORD, LPVOID};
+ use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO,
+ LPPROCESS_INFORMATION};
+ use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
#[abi = "stdcall"]
pub extern "stdcall" {
findFileData: HANDLE)
-> BOOL;
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
+ unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+ hSourceHandle: HANDLE,
+ hTargetProcessHandle: HANDLE,
+ lpTargetHandle: LPHANDLE,
+ dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwOptions: DWORD) -> BOOL;
unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
+ unsafe fn OpenProcess(dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwProcessId: DWORD) -> HANDLE;
+ unsafe fn GetCurrentProcess() -> HANDLE;
+ unsafe fn CreateProcessA(lpApplicationName: LPCTSTR,
+ lpCommandLine: LPTSTR,
+ lpProcessAttributes: LPSECURITY_ATTRIBUTES,
+ lpThreadAttributes: LPSECURITY_ATTRIBUTES,
+ bInheritHandles: BOOL,
+ dwCreationFlags: DWORD,
+ lpEnvironment: LPVOID,
+ lpCurrentDirectory: LPCTSTR,
+ lpStartupInfo: LPSTARTUPINFO,
+ lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL;
+ unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
+ unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
}
}
pub mod msvcrt {
- use libc::types::os::arch::c95::c_int;
+ use libc::types::os::arch::c95::{c_int, c_long};
#[abi = "cdecl"]
#[nolink]
pub extern {
#[link_name = "_commit"]
unsafe fn commit(fd: c_int) -> c_int;
+
+ #[link_name = "_get_osfhandle"]
+ unsafe fn get_osfhandle(fd: c_int) -> c_long;
}
}
}
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
- // first, as in rust_run_program.
+ // first, as in core::run.
let mut fds = Pipe {in: 0 as c_int,
out: 0 as c_int };
let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint,
use task;
use vec;
-pub mod rustrt {
- use libc::{c_int, c_void};
- use libc;
- use run;
-
- #[abi = "cdecl"]
- pub extern {
- unsafe fn rust_run_program(argv: **libc::c_char,
- envp: *c_void,
- dir: *libc::c_char,
- in_fd: c_int,
- out_fd: c_int,
- err_fd: c_int) -> run::RunProgramResult;
- unsafe fn rust_process_wait(pid: c_int) -> c_int;
- }
-}
-
-pub struct RunProgramResult {
- // the process id of the program, or -1 if in case of errors
- pid: pid_t,
- // a handle to the process - on unix this will always be NULL, but on windows it will be a
- // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
- handle: *(),
-}
-
/// A value representing a child process
pub struct Program {
priv pid: pid_t,
return res.pid;
}
+struct RunProgramResult {
+ // the process id of the program (this should never be negative)
+ pid: pid_t,
+ // a handle to the process - on unix this will always be NULL, but on windows it will be a
+ // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
+ handle: *(),
+}
+
+#[cfg(windows)]
+fn spawn_process_internal(prog: &str, args: &[~str],
+ env: &Option<~[(~str,~str)]>,
+ dir: &Option<~str>,
+ in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
+
+ use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
+ use libc::consts::os::extra::{
+ TRUE, FALSE,
+ STARTF_USESTDHANDLES,
+ INVALID_HANDLE_VALUE,
+ DUPLICATE_SAME_ACCESS
+ };
+ use libc::funcs::extra::kernel32::{
+ GetCurrentProcess,
+ DuplicateHandle,
+ CloseHandle,
+ CreateProcessA
+ };
+ use libc::funcs::extra::msvcrt::get_osfhandle;
+
+ unsafe {
+
+ let mut si = zeroed_startupinfo();
+ si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ let cur_proc = GetCurrentProcess();
+
+ let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE;
+ if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE;
+ if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE;
+ if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let cmd = make_command_line(prog, args);
+ let mut pi = zeroed_process_information();
+ let mut create_err = None;
+
+ do with_envp(env) |envp| {
+ do with_dirp(dir) |dirp| {
+ do str::as_c_str(cmd) |cmdp| {
+ let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
+ ptr::mut_null(), ptr::mut_null(), TRUE,
+ 0, envp, dirp, &mut si, &mut pi);
+ if created == FALSE {
+ create_err = Some(os::last_os_error());
+ }
+ }
+ }
+ }
+
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ for create_err.each |msg| {
+ fail!(fmt!("failure in CreateProcess: %s", *msg));
+ }
+
+ // We close the thread handle because we don't care about keeping the thread id valid,
+ // and we aren't keeping the thread handle around to be able to close it later. We don't
+ // close the process handle however because we want the process id to stay valid at least
+ // until the calling code closes the process handle.
+ CloseHandle(pi.hThread);
+
+ RunProgramResult {
+ pid: pi.dwProcessId as pid_t,
+ handle: pi.hProcess as *()
+ }
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
+ libc::types::os::arch::extra::STARTUPINFO {
+ cb: 0,
+ lpReserved: ptr::mut_null(),
+ lpDesktop: ptr::mut_null(),
+ lpTitle: ptr::mut_null(),
+ dwX: 0,
+ dwY: 0,
+ dwXSize: 0,
+ dwYSize: 0,
+ dwXCountChars: 0,
+ dwYCountCharts: 0,
+ dwFillAttribute: 0,
+ dwFlags: 0,
+ wShowWindow: 0,
+ cbReserved2: 0,
+ lpReserved2: ptr::mut_null(),
+ hStdInput: ptr::mut_null(),
+ hStdOutput: ptr::mut_null(),
+ hStdError: ptr::mut_null()
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
+ libc::types::os::arch::extra::PROCESS_INFORMATION {
+ hProcess: ptr::mut_null(),
+ hThread: ptr::mut_null(),
+ dwProcessId: 0,
+ dwThreadId: 0
+ }
+}
+
+// FIXME: this is only pub so it can be tested (see issue #4536)
+#[cfg(windows)]
+pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
+
+ let mut cmd = ~"";
+ append_arg(&mut cmd, prog);
+ for args.each |arg| {
+ cmd.push_char(' ');
+ append_arg(&mut cmd, *arg);
+ }
+ return cmd;
+
+ fn append_arg(cmd: &mut ~str, arg: &str) {
+ let quote = arg.any(|c| c == ' ' || c == '\t');
+ if quote {
+ cmd.push_char('"');
+ }
+ for uint::range(0, arg.len()) |i| {
+ append_char_at(cmd, arg, i);
+ }
+ if quote {
+ cmd.push_char('"');
+ }
+ }
+
+ fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
+ match arg[i] as char {
+ '"' => {
+ // Escape quotes.
+ cmd.push_str("\\\"");
+ }
+ '\\' => {
+ if backslash_run_ends_in_quote(arg, i) {
+ // Double all backslashes that are in runs before quotes.
+ cmd.push_str("\\\\");
+ } else {
+ // Pass other backslashes through unescaped.
+ cmd.push_char('\\');
+ }
+ }
+ c => {
+ cmd.push_char(c);
+ }
+ }
+ }
+
+ fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
+ while i < s.len() && s[i] as char == '\\' {
+ i += 1;
+ }
+ return i < s.len() && s[i] as char == '"';
+ }
+}
+
+#[cfg(unix)]
fn spawn_process_internal(prog: &str, args: &[~str],
env: &Option<~[(~str,~str)]>,
dir: &Option<~str>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
+
+ use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
+ use libc::funcs::bsd44::getdtablesize;
+
+ mod rustrt {
+ use libc::c_void;
+
+ #[abi = "cdecl"]
+ pub extern {
+ unsafe fn rust_unset_sigprocmask();
+ unsafe fn rust_set_environ(envp: *c_void);
+ }
+ }
+
unsafe {
- do with_argv(prog, args) |argv| {
- do with_envp(env) |envp| {
- do with_dirp(dir) |dirp| {
- rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd)
+
+ let pid = fork();
+ if pid < 0 {
+ fail!(fmt!("failure in fork: %s", os::last_os_error()));
+ } else if pid > 0 {
+ return RunProgramResult {pid: pid, handle: ptr::null()};
+ }
+
+ rustrt::rust_unset_sigprocmask();
+
+ if in_fd > 0 && dup2(in_fd, 0) == -1 {
+ fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error()));
+ }
+ if out_fd > 0 && dup2(out_fd, 1) == -1 {
+ fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error()));
+ }
+ if err_fd > 0 && dup2(err_fd, 2) == -1 {
+ fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error()));
+ }
+ // close all other fds
+ for int::range_rev(getdtablesize() as int - 1, 2) |fd| {
+ close(fd as c_int);
+ }
+
+ for dir.each |dir| {
+ do str::as_c_str(*dir) |dirp| {
+ if chdir(dirp) == -1 {
+ fail!(fmt!("failure in chdir: %s", os::last_os_error()));
}
}
}
+
+ do with_envp(env) |envp| {
+ if !envp.is_null() {
+ rustrt::rust_set_environ(envp);
+ }
+ do with_argv(prog, args) |argv| {
+ execvp(*argv, argv);
+ // execvp only returns if an error occurred
+ fail!(fmt!("failure in execvp: %s", os::last_os_error()));
+ }
+ }
}
}
+#[cfg(unix)]
fn with_argv<T>(prog: &str, args: &[~str],
cb: &fn(**libc::c_char) -> T) -> T {
let mut argptrs = str::as_c_str(prog, |b| ~[b]);
#[cfg(windows)]
fn with_envp<T>(env: &Option<~[(~str,~str)]>,
- cb: &fn(*c_void) -> T) -> T {
+ cb: &fn(*mut c_void) -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
blk += ~[0_u8];
vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p)))
}
- _ => cb(ptr::null())
+ _ => cb(ptr::mut_null())
}
}
}
+#[cfg(windows)]
fn with_dirp<T>(d: &Option<~str>,
cb: &fn(*libc::c_char) -> T) -> T {
match *d {
pub fn run_program(prog: &str, args: &[~str]) -> int {
let res = spawn_process_internal(prog, args, &None, &None,
0i32, 0i32, 0i32);
- if res.pid == -1 as pid_t { fail!(); }
-
let code = waitpid(res.pid);
free_handle(res.handle);
return code;
pipe_err.out);
unsafe {
- if res.pid == -1 as pid_t { fail!(); }
libc::close(pipe_input.in);
libc::close(pipe_output.out);
libc::close(pipe_err.out);
os::close(pipe_in.in);
os::close(pipe_out.out);
os::close(pipe_err.out);
- if res.pid == -1i32 {
- os::close(pipe_in.out);
- os::close(pipe_out.in);
- os::close(pipe_err.in);
- fail!();
- }
-
os::close(pipe_in.out);
// Spawn two entire schedulers to read both stdout and sterr
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
- let status = unsafe { rustrt::rust_process_wait(pid) };
- if status < 0 {
- fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error()));
+
+ use libc::types::os::arch::extra::DWORD;
+ use libc::consts::os::extra::{
+ SYNCHRONIZE,
+ PROCESS_QUERY_INFORMATION,
+ FALSE,
+ STILL_ACTIVE,
+ INFINITE,
+ WAIT_FAILED
+ };
+ use libc::funcs::extra::kernel32::{
+ OpenProcess,
+ GetExitCodeProcess,
+ CloseHandle,
+ WaitForSingleObject
+ };
+
+ unsafe {
+
+ let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
+ if proc.is_null() {
+ fail!(fmt!("failure in OpenProcess: %s", os::last_os_error()));
+ }
+
+ loop {
+ let mut status = 0;
+ if GetExitCodeProcess(proc, &mut status) == FALSE {
+ CloseHandle(proc);
+ fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error()));
+ }
+ if status != STILL_ACTIVE {
+ CloseHandle(proc);
+ return status as int;
+ }
+ if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
+ CloseHandle(proc);
+ fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error()));
+ }
+ }
}
- return status as int;
}
#[cfg(unix)]
use libc;
use option::None;
use os;
- use path::Path;
use run::{readclose, writeclose};
use run;
+ #[test]
+ #[cfg(windows)]
+ fn test_make_command_line() {
+ assert_eq!(
+ run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
+ ~"prog aaa bbb ccc"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
+ ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
+ ~"\"C:\\Program Files\\test\" aa\\\"bb"
+ );
+ assert_eq!(
+ run::make_command_line("echo", [~"a b c"]),
+ ~"echo \"a b c\""
+ );
+ }
+
// Regression test for memory leaks
#[test]
fn test_leaks() {
p.destroy(); // ...and nor should this (and nor should the destructor)
}
- #[cfg(unix)] // there is no way to sleep on windows from inside libcore...
fn test_destroy_actually_kills(force: bool) {
- let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force));
- os::remove_file(&path);
+ #[cfg(unix)]
+ static BLOCK_COMMAND: &'static str = "cat";
- let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str());
- let mut p = run::start_program("sh", [~"-c", cmd]);
+ #[cfg(windows)]
+ static BLOCK_COMMAND: &'static str = "cmd";
- p.destroy(); // destroy the program before it has a chance to echo its message
+ #[cfg(unix)]
+ fn process_exists(pid: libc::pid_t) -> bool {
+ run::program_output("ps", [~"-p", pid.to_str()]).out.contains(pid.to_str())
+ }
- unsafe {
- // wait to ensure the program is really destroyed and not just waiting itself
- libc::sleep(10);
+ #[cfg(windows)]
+ fn process_exists(pid: libc::pid_t) -> bool {
+
+ use libc::types::os::arch::extra::DWORD;
+ use libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess};
+ use libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE };
+
+ unsafe {
+ let proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
+ if proc.is_null() {
+ return false;
+ }
+ // proc will be non-null if the process is alive, or if it died recently
+ let mut status = 0;
+ GetExitCodeProcess(proc, &mut status);
+ CloseHandle(proc);
+ return status == STILL_ACTIVE;
+ }
+ }
+
+ // this program will stay alive indefinitely trying to read from stdin
+ let mut p = run::start_program(BLOCK_COMMAND, []);
+
+ assert!(process_exists(p.get_id()));
+
+ if force {
+ p.force_destroy();
+ } else {
+ p.destroy();
}
- // the program should not have had chance to echo its message
- assert!(!path.exists());
+ assert!(!process_exists(p.get_id()));
}
#[test]
- #[cfg(unix)]
fn test_unforced_destroy_actually_kills() {
test_destroy_actually_kills(false);
}
#[test]
- #[cfg(unix)]
fn test_forced_destroy_actually_kills() {
test_destroy_actually_kills(true);
}
pub static fn_field_code: uint = 0u;
pub static fn_field_box: uint = 1u;
+// The three fields of a trait object/trait instance: vtable, box, and type
+// description.
+pub static trt_field_vtable: uint = 0u;
+pub static trt_field_box: uint = 1u;
+// This field is only present in unique trait objects, so it comes last.
+pub static trt_field_tydesc: uint = 2u;
+
pub static vec_elt_fill: uint = 0u;
pub static vec_elt_alloc: uint = 1u;
let linker_args = getopts::opt_strs(matches, ~"link-args").flat_map( |a| {
let mut args = ~[];
- for str::each_split_char(*a, ',') |arg| {
+ for str::each_split_char(*a, ' ') |arg| {
args.push(str::from_slice(arg));
}
args
optmulti("L", "", "Add a directory to the library search path",
"PATH"),
optflag("", "lib", "Compile a library crate"),
- optmulti("", "link-args", "FLAGS is a comma-separated list of flags
+ optmulti("", "link-args", "FLAGS is a space-separated list of flags
passed to the linker", "FLAGS"),
optflag("", "ls", "List the symbols defined by a library crate"),
optflag("", "no-trans",
closure::make_closure_glue(bcx, v0, t, drop_ty)
}
ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
- let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u]));
+ let llbox = Load(bcx, GEPi(bcx, v0, [0u, abi::trt_field_box]));
decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx))
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
- let lluniquevalue = GEPi(bcx, v0, [0, 1]);
- let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2]));
+ let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
+ let lltydesc = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_tydesc]));
call_tydesc_glue_full(bcx, lluniquevalue, lltydesc,
abi::tydesc_field_free_glue, None);
bcx
closure::make_closure_glue(bcx, v, t, take_ty)
}
ty::ty_trait(_, _, ty::BoxTraitStore, _) => {
- let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u]));
+ let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
incr_refcnt_of_boxed(bcx, llbox);
bcx
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
- let llval = GEPi(bcx, v, [0, 1]);
- let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2]));
+ let llval = GEPi(bcx, v, [0, abi::trt_field_box]);
+ let lltydesc = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_tydesc]));
call_tydesc_glue_full(bcx, llval, lltydesc,
abi::tydesc_field_take_glue, None);
bcx
val_str(bcx.ccx().tn, llpair));
let llvtable = Load(bcx,
PointerCast(bcx,
- GEPi(bcx, llpair, [0u, 0u]),
+ GEPi(bcx, llpair,
+ [0u, abi::trt_field_vtable]),
T_ptr(T_ptr(T_vtable()))));
// Load the box from the @Trait pair and GEP over the box header if
// necessary:
let mut llself;
debug!("(translating trait callee) loading second index from pair");
- let llbox = Load(bcx, GEPi(bcx, llpair, [0u, 1u]));
+ let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box]));
// Munge `llself` appropriately for the type of `self` in the method.
let self_mode;
match store {
ty::RegionTraitStore(_) | ty::BoxTraitStore => {
- let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]);
- // Just store the pointer into the pair.
+ let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
+ // Just store the pointer into the pair. (Region/borrowed
+ // and boxed trait objects are represented as pairs, and
+ // have no type descriptor field.)
llboxdest = PointerCast(bcx,
llboxdest,
T_ptr(type_of(bcx.ccx(), v_ty)));
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
}
ty::UniqTraitStore => {
- // Translate the uniquely-owned value into the second element of
- // the triple. (The first element is the vtable.)
- let mut llvaldest = GEPi(bcx, lldest, [0, 1]);
+ // Translate the uniquely-owned value in the
+ // triple. (Unique trait objects are represented as
+ // triples.)
+ let mut llvaldest = GEPi(bcx, lldest, [0, abi::trt_field_box]);
llvaldest = PointerCast(bcx,
llvaldest,
T_ptr(type_of(bcx.ccx(), v_ty)));
bcx = expr::trans_into(bcx, val, SaveIn(llvaldest));
- // Get the type descriptor of the wrapped value and store it into
- // the third element of the triple as well.
+ // Get the type descriptor of the wrapped value and store
+ // it in the triple as well.
let tydesc = get_tydesc(bcx.ccx(), v_ty);
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc);
- let lltydescdest = GEPi(bcx, lldest, [0, 2]);
+ let lltydescdest = GEPi(bcx, lldest, [0, abi::trt_field_tydesc]);
Store(bcx, tydesc.tydesc, lltydescdest);
}
}
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
let vtable = get_vtable(bcx.ccx(), orig);
Store(bcx, vtable, PointerCast(bcx,
- GEPi(bcx, lldest, [0u, 0u]),
+ GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
T_ptr(val_ty(vtable))));
bcx
#include <crt_externs.h>
#endif
-struct RunProgramResult {
- pid_t pid;
- void* handle;
-};
-
#if defined(__WIN32__)
-#include <process.h>
-#include <io.h>
-
-bool backslash_run_ends_in_quote(char const *c) {
- while (*c == '\\') ++c;
- return *c == '"';
-}
-
-void append_first_char(char *&buf, char const *c) {
- switch (*c) {
-
- case '"':
- // Escape quotes.
- *buf++ = '\\';
- *buf++ = '"';
- break;
-
-
- case '\\':
- if (backslash_run_ends_in_quote(c)) {
- // Double all backslashes that are in runs before quotes.
- *buf++ = '\\';
- *buf++ = '\\';
- } else {
- // Pass other backslashes through unescaped.
- *buf++ = '\\';
- }
- break;
-
- default:
- *buf++ = *c;
- }
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // empty stub for windows to keep linker happy
}
-bool contains_whitespace(char const *arg) {
- while (*arg) {
- switch (*arg++) {
- case ' ':
- case '\t':
- return true;
- }
- }
- return false;
-}
-
-void append_arg(char *& buf, char const *arg, bool last) {
- bool quote = contains_whitespace(arg);
- if (quote)
- *buf++ = '"';
- while (*arg)
- append_first_char(buf, arg++);
- if (quote)
- *buf++ = '"';
-
- if (! last) {
- *buf++ = ' ';
- } else {
- *buf++ = '\0';
- }
-}
-
-extern "C" CDECL RunProgramResult
-rust_run_program(const char* argv[],
- void* envp,
- const char* dir,
- int in_fd, int out_fd, int err_fd) {
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESTDHANDLES;
-
- RunProgramResult result = {-1, NULL};
-
- HANDLE curproc = GetCurrentProcess();
- HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
- if (!DuplicateHandle(curproc, origStdin,
- curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
- HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
- if (!DuplicateHandle(curproc, origStdout,
- curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
- HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
- if (!DuplicateHandle(curproc, origStderr,
- curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
-
- size_t cmd_len = 0;
- for (const char** arg = argv; *arg; arg++) {
- cmd_len += strlen(*arg);
- cmd_len += 3; // Two quotes plus trailing space or \0
- }
- cmd_len *= 2; // Potentially backslash-escape everything.
-
- char* cmd = (char*)malloc(cmd_len);
- char* pos = cmd;
- for (const char** arg = argv; *arg; arg++) {
- append_arg(pos, *arg, *(arg+1) == NULL);
- }
-
- PROCESS_INFORMATION pi;
- BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
- 0, envp, dir, &si, &pi);
-
- CloseHandle(si.hStdInput);
- CloseHandle(si.hStdOutput);
- CloseHandle(si.hStdError);
- free(cmd);
-
- if (!created) {
- return result;
- }
-
- // We close the thread handle because we don't care about keeping the thread id valid,
- // and we aren't keeping the thread handle around to be able to close it later. We don't
- // close the process handle however because we want the process id to stay valid at least
- // until the calling rust code closes the process handle.
- CloseHandle(pi.hThread);
- result.pid = pi.dwProcessId;
- result.handle = pi.hProcess;
- return result;
-}
-
-extern "C" CDECL int
-rust_process_wait(int pid) {
-
- HANDLE proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
- if (proc == NULL) {
- return -1;
- }
-
- DWORD status;
- while (true) {
- if (!GetExitCodeProcess(proc, &status)) {
- CloseHandle(proc);
- return -1;
- }
- if (status != STILL_ACTIVE) {
- CloseHandle(proc);
- return (int) status;
- }
- WaitForSingleObject(proc, INFINITE);
- }
+extern "C" CDECL void
+rust_set_environ(void* envp) {
+ // empty stub for windows to keep linker happy
}
#elif defined(__GNUC__)
-#include <sys/file.h>
#include <signal.h>
-#include <sys/ioctl.h>
#include <unistd.h>
-#include <termios.h>
#ifdef __FreeBSD__
extern char **environ;
#endif
-extern "C" CDECL RunProgramResult
-rust_run_program(const char* argv[],
- void* envp,
- const char* dir,
- int in_fd, int out_fd, int err_fd) {
- int pid = fork();
- if (pid != 0) {
- RunProgramResult result = {pid, NULL};
- return result;
- }
-
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // this can't be safely converted to rust code because the
+ // representation of sigset_t is platform-dependent
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);
- if (dir) {
- int result = chdir(dir);
- // FIXME (#2674): need error handling
- assert(!result && "chdir failed");
- }
-
- if (envp) {
+extern "C" CDECL void
+rust_set_environ(void* envp) {
+ // FIXME: this could actually be converted to rust (see issue #2674)
#ifdef __APPLE__
- *_NSGetEnviron() = (char **)envp;
+ *_NSGetEnviron() = (char **) envp;
#else
- environ = (char **)envp;
+ environ = (char **) envp;
#endif
- }
-
- execvp(argv[0], (char * const *)argv);
- exit(1);
-}
-
-extern "C" CDECL int
-rust_process_wait(int pid) {
- // FIXME: stub; exists to placate linker. (#2692)
- return 0;
}
#else
rust_list_dir_wfd_fp_buf
rust_log_console_on
rust_log_console_off
-rust_process_wait
-rust_run_program
+rust_set_environ
+rust_unset_sigprocmask
rust_sched_current_nonlazy_threads
rust_sched_threads
rust_set_exit_status
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure the destructor is run for newtype structs.
+
+struct Foo(@mut int);
+
+#[unsafe_destructor]
+impl Drop for Foo {
+ fn finalize(&self) {
+ ***self = 23;
+ }
+}
+
+fn main() {
+ let y = @mut 32;
+ {
+ let x = Foo(y);
+ }
+ assert_eq!(*y, 23);
+}