Revert "[dartdev] Use VmInteropHandler for invoking sub commands"
This reverts commit 08252fc9e9.
Reason for revert: https://github.com/dart-lang/sdk/issues/59784
Original change's description:
> [dartdev] Use VmInteropHandler for invoking sub commands
>
> Use VmInteropHandler for invoking sub commands instead of running them
> in an isolate. Running sub commands in an isolate causes an increased footprint.
> Changing this to use VmInteropHandler avoids the additional memory footprint.
>
> Commands that need to use an AOT runtime for execution now exec the AOT
> runtime and run the command.
>
> TEST=ci
>
> Change-Id: If7aed1cab2fec9d9940bd562ad5aa9c4e9a6ac7f
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398604
> Reviewed-by: Ben Konyi <bkonyi@google.com>
> Reviewed-by: Brian Quinlan <bquinlan@google.com>
> Commit-Queue: Siva Annamalai <asiva@google.com>
Change-Id: I82a997d49a7d52e1fdaa7d75f509603ebe5e51dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401901
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
This commit is contained in:
@@ -17,7 +17,6 @@ import '../experiments.dart';
|
||||
import '../native_assets.dart';
|
||||
import '../sdk.dart';
|
||||
import '../utils.dart';
|
||||
import '../vm_interop_handler.dart';
|
||||
|
||||
const int genericErrorExitCode = 255;
|
||||
const int compileErrorExitCode = 254;
|
||||
@@ -94,18 +93,17 @@ class CompileJSCommand extends CompileSubcommandCommand {
|
||||
final args = argResults!;
|
||||
var snapshot = sdk.dart2jsAotSnapshot;
|
||||
var runtime = sdk.dartAotRuntime;
|
||||
var isAOT = true;
|
||||
if (!Sdk.checkArtifactExists(snapshot, logError: false)) {
|
||||
// AOT snapshots cannot be generated on IA32, so we need this fallback
|
||||
// branch until support for IA32 is dropped (https://dartbug.com/49969).
|
||||
snapshot = sdk.dart2jsSnapshot;
|
||||
runtime = sdk.dart;
|
||||
if (!Sdk.checkArtifactExists(snapshot)) {
|
||||
return genericErrorExitCode;
|
||||
}
|
||||
runtime = sdk.dart;
|
||||
isAOT = false;
|
||||
}
|
||||
final dart2jsCommand = [
|
||||
runtime,
|
||||
snapshot,
|
||||
'--libraries-spec=${sdk.librariesJson}',
|
||||
'--cfe-invocation-modes=compile',
|
||||
@@ -114,13 +112,8 @@ class CompileJSCommand extends CompileSubcommandCommand {
|
||||
if (args.rest.isNotEmpty) ...args.rest.sublist(0),
|
||||
];
|
||||
try {
|
||||
VmInteropHandler.run(
|
||||
runtime,
|
||||
dart2jsCommand,
|
||||
packageConfigOverride: null,
|
||||
isAOT : isAOT,
|
||||
);
|
||||
return 0;
|
||||
final exitCode = await runProcessInheritStdio(dart2jsCommand);
|
||||
return exitCode;
|
||||
} catch (e, st) {
|
||||
log.stderr('Error: JS compilation failed');
|
||||
log.stderr(e.toString());
|
||||
|
||||
@@ -18,9 +18,6 @@ abstract class VmInteropHandler {
|
||||
///
|
||||
/// If [markMainIsolateAsSystemIsolate] is given and set to true, the spawned
|
||||
/// isolate will run with `--mark-main-isolate-as-system-isolate` enabled.
|
||||
///
|
||||
/// If [isAOT] is given and set to true, the script is executed by
|
||||
/// execing the dartaotruntime.
|
||||
static void run(
|
||||
String script,
|
||||
List<String> args, {
|
||||
@@ -30,12 +27,11 @@ abstract class VmInteropHandler {
|
||||
//
|
||||
// See https://github.com/dart-lang/sdk/issues/53576
|
||||
bool markMainIsolateAsSystemIsolate = false,
|
||||
bool isAOT = false,
|
||||
}) {
|
||||
final port = _port;
|
||||
if (port == null) return;
|
||||
final message = <dynamic>[
|
||||
isAOT ? _kResultRunAOT : _kResultRunJIT,
|
||||
_kResultRun,
|
||||
script,
|
||||
packageConfigOverride,
|
||||
markMainIsolateAsSystemIsolate,
|
||||
@@ -55,9 +51,8 @@ abstract class VmInteropHandler {
|
||||
}
|
||||
|
||||
// Note: keep in sync with runtime/bin/dartdev_isolate.h
|
||||
static const int _kResultRunJIT = 1;
|
||||
static const int _kResultRunAOT = 2;
|
||||
static const int _kResultExit = 3;
|
||||
static const int _kResultRun = 1;
|
||||
static const int _kResultExit = 2;
|
||||
|
||||
static SendPort? _port;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ DartDevIsolate::DartDevRunner DartDevIsolate::runner_ =
|
||||
DartDevIsolate::DartDevRunner();
|
||||
bool DartDevIsolate::should_run_dart_dev_ = false;
|
||||
bool DartDevIsolate::print_usage_error_ = false;
|
||||
CommandLineOptions* DartDevIsolate::vm_options_ = nullptr;
|
||||
Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
|
||||
DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
|
||||
DartDevIsolate::DartDev_Result_Unknown;
|
||||
@@ -139,7 +138,7 @@ void DartDevIsolate::DartDevRunner::Run(
|
||||
Thread::Start("DartDev Runner", RunCallback, reinterpret_cast<uword>(this));
|
||||
monitor_->WaitMicros(Monitor::kNoTimeout);
|
||||
|
||||
if (result_ == DartDevIsolate::DartDev_Result_RunJIT) {
|
||||
if (result_ == DartDevIsolate::DartDev_Result_Run) {
|
||||
// Clear the DartDev dart_options and replace them with the processed
|
||||
// options provided by DartDev.
|
||||
dart_options_->Reset();
|
||||
@@ -158,8 +157,8 @@ void DartDevIsolate::DartDevRunner::DartDevResultCallback(
|
||||
ASSERT(message->type == Dart_CObject_kArray);
|
||||
int32_t type = GetArrayItem(message, 0)->value.as_int32;
|
||||
switch (type) {
|
||||
case DartDevIsolate::DartDev_Result_RunJIT: {
|
||||
result_ = DartDevIsolate::DartDev_Result_RunJIT;
|
||||
case DartDevIsolate::DartDev_Result_Run: {
|
||||
result_ = DartDevIsolate::DartDev_Result_Run;
|
||||
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
||||
auto item2 = GetArrayItem(message, 2);
|
||||
|
||||
@@ -205,86 +204,6 @@ void DartDevIsolate::DartDevRunner::DartDevResultCallback(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DartDevIsolate::DartDev_Result_RunAOT: {
|
||||
result_ = DartDevIsolate::DartDev_Result_RunAOT;
|
||||
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
||||
auto item2 = GetArrayItem(message, 2);
|
||||
|
||||
ASSERT(item2->type == Dart_CObject_kString ||
|
||||
item2->type == Dart_CObject_kNull);
|
||||
|
||||
auto item3 = GetArrayItem(message, 3);
|
||||
|
||||
ASSERT(item3->type == Dart_CObject_kBool);
|
||||
const bool mark_main_isolate_as_system_isolate = item3->value.as_bool;
|
||||
if (mark_main_isolate_as_system_isolate) {
|
||||
Options::set_mark_main_isolate_as_system_isolate(true);
|
||||
}
|
||||
|
||||
if (*script_ != nullptr) {
|
||||
free(*script_);
|
||||
}
|
||||
if (*package_config_override_ != nullptr) {
|
||||
free(*package_config_override_);
|
||||
*package_config_override_ = nullptr;
|
||||
}
|
||||
*script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
|
||||
|
||||
if (item2->type == Dart_CObject_kString) {
|
||||
*package_config_override_ = Utils::StrDup(item2->value.as_string);
|
||||
}
|
||||
|
||||
intptr_t num_vm_options = 0;
|
||||
const char** vm_options = nullptr;
|
||||
ASSERT(GetArrayItem(message, 4)->type == Dart_CObject_kArray);
|
||||
Dart_CObject* args = GetArrayItem(message, 4);
|
||||
intptr_t argc = args->value.as_array.length;
|
||||
Dart_CObject** dart_args = args->value.as_array.values;
|
||||
|
||||
if (vm_options_ != nullptr) {
|
||||
num_vm_options = vm_options_->count();
|
||||
vm_options = vm_options_->arguments();
|
||||
}
|
||||
auto deleter = [](char** args) {
|
||||
for (intptr_t i = 0; i < argc_; ++i) {
|
||||
free(args[i]);
|
||||
}
|
||||
delete[] args;
|
||||
};
|
||||
// Total count of arguments to be passed to the script being execed.
|
||||
argc_ = argc + num_vm_options + 1;
|
||||
|
||||
// Array of arguments to be passed to the script being execed.
|
||||
argv_ = std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_ + 1],
|
||||
deleter);
|
||||
|
||||
intptr_t idx = 0;
|
||||
// Copy in name of the script to run (dartaotruntime).
|
||||
argv_[0] = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
|
||||
idx += 1;
|
||||
// Copy in any vm options that need to be passed to the execed process.
|
||||
for (intptr_t i = 0; i < num_vm_options; ++i) {
|
||||
argv_[i + idx] = Utils::StrDup(vm_options[i]);
|
||||
}
|
||||
idx += num_vm_options;
|
||||
// Copy in the dart options that need to be passed to the command.
|
||||
for (intptr_t i = 0; i < argc; ++i) {
|
||||
argv_[i + idx] = Utils::StrDup(dart_args[i]->value.as_string);
|
||||
}
|
||||
// Null terminate the argv array.
|
||||
argv_[argc + idx] = nullptr;
|
||||
|
||||
// Exec the script to be run and pass the arguments.
|
||||
char err_msg[256];
|
||||
err_msg[0] = '\0';
|
||||
int ret = Process::Exec(nullptr, *script_,
|
||||
const_cast<const char**>(argv_.get()), argc_,
|
||||
nullptr, err_msg, sizeof(err_msg));
|
||||
if (ret != 0) {
|
||||
ProcessError(err_msg, kErrorExitCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DartDevIsolate::DartDev_Result_Exit: {
|
||||
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
|
||||
int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;
|
||||
@@ -395,9 +314,7 @@ DartDevIsolate::DartDev_Result DartDevIsolate::RunDartDev(
|
||||
Dart_IsolateGroupCreateCallback create_isolate,
|
||||
char** packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* vm_options,
|
||||
CommandLineOptions* dart_options) {
|
||||
vm_options_ = vm_options;
|
||||
runner_.Run(create_isolate, packages_file, script, dart_options);
|
||||
return runner_.result();
|
||||
}
|
||||
|
||||
@@ -27,9 +27,8 @@ class DartDevIsolate {
|
||||
// Note: keep in sync with pkg/dartdev/lib/vm_interop_handler.dart
|
||||
typedef enum {
|
||||
DartDev_Result_Unknown = -1,
|
||||
DartDev_Result_RunJIT = 1,
|
||||
DartDev_Result_RunAOT = 2,
|
||||
DartDev_Result_Exit = 3,
|
||||
DartDev_Result_Run = 1,
|
||||
DartDev_Result_Exit = 2,
|
||||
} DartDev_Result;
|
||||
|
||||
// Returns true if there does not exist a file at |script_uri| or the URI is
|
||||
@@ -59,7 +58,6 @@ class DartDevIsolate {
|
||||
Dart_IsolateGroupCreateCallback create_isolate,
|
||||
char** packages_file,
|
||||
char** script,
|
||||
CommandLineOptions* vm_options,
|
||||
CommandLineOptions* dart_options);
|
||||
|
||||
protected:
|
||||
@@ -85,11 +83,11 @@ class DartDevIsolate {
|
||||
static char** package_config_override_;
|
||||
static std::unique_ptr<char*[], void (*)(char**)> argv_;
|
||||
static intptr_t argc_;
|
||||
static Monitor* monitor_;
|
||||
|
||||
Dart_IsolateGroupCreateCallback create_isolate_;
|
||||
CommandLineOptions* dart_options_;
|
||||
const char* packages_file_;
|
||||
static Monitor* monitor_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
};
|
||||
@@ -100,7 +98,6 @@ class DartDevIsolate {
|
||||
static DartDevRunner runner_;
|
||||
static bool should_run_dart_dev_;
|
||||
static bool print_usage_error_;
|
||||
static CommandLineOptions* vm_options_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevIsolate);
|
||||
|
||||
@@ -1421,11 +1421,11 @@ void main(int argc, char** argv) {
|
||||
Options::gen_snapshot_kind() == SnapshotKind::kNone) {
|
||||
DartDevIsolate::DartDev_Result dartdev_result = DartDevIsolate::RunDartDev(
|
||||
CreateIsolateGroupAndSetup, &package_config_override, &script_name,
|
||||
&vm_options, &dart_options);
|
||||
&dart_options);
|
||||
ASSERT(dartdev_result != DartDevIsolate::DartDev_Result_Unknown);
|
||||
ran_dart_dev = true;
|
||||
should_run_user_program =
|
||||
(dartdev_result == DartDevIsolate::DartDev_Result_RunJIT);
|
||||
(dartdev_result == DartDevIsolate::DartDev_Result_Run);
|
||||
if (should_run_user_program) {
|
||||
try_load_snapshots_lambda();
|
||||
}
|
||||
|
||||
@@ -114,9 +114,9 @@ void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) {
|
||||
const char* path = DartUtils::GetStringValue(path_handle);
|
||||
Dart_Handle arguments = Dart_GetNativeArgument(args, 3);
|
||||
intptr_t args_length = 0;
|
||||
const char** string_args = const_cast<const char**>(
|
||||
char** string_args =
|
||||
ExtractCStringList(arguments, status_handle,
|
||||
"Arguments must be builtin strings", &args_length));
|
||||
"Arguments must be builtin strings", &args_length);
|
||||
if (string_args == nullptr) {
|
||||
Dart_SetBooleanReturnValue(args, false);
|
||||
return;
|
||||
|
||||
+1
-18
@@ -94,7 +94,7 @@ class Process {
|
||||
// process exit streams.
|
||||
static int Start(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -114,23 +114,6 @@ class Process {
|
||||
intptr_t exit_handler,
|
||||
ProcessResult* result);
|
||||
|
||||
// Exec process.
|
||||
// On systems that support 'exec' it will use it to replace
|
||||
// the current process image with the image corresponding to 'path'
|
||||
// On systems that do not support it (Windows) it will start in a
|
||||
// child process in the same group as the parent so that when the parent
|
||||
// is killed the child also dies.
|
||||
// Returns 0 if the process could be execed successfully
|
||||
// Returns -1 if the exec could not be done successfully and 'errmsg'
|
||||
// points to the error message
|
||||
static int Exec(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* errmsg,
|
||||
intptr_t errmsg_len);
|
||||
|
||||
// Kill a process with a given pid.
|
||||
static bool Kill(intptr_t id, int signal);
|
||||
|
||||
|
||||
@@ -838,19 +838,6 @@ int Process::Start(Namespace* namespc,
|
||||
return starter.Start();
|
||||
}
|
||||
|
||||
// The command line dart utility does not run on Fuchsia, this functionality
|
||||
// is not supported on that platform.
|
||||
int Process::Exec(Namespace* namespc,
|
||||
const char* path,
|
||||
const char** arguments,
|
||||
const char* working_directory,
|
||||
char* errmsg,
|
||||
intptr_t errmsg_len) {
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"Process::Exec is not supported on this platform");
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Process::SetSignalHandler(intptr_t signal) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
||||
@@ -246,47 +246,11 @@ int ExitCodeHandler::process_count_ = 0;
|
||||
bool ExitCodeHandler::terminate_done_ = false;
|
||||
Monitor* ExitCodeHandler::monitor_ = nullptr;
|
||||
|
||||
// Tries to find path relative to the current namespace unless it should be
|
||||
// searched in the PATH environment variable.
|
||||
// The path that should be passed to exec is returned in realpath.
|
||||
// Returns true on success, and false if there was an error that should
|
||||
// be reported to the parent.
|
||||
static bool PathInNamespace(char* realpath,
|
||||
intptr_t realpath_size,
|
||||
Namespace* namespc,
|
||||
const char* path) {
|
||||
// Perform a PATH search if there's no slash in the path.
|
||||
if (Namespace::IsDefault(namespc) || strchr(path, '/') == nullptr) {
|
||||
// TODO(zra): If there is a non-default namespace, the entries in PATH
|
||||
// should be treated as relative to the namespace.
|
||||
strncpy(realpath, path, realpath_size);
|
||||
realpath[realpath_size - 1] = '\0';
|
||||
return true;
|
||||
}
|
||||
NamespaceScope ns(namespc, path);
|
||||
const int fd =
|
||||
TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC));
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
char procpath[PATH_MAX];
|
||||
snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd);
|
||||
const intptr_t length =
|
||||
TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size));
|
||||
if (length < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return false;
|
||||
}
|
||||
realpath[length] = '\0';
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
class ProcessStarter {
|
||||
public:
|
||||
ProcessStarter(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -317,7 +281,7 @@ class ProcessStarter {
|
||||
exec_control_[0] = -1;
|
||||
exec_control_[1] = -1;
|
||||
|
||||
program_arguments_ = reinterpret_cast<const char**>(Dart_ScopeAllocate(
|
||||
program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
|
||||
(arguments_length + 2) * sizeof(*program_arguments_)));
|
||||
program_arguments_[0] = const_cast<char*>(path_);
|
||||
for (int i = 0; i < arguments_length; i++) {
|
||||
@@ -483,7 +447,31 @@ class ProcessStarter {
|
||||
// Returns true on success, and false if there was an error that should
|
||||
// be reported to the parent.
|
||||
bool FindPathInNamespace(char* realpath, intptr_t realpath_size) {
|
||||
return PathInNamespace(realpath, realpath_size, namespc_, path_);
|
||||
// Perform a PATH search if there's no slash in the path.
|
||||
if (Namespace::IsDefault(namespc_) || strchr(path_, '/') == nullptr) {
|
||||
// TODO(zra): If there is a non-default namespace, the entries in PATH
|
||||
// should be treated as relative to the namespace.
|
||||
strncpy(realpath, path_, realpath_size);
|
||||
realpath[realpath_size - 1] = '\0';
|
||||
return true;
|
||||
}
|
||||
NamespaceScope ns(namespc_, path_);
|
||||
const int fd =
|
||||
TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC));
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
char procpath[PATH_MAX];
|
||||
snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd);
|
||||
const intptr_t length =
|
||||
TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size));
|
||||
if (length < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return false;
|
||||
}
|
||||
realpath[length] = '\0';
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExecProcess() {
|
||||
@@ -784,7 +772,7 @@ class ProcessStarter {
|
||||
int write_out_[2]; // Pipe for stdin to child process.
|
||||
int exec_control_[2]; // Pipe to get the result from exec.
|
||||
|
||||
const char** program_arguments_;
|
||||
char** program_arguments_;
|
||||
char** program_environment_;
|
||||
|
||||
Namespace* namespc_;
|
||||
@@ -804,7 +792,7 @@ class ProcessStarter {
|
||||
|
||||
int Process::Start(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -926,31 +914,6 @@ bool Process::Wait(intptr_t pid,
|
||||
return true;
|
||||
}
|
||||
|
||||
int Process::Exec(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* errmsg,
|
||||
intptr_t errmsg_len) {
|
||||
if (working_directory != nullptr &&
|
||||
!Directory::SetCurrent(namespc, working_directory)) {
|
||||
Utils::StrError(errno, errmsg, errmsg_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char realpath[PATH_MAX];
|
||||
if (!PathInNamespace(realpath, PATH_MAX, namespc, path)) {
|
||||
Utils::StrError(errno, errmsg, errmsg_len);
|
||||
return -1;
|
||||
}
|
||||
// TODO(dart:io) Test for the existence of execveat, and use it instead.
|
||||
execvp(const_cast<const char*>(realpath),
|
||||
const_cast<char* const*>(arguments));
|
||||
Utils::StrError(errno, errmsg, errmsg_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Process::Kill(intptr_t id, int signal) {
|
||||
return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ Monitor* ExitCodeHandler::monitor_ = nullptr;
|
||||
class ProcessStarter {
|
||||
public:
|
||||
ProcessStarter(const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -279,7 +279,7 @@ class ProcessStarter {
|
||||
exec_control_[0] = -1;
|
||||
exec_control_[1] = -1;
|
||||
|
||||
program_arguments_ = reinterpret_cast<const char**>(Dart_ScopeAllocate(
|
||||
program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
|
||||
(arguments_length + 2) * sizeof(*program_arguments_)));
|
||||
program_arguments_[0] = const_cast<char*>(path_);
|
||||
for (int i = 0; i < arguments_length; i++) {
|
||||
@@ -740,7 +740,7 @@ class ProcessStarter {
|
||||
int write_out_[2]; // Pipe for stdin to child process.
|
||||
int exec_control_[2]; // Pipe to get the result from exec.
|
||||
|
||||
const char** program_arguments_;
|
||||
char** program_arguments_;
|
||||
char** program_environment_;
|
||||
|
||||
const char* path_;
|
||||
@@ -760,7 +760,7 @@ class ProcessStarter {
|
||||
|
||||
int Process::Start(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -898,24 +898,6 @@ bool Process::Wait(intptr_t pid,
|
||||
#endif // defined(DART_HOST_OS_IOS)
|
||||
}
|
||||
|
||||
int Process::Exec(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* errmsg,
|
||||
intptr_t errmsg_len) {
|
||||
if (working_directory != nullptr &&
|
||||
TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) {
|
||||
Utils::StrError(errno, errmsg, errmsg_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
execvp(const_cast<const char*>(path), const_cast<char* const*>(arguments));
|
||||
Utils::StrError(errno, errmsg, errmsg_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int SignalMap(intptr_t id) {
|
||||
switch (static_cast<ProcessSignals>(id)) {
|
||||
case kSighup:
|
||||
|
||||
+4
-128
@@ -20,7 +20,6 @@
|
||||
#include "bin/utils.h"
|
||||
#include "bin/utils_win.h"
|
||||
#include "platform/syslog.h"
|
||||
#include "platform/text_buffer.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
@@ -345,7 +344,7 @@ static int GenerateNames(wchar_t pipe_names[Count][kMaxPipeNameSize]) {
|
||||
class ProcessStarter {
|
||||
public:
|
||||
ProcessStarter(const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -374,12 +373,11 @@ class ProcessStarter {
|
||||
stderr_handles_[kWriteHandle] = INVALID_HANDLE_VALUE;
|
||||
exit_handles_[kReadHandle] = INVALID_HANDLE_VALUE;
|
||||
exit_handles_[kWriteHandle] = INVALID_HANDLE_VALUE;
|
||||
child_process_handle_ = INVALID_HANDLE_VALUE;
|
||||
|
||||
// Transform input strings to system format.
|
||||
const wchar_t* system_path = StringUtilsWin::Utf8ToWide(path_);
|
||||
const wchar_t** system_arguments;
|
||||
system_arguments = reinterpret_cast<const wchar_t**>(
|
||||
wchar_t** system_arguments;
|
||||
system_arguments = reinterpret_cast<wchar_t**>(
|
||||
Dart_ScopeAllocate(arguments_length * sizeof(*system_arguments)));
|
||||
for (int i = 0; i < arguments_length; i++) {
|
||||
system_arguments[i] = StringUtilsWin::Utf8ToWide(arguments[i]);
|
||||
@@ -564,42 +562,7 @@ class ProcessStarter {
|
||||
*exit_handler_ = reinterpret_cast<intptr_t>(exit_handle);
|
||||
}
|
||||
}
|
||||
child_process_handle_ = process_info.hProcess;
|
||||
CloseHandle(process_info.hThread);
|
||||
|
||||
// Return process id.
|
||||
*id_ = process_info.dwProcessId;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StartForExec() {
|
||||
// Setup info
|
||||
STARTUPINFOEXW startup_info;
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
startup_info.StartupInfo.cb = sizeof(startup_info);
|
||||
ASSERT(mode_ == kInheritStdio);
|
||||
ASSERT(Process::ModeIsAttached(mode_));
|
||||
ASSERT(!Process::ModeHasStdio(mode_));
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
ZeroMemory(&process_info, sizeof(process_info));
|
||||
|
||||
// Create process.
|
||||
DWORD creation_flags =
|
||||
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT;
|
||||
BOOL result = CreateProcessW(
|
||||
nullptr, // ApplicationName
|
||||
command_line_,
|
||||
nullptr, // ProcessAttributes
|
||||
nullptr, // ThreadAttributes
|
||||
TRUE, // InheritHandles
|
||||
creation_flags, environment_block_, system_working_directory_,
|
||||
reinterpret_cast<STARTUPINFOW*>(&startup_info), &process_info);
|
||||
|
||||
if (result == 0) {
|
||||
return SetOsErrorMessage(os_error_message_);
|
||||
}
|
||||
child_process_handle_ = process_info.hProcess;
|
||||
CloseHandle(process_info.hThread);
|
||||
|
||||
// Return process id.
|
||||
@@ -664,7 +627,6 @@ class ProcessStarter {
|
||||
HANDLE stdout_handles_[2];
|
||||
HANDLE stderr_handles_[2];
|
||||
HANDLE exit_handles_[2];
|
||||
HANDLE child_process_handle_;
|
||||
|
||||
const wchar_t* system_working_directory_;
|
||||
wchar_t* command_line_;
|
||||
@@ -689,7 +651,7 @@ class ProcessStarter {
|
||||
|
||||
int Process::Start(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* environment[],
|
||||
@@ -918,92 +880,6 @@ bool Process::Wait(intptr_t pid,
|
||||
return true;
|
||||
}
|
||||
|
||||
int Process::Exec(Namespace* namespc,
|
||||
const char* path,
|
||||
const char* arguments[],
|
||||
intptr_t arguments_length,
|
||||
const char* working_directory,
|
||||
char* errmsg,
|
||||
intptr_t errmsg_len) {
|
||||
// Create a Job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
||||
HANDLE hjob = CreateJobObject(nullptr, nullptr);
|
||||
if (hjob == nullptr) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - CreateJobObject failed %d\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
|
||||
DWORD qresult;
|
||||
if (!QueryInformationJobObject(hjob, JobObjectExtendedLimitInformation, &info,
|
||||
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
|
||||
&qresult)) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - QueryInformationJobObject failed %d\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
if (!SetInformationJobObject(hjob, JobObjectExtendedLimitInformation, &info,
|
||||
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - SetInformationJobObject failed %d\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Put the current process into the job object (there is a race here
|
||||
// as the process can crash before it is in the Job object, but since
|
||||
// we haven't spawned any children yet this race is harmless)
|
||||
if (!AssignProcessToJobObject(hjob, GetCurrentProcess())) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - AssignProcessToJobObject failed %d\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Spawn the new child process (this child will automatically get
|
||||
// added to the Job object).
|
||||
// If the parent process is killed or it crashes the Job object
|
||||
// will get destroyed and all the child processes will also get killed.
|
||||
// arguments includes the name of the executable to run which is the same
|
||||
// as the value passed in 'path', we strip that off when starting the
|
||||
// process.
|
||||
intptr_t pid = -1;
|
||||
char* os_error_message = nullptr; // Scope allocated by Process::Start.
|
||||
ProcessStarter starter(path, &(arguments[1]), (arguments_length - 1),
|
||||
working_directory, nullptr, 0, kInheritStdio, nullptr,
|
||||
nullptr, nullptr, &pid, nullptr, &os_error_message);
|
||||
int result = starter.StartForExec();
|
||||
if (result != 0) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - %s\n", os_error_message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Now wait for this child process to terminate (normal exit or crash).
|
||||
HANDLE child_process = starter.child_process_handle_;
|
||||
ASSERT(child_process != INVALID_HANDLE_VALUE);
|
||||
DWORD wait_result = WaitForSingleObject(child_process, INFINITE);
|
||||
if (wait_result != WAIT_OBJECT_0) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - WaitForSingleObject failed %d\n", GetLastError());
|
||||
CloseHandle(child_process);
|
||||
return -1;
|
||||
}
|
||||
int retval;
|
||||
if (!GetExitCodeProcess(child_process, reinterpret_cast<DWORD*>(&retval))) {
|
||||
BufferFormatter f(errmsg, errmsg_len);
|
||||
f.Printf("Process::Exec - GetExitCodeProcess failed %d\n", GetLastError());
|
||||
CloseHandle(child_process);
|
||||
return -1;
|
||||
}
|
||||
CloseHandle(child_process);
|
||||
// We exit the process here to simulate the same behaviour as exec on systems
|
||||
// that support it.
|
||||
ExitProcess(retval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Process::Kill(intptr_t id, int signal) {
|
||||
USE(signal); // signal is not used on Windows.
|
||||
HANDLE process_handle;
|
||||
|
||||
Reference in New Issue
Block a user