Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
544ac620
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
544ac620
编写于
4月 30, 2013
作者:
G
gareth
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Convert most of rust_run_program.cpp to rust (issue #2674).
上级
b6988843
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
454 addition
and
236 deletion
+454
-236
src/libcore/libc.rs
src/libcore/libc.rs
+127
-4
src/libcore/os.rs
src/libcore/os.rs
+1
-1
src/libcore/run.rs
src/libcore/run.rs
+308
-45
src/rt/rust_run_program.cpp
src/rt/rust_run_program.cpp
+16
-184
src/rt/rustrt.def.in
src/rt/rustrt.def.in
+2
-2
未找到文件。
src/libcore/libc.rs
浏览文件 @
544ac620
...
...
@@ -582,12 +582,16 @@ pub mod extra {
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
;
...
...
@@ -596,6 +600,36 @@ pub mod extra {
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
;
}
}
}
...
...
@@ -848,6 +882,11 @@ pub mod posix08 {
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
;
...
...
@@ -855,6 +894,50 @@ pub mod extra {
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
;
}
}
...
...
@@ -1751,12 +1834,24 @@ unsafe fn sysctlbyname(name: *c_char,
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
{
}
...
...
@@ -1790,9 +1885,11 @@ pub mod extra {
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"
{
...
...
@@ -1829,19 +1926,45 @@ unsafe fn FindNextFileW(findFile: HANDLE,
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
;
}
}
}
...
...
src/libcore/os.rs
浏览文件 @
544ac620
...
...
@@ -373,7 +373,7 @@ pub fn pipe() -> Pipe {
// 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
,
...
...
src/libcore/run.rs
浏览文件 @
544ac620
...
...
@@ -22,31 +22,6 @@
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
,
...
...
@@ -191,21 +166,262 @@ pub fn spawn_process(prog: &str, args: &[~str],
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
{
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
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
{
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
]);
...
...
@@ -246,7 +462,7 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
#[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.
...
...
@@ -264,11 +480,12 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
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
{
...
...
@@ -312,8 +529,6 @@ fn with_dirp<T>(d: &Option<~str>,
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
;
...
...
@@ -345,7 +560,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program {
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
);
...
...
@@ -398,13 +612,6 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
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
...
...
@@ -485,11 +692,46 @@ pub fn waitpid(pid: pid_t) -> int {
#[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)]
...
...
@@ -543,6 +785,27 @@ mod tests {
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
()
{
...
...
src/rt/rust_run_program.cpp
浏览文件 @
544ac620
...
...
@@ -15,212 +15,44 @@
#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
...
...
src/rt/rustrt.def.in
浏览文件 @
544ac620
...
...
@@ -37,8 +37,8 @@ rust_list_dir_wfd_size
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
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录