core :: Process :: arguments=
The arguments of the commandcore :: Process :: defaultinit
Launch a command with some argumentscore :: Process :: arguments=
The arguments of the commandcore :: Object :: class_factory
Implementation used byget_class
to create the specific class.
core :: Object :: defaultinit
core :: Process :: defaultinit
Launch a command with some argumentscore :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
core :: Object :: output_class_name
Display class name on stdout (debug only).Process
on which stdout can be read and stdin can be written to like a Duplex
# Simple sub-process
class Process
# The pid of the process
fun id: Int do return data.id
# Is the process finished?
fun is_finished: Bool do return data.is_finished
# Wait the termination of the process
fun wait
do
data.wait
assert is_finished
end
# The status once finished
#
# Require: `is_finished`
fun status: Int
do
assert is_finished
return data.status
end
# The target executable
# Either a file path or the name of an executable available in PATH.
var command: Text
# The arguments of the command
# Starts with the first real arguments---ie. does not include the progname (`argv[0]`, in C)
var arguments: nullable Array[Text]
# Launch a command with some arguments
init(command: Text, arguments: Text...) is old_style_init do
self.command = command
self.arguments = arguments
execute
end
# Launch a simple command with arguments passed as an array
init from_a(command: Text, arguments: nullable Array[Text])
do
self.command = command
self.arguments = arguments
execute
end
# Flags used internally to know which pipe to open
private fun pipeflags: Int do return 0
# Internal code to handle execution
protected fun execute
do
var arguments = self.arguments
var args = new FlatBuffer
var argc = 1
if not is_windows then
# Pass the arguments as a big C string where elements are separated with '\0'
args.append command
if arguments != null then
for a in arguments do
args.add '\0'
args.append a
end
argc += arguments.length
end
else
# Combine the program and args in a single string
assert not command.chars.has('"')
args = new FlatBuffer
args.add '"'
args.append command
args.add '"'
if arguments != null then
for a in arguments do
args.append " \""
args.append a.replace('"', "\\\"")
args.add '"'
end
end
end
data = basic_exec_execute(command.to_cstring, args.to_s.to_cstring, argc, pipeflags)
assert not data.address_is_null else print_error "Internal error executing: {command}"
end
private var data: NativeProcess
private fun basic_exec_execute(prog, args: CString, argc: Int, pipeflag: Int): NativeProcess `{
#ifdef _WIN32
SECURITY_ATTRIBUTES sec_attr;
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attr.bInheritHandle = TRUE;
sec_attr.lpSecurityDescriptor = NULL;
STARTUPINFO start_info;
ZeroMemory(&start_info, sizeof(STARTUPINFO));
start_info.cb = sizeof(STARTUPINFO);
start_info.dwFlags = STARTF_USESTDHANDLES;
HANDLE in_fd[2];
HANDLE out_fd[2];
HANDLE err_fd[2];
se_exec_data_t *result = (se_exec_data_t*)malloc(sizeof(se_exec_data_t));
// Redirect stdin?
if (pipeflag & 1) {
if (!CreatePipe(&in_fd[0], &in_fd[1], &sec_attr, 0)) {
return NULL;
}
start_info.hStdInput = in_fd[0];
result->in_fd = _open_osfhandle((intptr_t)in_fd[1], _O_WRONLY);
if ( !SetHandleInformation(in_fd[1], HANDLE_FLAG_INHERIT, 0) )
return NULL;
} else {
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
result->in_fd = -1;
}
// Redirect stdout?
if (pipeflag & 2) {
if (!CreatePipe(&out_fd[0], &out_fd[1], &sec_attr, 0)) {
return NULL;
}
start_info.hStdOutput = out_fd[1];
result->out_fd = _open_osfhandle((intptr_t)out_fd[0], _O_RDONLY);
if ( !SetHandleInformation(out_fd[0], HANDLE_FLAG_INHERIT, 0) )
return NULL;
} else {
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
result->out_fd = -1;
}
// Redirect stderr?
if (pipeflag & 4) {
if (!CreatePipe(&err_fd[0], &err_fd[1], &sec_attr, 0)) {
return NULL;
}
start_info.hStdError = err_fd[1];
result->err_fd = _open_osfhandle((intptr_t)err_fd[0], _O_RDONLY);
if ( !SetHandleInformation(err_fd[0], HANDLE_FLAG_INHERIT, 0) )
return NULL;
} else {
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
result->err_fd = -1;
}
PROCESS_INFORMATION proc_info;
ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
BOOL created = CreateProcess(NULL,
args, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // inherit handles
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&start_info,
&proc_info);
if (pipeflag & 1) CloseHandle(in_fd[0]);
if (pipeflag & 2) CloseHandle(out_fd[1]);
if (pipeflag & 3) CloseHandle(err_fd[1]);
// Error?
if (!created) {
result->running = 0;
result->status = 127;
// Close subprocess pipes
if (pipeflag & 1) CloseHandle(in_fd[1]);
if (pipeflag & 2) CloseHandle(out_fd[0]);
if (pipeflag & 3) CloseHandle(err_fd[0]);
} else {
result->h_process = proc_info.hProcess;
result->h_thread = proc_info.hThread;
result->id = GetProcessId(proc_info.hProcess);
result->running = 1;
}
return result;
#else
se_exec_data_t* result = NULL;
int id;
int in_fd[2];
int out_fd[2];
int err_fd[2];
if (pipeflag & 1) {
int res = pipe(in_fd);
if ( res == -1 ) {
return NULL;
}
}
if (pipeflag & 2) {
int res = pipe(out_fd);
if ( res == -1 ) {
return NULL;
}
}
if (pipeflag & 4) {
int res = pipe(err_fd);
if ( res == -1 ) {
return NULL;
}
}
id = fork();
if (id == 0)
{ /* child */
char **arg = malloc(sizeof(char*) * (argc+1));
char *c = args;
int i;
/* Prepare args */
for(i=0; i<argc; i++)
{
arg[i] = c;
c += strlen(c) + 1;
}
arg[argc] = NULL;
/* Connect pipe */
if (pipeflag & 1)
{
close(0);
dup2(in_fd[0], 0);
close(in_fd[0]);
close(in_fd[1]);
}
if (pipeflag & 2)
{
close(1);
dup2(out_fd[1], 1);
close(out_fd[0]);
close(out_fd[1]);
}
if (pipeflag & 4)
{
close(2);
dup2(err_fd[1], 2);
close(err_fd[0]);
close(err_fd[1]);
}
/* calls */
execvp(prog, arg);
_exit(127);
}
else if (id > 0)
{ /* father */
result = (se_exec_data_t*)malloc(sizeof(se_exec_data_t));
result->id = id;
result->running = 1;
if (pipeflag & 1)
{
result->in_fd = in_fd[1];
close(in_fd[0]);
} else
result->in_fd = -1;
if (pipeflag & 2)
{
result->out_fd = out_fd[0];
close(out_fd[1]);
} else
result->out_fd = -1;
if (pipeflag & 4)
{
result->err_fd = err_fd[0];
close(err_fd[1]);
} else
result->err_fd = -1;
} else {
perror("Process:");
return NULL;
}
return result;
#endif
`}
end
lib/core/exec.nit:51,1--338,3
redef class Process
# Send a signal to the process
fun signal(signal: Int) do native_kill(id, signal)
# Send the kill signal to the process
fun kill do signal(sigkill)
# Native implementation of `signal`
private fun native_kill(pid, signal: Int) `{ kill(pid, signal); `}
end
lib/signals/signals.nit:229,1--238,3