diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart index 75f113c7233..54ad4543dcf 100644 --- a/pkg/dartdev/lib/src/commands/compile.dart +++ b/pkg/dartdev/lib/src/commands/compile.dart @@ -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()); diff --git a/pkg/dartdev/lib/src/vm_interop_handler.dart b/pkg/dartdev/lib/src/vm_interop_handler.dart index 43bd647b009..37eed1dc3b4 100644 --- a/pkg/dartdev/lib/src/vm_interop_handler.dart +++ b/pkg/dartdev/lib/src/vm_interop_handler.dart @@ -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 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 = [ - 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; } diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc index 95c9fd536e1..c7aab45c115 100644 --- a/runtime/bin/dartdev_isolate.cc +++ b/runtime/bin/dartdev_isolate.cc @@ -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(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(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(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(); } diff --git a/runtime/bin/dartdev_isolate.h b/runtime/bin/dartdev_isolate.h index ed997ccaeca..79566c658f3 100644 --- a/runtime/bin/dartdev_isolate.h +++ b/runtime/bin/dartdev_isolate.h @@ -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 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); diff --git a/runtime/bin/main_impl.cc b/runtime/bin/main_impl.cc index cd4fab25179..4a26768a1d4 100644 --- a/runtime/bin/main_impl.cc +++ b/runtime/bin/main_impl.cc @@ -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(); } diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc index dfb0b77e403..f990e80e3ac 100644 --- a/runtime/bin/process.cc +++ b/runtime/bin/process.cc @@ -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( + 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; diff --git a/runtime/bin/process.h b/runtime/bin/process.h index 2aa40cdcb85..9bd547c802b 100644 --- a/runtime/bin/process.h +++ b/runtime/bin/process.h @@ -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); diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc index 170f0740cdf..eed2af0494d 100644 --- a/runtime/bin/process_fuchsia.cc +++ b/runtime/bin/process_fuchsia.cc @@ -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; diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc index da95e5a1ecd..64e74fcfab9 100644 --- a/runtime/bin/process_linux.cc +++ b/runtime/bin/process_linux.cc @@ -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(Dart_ScopeAllocate( + program_arguments_ = reinterpret_cast(Dart_ScopeAllocate( (arguments_length + 2) * sizeof(*program_arguments_))); program_arguments_[0] = const_cast(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(realpath), - const_cast(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); } diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc index 94568e3e176..d7eb45e4ae0 100644 --- a/runtime/bin/process_macos.cc +++ b/runtime/bin/process_macos.cc @@ -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(Dart_ScopeAllocate( + program_arguments_ = reinterpret_cast(Dart_ScopeAllocate( (arguments_length + 2) * sizeof(*program_arguments_))); program_arguments_[0] = const_cast(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(path), const_cast(arguments)); - Utils::StrError(errno, errmsg, errmsg_len); - return -1; -} - static int SignalMap(intptr_t id) { switch (static_cast(id)) { case kSighup: diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc index b9949c9c52a..e9a353b36c3 100644 --- a/runtime/bin/process_win.cc +++ b/runtime/bin/process_win.cc @@ -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( + wchar_t** system_arguments; + system_arguments = reinterpret_cast( 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(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(&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(&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;