35 using v8::EscapableHandleScope;
36 using v8::FunctionCallbackInfo;
37 using v8::HandleScope;
48 SyncProcessOutputBuffer::SyncProcessOutputBuffer()
54 void SyncProcessOutputBuffer::OnAlloc(
size_t suggested_size,
55 uv_buf_t*
buf)
const {
56 if (used() == kBufferSize)
57 *buf = uv_buf_init(
nullptr, 0);
59 *buf = uv_buf_init(data_ + used(), available());
63 void SyncProcessOutputBuffer::OnRead(
const uv_buf_t* buf,
size_t nread) {
65 CHECK_EQ(buf->base, data_ + used());
66 used_ +=
static_cast<unsigned int>(nread);
71 memcpy(dest, data_, used());
76 unsigned int SyncProcessOutputBuffer::available()
const {
77 return sizeof data_ - used();
81 unsigned int SyncProcessOutputBuffer::used()
const {
86 SyncProcessOutputBuffer* SyncProcessOutputBuffer::next()
const {
91 void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
96 SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
99 uv_buf_t input_buffer)
100 : process_handler_(process_handler),
103 input_buffer_(input_buffer),
112 lifecycle_(kUninitialized) {
113 CHECK(readable || writable);
117 SyncProcessStdioPipe::~SyncProcessStdioPipe() {
118 CHECK(lifecycle_ == kUninitialized || lifecycle_ == kClosed);
120 SyncProcessOutputBuffer*
buf;
121 SyncProcessOutputBuffer* next;
123 for (buf = first_output_buffer_; buf !=
nullptr; buf = next) {
131 CHECK_EQ(lifecycle_, kUninitialized);
133 int r = uv_pipe_init(loop, uv_pipe(), 0);
137 uv_pipe()->data =
this;
139 lifecycle_ = kInitialized;
145 CHECK_EQ(lifecycle_, kInitialized);
149 lifecycle_ = kStarted;
152 if (input_buffer_.len > 0) {
153 CHECK_NE(input_buffer_.base,
nullptr);
155 int r = uv_write(&write_req_,
164 int r = uv_shutdown(&shutdown_req_, uv_stream(), ShutdownCallback);
170 int r = uv_read_start(uv_stream(), AllocCallback, ReadCallback);
179 void SyncProcessStdioPipe::Close() {
180 CHECK(lifecycle_ == kInitialized || lifecycle_ == kStarted);
182 uv_close(uv_handle(), CloseCallback);
184 lifecycle_ = kClosing;
188 Local<Object> SyncProcessStdioPipe::GetOutputAsBuffer(Environment* env)
const {
189 size_t length = OutputLength();
190 Local<Object> js_buffer =
Buffer::New(env, length).ToLocalChecked();
196 bool SyncProcessStdioPipe::readable()
const {
201 bool SyncProcessStdioPipe::writable()
const {
206 uv_stdio_flags SyncProcessStdioPipe::uv_flags()
const {
209 flags = UV_CREATE_PIPE;
211 flags |= UV_READABLE_PIPE;
213 flags |= UV_WRITABLE_PIPE;
215 return static_cast<uv_stdio_flags
>(flags);
219 uv_pipe_t* SyncProcessStdioPipe::uv_pipe()
const {
220 CHECK_LT(lifecycle_, kClosing);
225 uv_stream_t* SyncProcessStdioPipe::uv_stream()
const {
226 return reinterpret_cast<uv_stream_t*
>(uv_pipe());
230 uv_handle_t* SyncProcessStdioPipe::uv_handle()
const {
231 return reinterpret_cast<uv_handle_t*
>(uv_pipe());
235 size_t SyncProcessStdioPipe::OutputLength()
const {
236 SyncProcessOutputBuffer*
buf;
239 for (buf = first_output_buffer_; buf !=
nullptr; buf = buf->next())
246 void SyncProcessStdioPipe::CopyOutput(
char* dest)
const {
247 SyncProcessOutputBuffer*
buf;
250 for (buf = first_output_buffer_; buf !=
nullptr; buf = buf->next())
251 offset += buf->Copy(dest + offset);
255 void SyncProcessStdioPipe::OnAlloc(
size_t suggested_size, uv_buf_t* buf) {
261 if (last_output_buffer_ ==
nullptr) {
263 first_output_buffer_ =
new SyncProcessOutputBuffer();
264 last_output_buffer_ = first_output_buffer_;
266 }
else if (last_output_buffer_->available() == 0) {
268 SyncProcessOutputBuffer* buf =
new SyncProcessOutputBuffer();
269 last_output_buffer_->set_next(buf);
270 last_output_buffer_ =
buf;
273 last_output_buffer_->OnAlloc(suggested_size, buf);
277 void SyncProcessStdioPipe::OnRead(
const uv_buf_t* buf, ssize_t nread) {
278 if (nread == UV_EOF) {
281 }
else if (nread < 0) {
282 SetError(static_cast<int>(nread));
284 uv_read_stop(uv_stream());
287 last_output_buffer_->OnRead(buf, nread);
288 process_handler_->IncrementBufferSizeAndCheckOverflow(nread);
293 void SyncProcessStdioPipe::OnWriteDone(
int result) {
299 void SyncProcessStdioPipe::OnShutdownDone(
int result) {
305 void SyncProcessStdioPipe::OnClose() {
306 lifecycle_ = kClosed;
310 void SyncProcessStdioPipe::SetError(
int error) {
312 process_handler_->SetPipeError(error);
316 void SyncProcessStdioPipe::AllocCallback(uv_handle_t* handle,
317 size_t suggested_size,
319 SyncProcessStdioPipe*
self =
320 reinterpret_cast<SyncProcessStdioPipe*
>(handle->data);
321 self->OnAlloc(suggested_size, buf);
325 void SyncProcessStdioPipe::ReadCallback(uv_stream_t* stream,
327 const uv_buf_t* buf) {
328 SyncProcessStdioPipe*
self =
329 reinterpret_cast<SyncProcessStdioPipe*
>(stream->data);
330 self->OnRead(buf, nread);
334 void SyncProcessStdioPipe::WriteCallback(uv_write_t*
req,
int result) {
335 SyncProcessStdioPipe*
self =
336 reinterpret_cast<SyncProcessStdioPipe*
>(req->handle->data);
337 self->OnWriteDone(result);
341 void SyncProcessStdioPipe::ShutdownCallback(uv_shutdown_t* req,
int result) {
342 SyncProcessStdioPipe*
self =
343 reinterpret_cast<SyncProcessStdioPipe*
>(req->handle->data);
349 if (result == UV_ENOTCONN)
352 self->OnShutdownDone(result);
356 void SyncProcessStdioPipe::CloseCallback(uv_handle_t* handle) {
357 SyncProcessStdioPipe*
self =
358 reinterpret_cast<SyncProcessStdioPipe*
>(handle->data);
365 Local<Context> context) {
366 Environment* env = Environment::GetCurrent(context);
367 env->SetMethod(target,
"spawn", Spawn);
371 void SyncProcessRunner::Spawn(
const FunctionCallbackInfo<Value>& args) {
372 Environment* env = Environment::GetCurrent(args);
373 env->PrintSyncTrace();
374 SyncProcessRunner
p(env);
375 Local<Value> result =
p.Run(args[0]);
376 args.GetReturnValue().Set(result);
380 SyncProcessRunner::SyncProcessRunner(Environment* env)
383 kill_signal_(SIGTERM),
390 stdio_pipes_initialized_(false),
392 uv_process_options_(),
401 buffered_output_size_(0),
406 kill_timer_initialized_(false),
411 lifecycle_(kUninitialized),
417 SyncProcessRunner::~SyncProcessRunner() {
418 CHECK_EQ(lifecycle_, kHandlesClosed);
420 if (stdio_pipes_ !=
nullptr) {
421 for (
size_t i = 0; i < stdio_count_; i++) {
422 if (stdio_pipes_[i] !=
nullptr)
423 delete stdio_pipes_[i];
427 delete[] stdio_pipes_;
428 delete[] file_buffer_;
429 delete[] args_buffer_;
430 delete[] cwd_buffer_;
431 delete[] env_buffer_;
432 delete[] uv_stdio_containers_;
436 Environment* SyncProcessRunner::env()
const {
441 Local<Object> SyncProcessRunner::Run(Local<Value> options) {
442 EscapableHandleScope scope(env()->isolate());
444 CHECK_EQ(lifecycle_, kUninitialized);
446 TryInitializeAndRunLoop(options);
447 CloseHandlesAndDeleteLoop();
449 Local<Object> result = BuildResultObject();
451 return scope.Escape(result);
455 void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
460 CHECK_EQ(lifecycle_, kUninitialized);
461 lifecycle_ = kInitialized;
463 uv_loop_ =
new uv_loop_t;
464 if (uv_loop_ ==
nullptr)
465 return SetError(UV_ENOMEM);
466 CHECK_EQ(uv_loop_init(uv_loop_), 0);
468 r = ParseOptions(options);
473 r = uv_timer_init(uv_loop_, &uv_timer_);
477 uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
479 uv_timer_.data =
this;
480 kill_timer_initialized_ =
true;
486 r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
491 uv_process_options_.exit_cb = ExitCallback;
492 r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
495 uv_process_.data =
this;
497 for (uint32_t i = 0; i < stdio_count_; i++) {
498 SyncProcessStdioPipe* h = stdio_pipes_[i];
502 return SetPipeError(r);
506 r = uv_run(uv_loop_, UV_RUN_DEFAULT);
512 CHECK_GE(exit_status_, 0);
516 void SyncProcessRunner::CloseHandlesAndDeleteLoop() {
517 CHECK_LT(lifecycle_, kHandlesClosed);
519 if (uv_loop_ !=
nullptr) {
523 uv_handle_t* uv_process_handle =
524 reinterpret_cast<uv_handle_t*
>(&uv_process_);
529 if (uv_process_handle->type == UV_PROCESS &&
530 !uv_is_closing(uv_process_handle))
531 uv_close(uv_process_handle,
nullptr);
535 int r = uv_run(uv_loop_, UV_RUN_DEFAULT);
539 CHECK_EQ(uv_loop_close(uv_loop_), 0);
545 CHECK_EQ(
false, stdio_pipes_initialized_);
546 CHECK_EQ(
false, kill_timer_initialized_);
549 lifecycle_ = kHandlesClosed;
553 void SyncProcessRunner::CloseStdioPipes() {
554 CHECK_LT(lifecycle_, kHandlesClosed);
556 if (stdio_pipes_initialized_) {
557 CHECK_NE(stdio_pipes_,
nullptr);
558 CHECK_NE(uv_loop_,
nullptr);
560 for (uint32_t i = 0; i < stdio_count_; i++) {
561 if (stdio_pipes_[i] !=
nullptr)
562 stdio_pipes_[i]->Close();
565 stdio_pipes_initialized_ =
false;
570 void SyncProcessRunner::CloseKillTimer() {
571 CHECK_LT(lifecycle_, kHandlesClosed);
573 if (kill_timer_initialized_) {
574 CHECK_GT(timeout_, 0);
575 CHECK_NE(uv_loop_,
nullptr);
577 uv_handle_t* uv_timer_handle =
reinterpret_cast<uv_handle_t*
>(&uv_timer_);
578 uv_ref(uv_timer_handle);
579 uv_close(uv_timer_handle, KillTimerCloseCallback);
581 kill_timer_initialized_ =
false;
586 void SyncProcessRunner::Kill() {
597 if (exit_status_ < 0) {
598 int r = uv_process_kill(&uv_process_, kill_signal_);
603 if (r < 0 && r != UV_ESRCH) {
606 r = uv_process_kill(&uv_process_, SIGKILL);
607 CHECK(r >= 0 || r == UV_ESRCH);
619 void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
620 buffered_output_size_ += length;
622 if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
623 SetError(UV_ENOBUFS);
629 void SyncProcessRunner::OnExit(int64_t exit_status,
int term_signal) {
631 return SetError(static_cast<int>(exit_status));
633 exit_status_ = exit_status;
634 term_signal_ = term_signal;
638 void SyncProcessRunner::OnKillTimerTimeout() {
639 SetError(UV_ETIMEDOUT);
644 int SyncProcessRunner::GetError() {
652 void SyncProcessRunner::SetError(
int error) {
658 void SyncProcessRunner::SetPipeError(
int pipe_error) {
659 if (pipe_error_ == 0)
660 pipe_error_ = pipe_error;
664 Local<Object> SyncProcessRunner::BuildResultObject() {
665 EscapableHandleScope scope(env()->isolate());
667 Local<Object> js_result =
Object::New(env()->isolate());
669 if (GetError() != 0) {
670 js_result->Set(env()->error_string(),
674 if (exit_status_ >= 0) {
675 if (term_signal_ > 0) {
676 js_result->Set(env()->status_string(), Null(env()->isolate()));
678 js_result->Set(env()->status_string(),
679 Number::New(env()->isolate(), static_cast<double>(exit_status_)));
683 js_result->Set(env()->status_string(), Null(env()->isolate()));
686 if (term_signal_ > 0)
687 js_result->Set(env()->signal_string(),
688 String::NewFromUtf8(env()->isolate(),
signo_string(term_signal_)));
690 js_result->Set(env()->signal_string(), Null(env()->isolate()));
692 if (exit_status_ >= 0)
693 js_result->Set(env()->output_string(), BuildOutputArray());
695 js_result->Set(env()->output_string(), Null(env()->isolate()));
697 js_result->Set(env()->pid_string(),
700 return scope.Escape(js_result);
704 Local<Array> SyncProcessRunner::BuildOutputArray() {
705 CHECK_GE(lifecycle_, kInitialized);
706 CHECK_NE(stdio_pipes_,
nullptr);
708 EscapableHandleScope scope(env()->isolate());
709 Local<Array> js_output =
Array::New(env()->isolate(), stdio_count_);
711 for (uint32_t i = 0; i < stdio_count_; i++) {
712 SyncProcessStdioPipe* h = stdio_pipes_[i];
713 if (h !=
nullptr && h->writable())
714 js_output->Set(i, h->GetOutputAsBuffer(env()));
716 js_output->Set(i, Null(env()->isolate()));
719 return scope.Escape(js_output);
723 int SyncProcessRunner::ParseOptions(Local<Value> js_value) {
724 HandleScope scope(env()->isolate());
727 if (!js_value->IsObject())
730 Local<Object> js_options = js_value.As<Object>();
732 Local<Value> js_file = js_options->Get(env()->file_string());
733 r = CopyJsString(js_file, &file_buffer_);
736 uv_process_options_.file = file_buffer_;
738 Local<Value> js_args = js_options->Get(env()->args_string());
739 r = CopyJsStringArray(js_args, &args_buffer_);
742 uv_process_options_.args =
reinterpret_cast<char**
>(args_buffer_);
745 Local<Value> js_cwd = js_options->Get(env()->cwd_string());
747 r = CopyJsString(js_cwd, &cwd_buffer_);
750 uv_process_options_.cwd = cwd_buffer_;
753 Local<Value> js_env_pairs = js_options->Get(env()->env_pairs_string());
754 if (IsSet(js_env_pairs)) {
755 r = CopyJsStringArray(js_env_pairs, &env_buffer_);
759 uv_process_options_.env =
reinterpret_cast<char**
>(env_buffer_);
761 Local<Value> js_uid = js_options->Get(env()->uid_string());
763 CHECK(js_uid->IsInt32());
764 const int32_t uid = js_uid->Int32Value(env()->context()).FromJust();
765 uv_process_options_.uid =
static_cast<uv_uid_t
>(uid);
766 uv_process_options_.flags |= UV_PROCESS_SETUID;
769 Local<Value> js_gid = js_options->Get(env()->gid_string());
771 CHECK(js_gid->IsInt32());
772 const int32_t gid = js_gid->Int32Value(env()->context()).FromJust();
773 uv_process_options_.gid =
static_cast<uv_gid_t
>(gid);
774 uv_process_options_.flags |= UV_PROCESS_SETGID;
777 if (js_options->Get(env()->detached_string())->BooleanValue())
778 uv_process_options_.flags |= UV_PROCESS_DETACHED;
780 Local<String> wba = env()->windows_verbatim_arguments_string();
782 if (js_options->Get(wba)->BooleanValue())
783 uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
785 Local<Value> js_timeout = js_options->Get(env()->timeout_string());
786 if (IsSet(js_timeout)) {
787 CHECK(js_timeout->IsNumber());
788 int64_t timeout = js_timeout->IntegerValue();
789 timeout_ =
static_cast<uint64_t
>(timeout);
792 Local<Value> js_max_buffer = js_options->Get(env()->max_buffer_string());
793 if (IsSet(js_max_buffer)) {
794 CHECK(js_max_buffer->IsNumber());
795 max_buffer_ = js_max_buffer->NumberValue();
798 Local<Value> js_kill_signal = js_options->Get(env()->kill_signal_string());
799 if (IsSet(js_kill_signal)) {
800 CHECK(js_kill_signal->IsInt32());
801 kill_signal_ = js_kill_signal->Int32Value();
804 Local<Value> js_stdio = js_options->Get(env()->stdio_string());
805 r = ParseStdioOptions(js_stdio);
813 int SyncProcessRunner::ParseStdioOptions(Local<Value> js_value) {
814 HandleScope scope(env()->isolate());
815 Local<Array> js_stdio_options;
817 if (!js_value->IsArray())
820 js_stdio_options = js_value.As<Array>();
822 stdio_count_ = js_stdio_options->Length();
823 uv_stdio_containers_ =
new uv_stdio_container_t[stdio_count_];
825 stdio_pipes_ =
new SyncProcessStdioPipe*[stdio_count_]();
826 stdio_pipes_initialized_ =
true;
828 for (uint32_t i = 0; i < stdio_count_; i++) {
829 Local<Value> js_stdio_option = js_stdio_options->Get(i);
831 if (!js_stdio_option->IsObject())
834 int r = ParseStdioOption(i, js_stdio_option.As<Object>());
839 uv_process_options_.stdio = uv_stdio_containers_;
840 uv_process_options_.stdio_count = stdio_count_;
846 int SyncProcessRunner::ParseStdioOption(
int child_fd,
847 Local<Object> js_stdio_option) {
848 Local<Value> js_type = js_stdio_option->Get(env()->type_string());
850 if (js_type->StrictEquals(env()->ignore_string())) {
851 return AddStdioIgnore(child_fd);
853 }
else if (js_type->StrictEquals(env()->pipe_string())) {
854 Local<String> rs = env()->readable_string();
855 Local<String> ws = env()->writable_string();
857 bool readable = js_stdio_option->Get(rs)->BooleanValue();
858 bool writable = js_stdio_option->Get(ws)->BooleanValue();
860 uv_buf_t buf = uv_buf_init(
nullptr, 0);
863 Local<Value> input = js_stdio_option->Get(env()->input_string());
867 }
else if (!input->IsUndefined() && !input->IsNull()) {
875 return AddStdioPipe(child_fd, readable, writable, buf);
877 }
else if (js_type->StrictEquals(env()->inherit_string()) ||
878 js_type->StrictEquals(env()->fd_string())) {
879 int inherit_fd = js_stdio_option->Get(env()->fd_string())->Int32Value();
880 return AddStdioInheritFD(child_fd, inherit_fd);
883 CHECK(0 &&
"invalid child stdio type");
889 int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
890 CHECK_LT(child_fd, stdio_count_);
891 CHECK_EQ(stdio_pipes_[child_fd],
nullptr);
893 uv_stdio_containers_[child_fd].flags = UV_IGNORE;
899 int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
902 uv_buf_t input_buffer) {
903 CHECK_LT(child_fd, stdio_count_);
904 CHECK_EQ(stdio_pipes_[child_fd],
nullptr);
906 SyncProcessStdioPipe* h =
new SyncProcessStdioPipe(
this,
911 int r = h->Initialize(uv_loop_);
917 stdio_pipes_[child_fd] = h;
919 uv_stdio_containers_[child_fd].flags = h->uv_flags();
920 uv_stdio_containers_[child_fd].data.stream = h->uv_stream();
926 int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd,
int inherit_fd) {
927 CHECK_LT(child_fd, stdio_count_);
928 CHECK_EQ(stdio_pipes_[child_fd],
nullptr);
930 uv_stdio_containers_[child_fd].flags = UV_INHERIT_FD;
931 uv_stdio_containers_[child_fd].data.fd = inherit_fd;
937 bool SyncProcessRunner::IsSet(Local<Value> value) {
938 return !value->IsUndefined() && !value->IsNull();
942 int SyncProcessRunner::CopyJsString(Local<Value> js_value,
943 const char** target) {
944 Isolate* isolate = env()->isolate();
945 Local<String> js_string;
946 size_t size, written;
949 if (js_value->IsString())
950 js_string = js_value.As<String>();
952 js_string = js_value->ToString(env()->isolate());
955 size = StringBytes::StorageSize(isolate, js_string,
UTF8) + 1;
957 buffer =
new char[size];
959 written = StringBytes::Write(isolate, buffer, -1, js_string,
UTF8);
960 buffer[written] =
'\0';
967 int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
969 Isolate* isolate = env()->isolate();
970 Local<Array> js_array;
972 size_t list_size, data_size, data_offset;
976 if (!js_value->IsArray())
979 js_array = js_value.As<Array>()->Clone().As<Array>();
980 length = js_array->Length();
984 for (uint32_t i = 0; i < length; i++) {
985 if (!js_array->Get(i)->IsString())
986 js_array->Set(i, js_array->Get(i)->ToString(env()->isolate()));
991 list_size = (length + 1) *
sizeof *list;
996 for (uint32_t i = 0; i < length; i++) {
997 data_size += StringBytes::StorageSize(isolate, js_array->Get(i),
UTF8) + 1;
998 data_size = ROUND_UP(data_size,
sizeof(
void*));
1001 buffer =
new char[list_size + data_size];
1003 list =
reinterpret_cast<char**
>(buffer);
1004 data_offset = list_size;
1006 for (uint32_t i = 0; i < length; i++) {
1007 list[i] = buffer + data_offset;
1008 data_offset += StringBytes::Write(isolate,
1009 buffer + data_offset,
1013 buffer[data_offset++] =
'\0';
1014 data_offset = ROUND_UP(data_offset,
sizeof(
void*));
1017 list[length] =
nullptr;
1024 void SyncProcessRunner::ExitCallback(uv_process_t* handle,
1025 int64_t exit_status,
1027 SyncProcessRunner*
self =
reinterpret_cast<SyncProcessRunner*
>(handle->data);
1028 uv_close(reinterpret_cast<uv_handle_t*>(handle),
nullptr);
1029 self->OnExit(exit_status, term_signal);
1033 void SyncProcessRunner::KillTimerCallback(uv_timer_t* handle) {
1034 SyncProcessRunner*
self =
reinterpret_cast<SyncProcessRunner*
>(handle->data);
1035 self->OnKillTimerTimeout();
1039 void SyncProcessRunner::KillTimerCloseCallback(uv_handle_t* handle) {
bool HasInstance(Local< Value > val)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
size_t Length(Local< Value > val)
const char * signo_string(int signo)
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
char * Data(Local< Value > val)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
int Start(Isolate *isolate, IsolateData *isolate_data, int argc, const char *const *argv, int exec_argc, const char *const *exec_argv)
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)