1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "spawn_sync.h"
24 #include "string_bytes.h"
35 using v8::EscapableHandleScope;
36 using v8::FunctionCallbackInfo;
38 using v8::HandleScope;
49 SyncProcessOutputBuffer::SyncProcessOutputBuffer()
55 void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
56 uv_buf_t* buf) const {
57 if (used() == kBufferSize)
58 *buf = uv_buf_init(NULL, 0);
60 *buf = uv_buf_init(data_ + used(), available());
64 void SyncProcessOutputBuffer::OnRead(const uv_buf_t* buf, size_t nread) {
65 // If we hand out the same chunk twice, this should catch it.
66 assert(buf->base == data_ + used());
67 used_ += static_cast<unsigned int>(nread);
71 size_t SyncProcessOutputBuffer::Copy(char* dest) const {
72 memcpy(dest, data_, used());
77 unsigned int SyncProcessOutputBuffer::available() const {
78 return sizeof data_ - used();
82 unsigned int SyncProcessOutputBuffer::used() const {
87 SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
92 void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
97 SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
100 uv_buf_t input_buffer)
101 : process_handler_(process_handler),
104 input_buffer_(input_buffer),
106 first_output_buffer_(NULL),
107 last_output_buffer_(NULL),
113 lifecycle_(kUninitialized) {
114 assert(readable || writable);
118 SyncProcessStdioPipe::~SyncProcessStdioPipe() {
119 assert(lifecycle_ == kUninitialized || lifecycle_ == kClosed);
121 SyncProcessOutputBuffer* buf;
122 SyncProcessOutputBuffer* next;
124 for (buf = first_output_buffer_; buf != NULL; buf = next) {
131 int SyncProcessStdioPipe::Initialize(uv_loop_t* loop) {
132 assert(lifecycle_ == kUninitialized);
134 int r = uv_pipe_init(loop, uv_pipe(), 0);
138 uv_pipe()->data = this;
140 lifecycle_ = kInitialized;
145 int SyncProcessStdioPipe::Start() {
146 assert(lifecycle_ == kInitialized);
148 // Set the busy flag already. If this function fails no recovery is
150 lifecycle_ = kStarted;
153 if (input_buffer_.len > 0) {
154 assert(input_buffer_.base != NULL);
156 int r = uv_write(&write_req_,
165 int r = uv_shutdown(&shutdown_req_, uv_stream(), ShutdownCallback);
171 int r = uv_read_start(uv_stream(), AllocCallback, ReadCallback);
180 void SyncProcessStdioPipe::Close() {
181 assert(lifecycle_ == kInitialized || lifecycle_ == kStarted);
183 uv_close(uv_handle(), CloseCallback);
185 lifecycle_ = kClosing;
189 Local<Object> SyncProcessStdioPipe::GetOutputAsBuffer() const {
190 size_t length = OutputLength();
191 Local<Object> js_buffer = Buffer::New(length);
192 CopyOutput(Buffer::Data(js_buffer));
197 bool SyncProcessStdioPipe::readable() const {
202 bool SyncProcessStdioPipe::writable() const {
207 uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
210 flags = UV_CREATE_PIPE;
212 flags |= UV_READABLE_PIPE;
214 flags |= UV_WRITABLE_PIPE;
216 return static_cast<uv_stdio_flags>(flags);
220 uv_pipe_t* SyncProcessStdioPipe::uv_pipe() const {
221 assert(lifecycle_ < kClosing);
226 uv_stream_t* SyncProcessStdioPipe::uv_stream() const {
227 return reinterpret_cast<uv_stream_t*>(uv_pipe());
231 uv_handle_t* SyncProcessStdioPipe::uv_handle() const {
232 return reinterpret_cast<uv_handle_t*>(uv_pipe());
236 size_t SyncProcessStdioPipe::OutputLength() const {
237 SyncProcessOutputBuffer* buf;
240 for (buf = first_output_buffer_; buf != NULL; buf = buf->next())
247 void SyncProcessStdioPipe::CopyOutput(char* dest) const {
248 SyncProcessOutputBuffer* buf;
251 for (buf = first_output_buffer_; buf != NULL; buf = buf->next())
252 offset += buf->Copy(dest + offset);
256 void SyncProcessStdioPipe::OnAlloc(size_t suggested_size, uv_buf_t* buf) {
257 // This function assumes that libuv will never allocate two buffers for the
258 // same stream at the same time. There's an assert in
259 // SyncProcessOutputBuffer::OnRead that would fail if this assumption was
262 if (last_output_buffer_ == NULL) {
263 // Allocate the first capture buffer.
264 first_output_buffer_ = new SyncProcessOutputBuffer();
265 last_output_buffer_ = first_output_buffer_;
267 } else if (last_output_buffer_->available() == 0) {
268 // The current capture buffer is full so get us a new one.
269 SyncProcessOutputBuffer* buf = new SyncProcessOutputBuffer();
270 last_output_buffer_->set_next(buf);
271 last_output_buffer_ = buf;
274 last_output_buffer_->OnAlloc(suggested_size, buf);
278 void SyncProcessStdioPipe::OnRead(const uv_buf_t* buf, ssize_t nread) {
279 if (nread == UV_EOF) {
280 // Libuv implicitly stops reading on EOF.
282 } else if (nread < 0) {
283 SetError(static_cast<int>(nread));
284 // At some point libuv should really implicitly stop reading on error.
285 uv_read_stop(uv_stream());
288 last_output_buffer_->OnRead(buf, nread);
289 process_handler_->IncrementBufferSizeAndCheckOverflow(nread);
294 void SyncProcessStdioPipe::OnWriteDone(int result) {
300 void SyncProcessStdioPipe::OnShutdownDone(int result) {
306 void SyncProcessStdioPipe::OnClose() {
307 lifecycle_ = kClosed;
311 void SyncProcessStdioPipe::SetError(int error) {
313 process_handler_->SetPipeError(error);
317 void SyncProcessStdioPipe::AllocCallback(uv_handle_t* handle,
318 size_t suggested_size,
320 SyncProcessStdioPipe* self =
321 reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
322 self->OnAlloc(suggested_size, buf);
326 void SyncProcessStdioPipe::ReadCallback(uv_stream_t* stream,
328 const uv_buf_t* buf) {
329 SyncProcessStdioPipe* self =
330 reinterpret_cast<SyncProcessStdioPipe*>(stream->data);
331 self->OnRead(buf, nread);
335 void SyncProcessStdioPipe::WriteCallback(uv_write_t* req, int result) {
336 SyncProcessStdioPipe* self =
337 reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
338 self->OnWriteDone(result);
342 void SyncProcessStdioPipe::ShutdownCallback(uv_shutdown_t* req, int result) {
343 SyncProcessStdioPipe* self =
344 reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
345 self->OnShutdownDone(result);
349 void SyncProcessStdioPipe::CloseCallback(uv_handle_t* handle) {
350 SyncProcessStdioPipe* self =
351 reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
356 void SyncProcessRunner::Initialize(Handle<Object> target,
357 Handle<Value> unused,
358 Handle<Context> context) {
359 NODE_SET_METHOD(target, "spawn", Spawn);
363 void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
364 Isolate* isolate = args.GetIsolate();
365 HandleScope scope(isolate);
366 SyncProcessRunner p(Environment::GetCurrent(isolate));
367 Local<Value> result = p.Run(args[0]);
368 args.GetReturnValue().Set(result);
372 SyncProcessRunner::SyncProcessRunner(Environment* env)
375 kill_signal_(SIGTERM),
380 uv_stdio_containers_(NULL),
382 stdio_pipes_initialized_(false),
384 uv_process_options_(),
393 buffered_output_size_(0),
398 kill_timer_initialized_(false),
403 lifecycle_(kUninitialized),
409 SyncProcessRunner::~SyncProcessRunner() {
410 assert(lifecycle_ == kHandlesClosed);
412 if (stdio_pipes_ != NULL) {
413 for (size_t i = 0; i < stdio_count_; i++) {
414 if (stdio_pipes_[i] != NULL)
415 delete stdio_pipes_[i];
419 delete[] stdio_pipes_;
420 delete[] file_buffer_;
421 delete[] args_buffer_;
422 delete[] cwd_buffer_;
423 delete[] env_buffer_;
424 delete[] uv_stdio_containers_;
428 Environment* SyncProcessRunner::env() const {
433 Local<Object> SyncProcessRunner::Run(Local<Value> options) {
434 EscapableHandleScope scope(env()->isolate());
436 assert(lifecycle_ == kUninitialized);
438 TryInitializeAndRunLoop(options);
439 CloseHandlesAndDeleteLoop();
441 Local<Object> result = BuildResultObject();
443 return scope.Escape(result);
447 void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
450 // There is no recovery from failure inside TryInitializeAndRunLoop - the
451 // only option we'd have is to close all handles and destroy the loop.
452 assert(lifecycle_ == kUninitialized);
453 lifecycle_ = kInitialized;
455 uv_loop_ = new uv_loop_t;
456 if (uv_loop_ == NULL)
457 return SetError(UV_ENOMEM);
458 CHECK_EQ(uv_loop_init(uv_loop_), 0);
460 r = ParseOptions(options);
465 r = uv_timer_init(uv_loop_, &uv_timer_);
469 uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
471 uv_timer_.data = this;
472 kill_timer_initialized_ = true;
474 // Start the timer immediately. If uv_spawn fails then
475 // CloseHandlesAndDeleteLoop() will immediately close the timer handle
476 // which implicitly stops it, so there is no risk that the timeout callback
477 // runs when the process didn't start.
478 r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
483 uv_process_options_.exit_cb = ExitCallback;
484 r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
487 uv_process_.data = this;
489 for (uint32_t i = 0; i < stdio_count_; i++) {
490 SyncProcessStdioPipe* h = stdio_pipes_[i];
494 return SetPipeError(r);
498 r = uv_run(uv_loop_, UV_RUN_DEFAULT);
500 // We can't handle uv_run failure.
503 // If we get here the process should have exited.
504 assert(exit_status_ >= 0);
508 void SyncProcessRunner::CloseHandlesAndDeleteLoop() {
509 assert(lifecycle_ < kHandlesClosed);
511 if (uv_loop_ != NULL) {
515 // Give closing watchers a chance to finish closing and get their close
517 int r = uv_run(uv_loop_, UV_RUN_DEFAULT);
521 CHECK_EQ(uv_loop_close(uv_loop_), 0);
526 // If the loop doesn't exist, neither should any pipes or timers.
527 assert(!stdio_pipes_initialized_);
528 assert(!kill_timer_initialized_);
531 lifecycle_ = kHandlesClosed;
535 void SyncProcessRunner::CloseStdioPipes() {
536 assert(lifecycle_ < kHandlesClosed);
538 if (stdio_pipes_initialized_) {
539 assert(stdio_pipes_ != NULL);
540 assert(uv_loop_ != NULL);
542 for (uint32_t i = 0; i < stdio_count_; i++) {
543 if (stdio_pipes_[i] != NULL)
544 stdio_pipes_[i]->Close();
547 stdio_pipes_initialized_ = false;
552 void SyncProcessRunner::CloseKillTimer() {
553 assert(lifecycle_ < kHandlesClosed);
555 if (kill_timer_initialized_) {
556 assert(timeout_ > 0);
557 assert(uv_loop_ != NULL);
559 uv_handle_t* uv_timer_handle = reinterpret_cast<uv_handle_t*>(&uv_timer_);
560 uv_ref(uv_timer_handle);
561 uv_close(uv_timer_handle, KillTimerCloseCallback);
563 kill_timer_initialized_ = false;
568 void SyncProcessRunner::Kill() {
569 // Only attempt to kill once.
574 // We might get here even if the process we spawned has already exited. This
575 // could happen when our child process spawned another process which
576 // inherited (one of) the stdio pipes. In this case we won't attempt to send
577 // a signal to the process, however we will still close our end of the stdio
578 // pipes so this situation won't make us hang.
579 if (exit_status_ < 0) {
580 int r = uv_process_kill(&uv_process_, kill_signal_);
582 // If uv_kill failed with an error that isn't ESRCH, the user probably
583 // specified an invalid or unsupported signal. Signal this to the user as
584 // and error and kill the process with SIGKILL instead.
585 if (r < 0 && r != UV_ESRCH) {
588 r = uv_process_kill(&uv_process_, SIGKILL);
589 assert(r >= 0 || r == UV_ESRCH);
593 // Close all stdio pipes.
596 // Stop the timeout timer immediately.
601 void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
602 buffered_output_size_ += length;
604 if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
605 SetError(UV_ENOBUFS);
611 void SyncProcessRunner::OnExit(int64_t exit_status, int term_signal) {
613 return SetError(static_cast<int>(exit_status));
615 exit_status_ = exit_status;
616 term_signal_ = term_signal;
620 void SyncProcessRunner::OnKillTimerTimeout(int status) {
622 SetError(UV_ETIMEDOUT);
627 int SyncProcessRunner::GetError() {
635 void SyncProcessRunner::SetError(int error) {
641 void SyncProcessRunner::SetPipeError(int pipe_error) {
642 if (pipe_error_ == 0)
643 pipe_error_ = pipe_error;
647 Local<Object> SyncProcessRunner::BuildResultObject() {
648 EscapableHandleScope scope(env()->isolate());
650 Local<Object> js_result = Object::New(env()->isolate());
652 if (GetError() != 0) {
653 js_result->Set(env()->error_string(),
654 Integer::New(env()->isolate(), GetError()));
657 if (exit_status_ >= 0)
658 js_result->Set(env()->status_string(),
659 Number::New(env()->isolate(), static_cast<double>(exit_status_)));
661 // If exit_status_ < 0 the process was never started because of some error.
662 js_result->Set(env()->status_string(), Null(env()->isolate()));
664 if (term_signal_ > 0)
665 js_result->Set(env()->signal_string(),
666 String::NewFromUtf8(env()->isolate(), signo_string(term_signal_)));
668 js_result->Set(env()->signal_string(), Null(env()->isolate()));
670 if (exit_status_ >= 0)
671 js_result->Set(env()->output_string(), BuildOutputArray());
673 js_result->Set(env()->output_string(), Null(env()->isolate()));
675 js_result->Set(env()->pid_string(),
676 Number::New(env()->isolate(), uv_process_.pid));
678 return scope.Escape(js_result);
682 Local<Array> SyncProcessRunner::BuildOutputArray() {
683 assert(lifecycle_ >= kInitialized);
684 assert(stdio_pipes_ != NULL);
686 EscapableHandleScope scope(env()->isolate());
687 Local<Array> js_output = Array::New(env()->isolate(), stdio_count_);
689 for (uint32_t i = 0; i < stdio_count_; i++) {
690 SyncProcessStdioPipe* h = stdio_pipes_[i];
691 if (h != NULL && h->writable())
692 js_output->Set(i, h->GetOutputAsBuffer());
694 js_output->Set(i, Null(env()->isolate()));
697 return scope.Escape(js_output);
701 int SyncProcessRunner::ParseOptions(Local<Value> js_value) {
702 HandleScope scope(env()->isolate());
705 if (!js_value->IsObject())
708 Local<Object> js_options = js_value.As<Object>();
710 Local<Value> js_file = js_options->Get(env()->file_string());
711 r = CopyJsString(js_file, &file_buffer_);
714 uv_process_options_.file = file_buffer_;
716 Local<Value> js_args = js_options->Get(env()->args_string());
717 r = CopyJsStringArray(js_args, &args_buffer_);
720 uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
723 Local<Value> js_cwd = js_options->Get(env()->cwd_string());
725 r = CopyJsString(js_cwd, &uv_process_options_.cwd);
728 uv_process_options_.cwd = cwd_buffer_;
731 Local<Value> js_env_pairs = js_options->Get(env()->env_pairs_string());
732 if (IsSet(js_env_pairs)) {
733 r = CopyJsStringArray(js_env_pairs, &env_buffer_);
736 uv_process_options_.args = reinterpret_cast<char**>(env_buffer_);
739 Local<Value> js_uid = js_options->Get(env()->uid_string());
741 if (!CheckRange<uv_uid_t>(js_uid))
743 uv_process_options_.uid = static_cast<uv_gid_t>(js_uid->Int32Value());
744 uv_process_options_.flags |= UV_PROCESS_SETUID;
747 Local<Value> js_gid = js_options->Get(env()->gid_string());
749 if (!CheckRange<uv_gid_t>(js_gid))
751 uv_process_options_.gid = static_cast<uv_gid_t>(js_gid->Int32Value());
752 uv_process_options_.flags |= UV_PROCESS_SETGID;
755 if (js_options->Get(env()->detached_string())->BooleanValue())
756 uv_process_options_.flags |= UV_PROCESS_DETACHED;
758 Local<String> wba = env()->windows_verbatim_arguments_string();
760 if (js_options->Get(wba)->BooleanValue())
761 uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
763 Local<Value> js_timeout = js_options->Get(env()->timeout_string());
764 if (IsSet(js_timeout)) {
765 if (!js_timeout->IsNumber())
767 int64_t timeout = js_timeout->IntegerValue();
770 timeout_ = static_cast<uint64_t>(timeout);
773 Local<Value> js_max_buffer = js_options->Get(env()->max_buffer_string());
774 if (IsSet(js_max_buffer)) {
775 if (!CheckRange<uint32_t>(js_max_buffer))
777 max_buffer_ = js_max_buffer->Uint32Value();
780 Local<Value> js_kill_signal = js_options->Get(env()->kill_signal_string());
781 if (IsSet(js_kill_signal)) {
782 if (!js_kill_signal->IsInt32())
784 kill_signal_ = js_kill_signal->Int32Value();
785 if (kill_signal_ == 0)
789 Local<Value> js_stdio = js_options->Get(env()->stdio_string());
790 r = ParseStdioOptions(js_stdio);
798 int SyncProcessRunner::ParseStdioOptions(Local<Value> js_value) {
799 HandleScope scope(env()->isolate());
800 Local<Array> js_stdio_options;
802 if (!js_value->IsArray())
805 js_stdio_options = js_value.As<Array>();
807 stdio_count_ = js_stdio_options->Length();
808 uv_stdio_containers_ = new uv_stdio_container_t[stdio_count_];
810 stdio_pipes_ = new SyncProcessStdioPipe*[stdio_count_]();
811 stdio_pipes_initialized_ = true;
813 for (uint32_t i = 0; i < stdio_count_; i++) {
814 Local<Value> js_stdio_option = js_stdio_options->Get(i);
816 if (!js_stdio_option->IsObject())
819 int r = ParseStdioOption(i, js_stdio_option.As<Object>());
824 uv_process_options_.stdio = uv_stdio_containers_;
825 uv_process_options_.stdio_count = stdio_count_;
831 int SyncProcessRunner::ParseStdioOption(int child_fd,
832 Local<Object> js_stdio_option) {
833 Local<Value> js_type = js_stdio_option->Get(env()->type_string());
835 if (js_type->StrictEquals(env()->ignore_string())) {
836 return AddStdioIgnore(child_fd);
838 } else if (js_type->StrictEquals(env()->pipe_string())) {
839 Local<String> rs = env()->readable_string();
840 Local<String> ws = env()->writable_string();
842 bool readable = js_stdio_option->Get(rs)->BooleanValue();
843 bool writable = js_stdio_option->Get(ws)->BooleanValue();
845 uv_buf_t buf = uv_buf_init(NULL, 0);
848 Local<Value> input = js_stdio_option->Get(env()->input_string());
849 if (Buffer::HasInstance(input)) {
850 buf = uv_buf_init(Buffer::Data(input),
851 static_cast<unsigned int>(Buffer::Length(input)));
852 } else if (!input->IsUndefined() && !input->IsNull()) {
853 // Strings, numbers etc. are currently unsupported. It's not possible
854 // to create a buffer for them here because there is no way to free
860 return AddStdioPipe(child_fd, readable, writable, buf);
862 } else if (js_type->StrictEquals(env()->inherit_string()) ||
863 js_type->StrictEquals(env()->fd_string())) {
864 int inherit_fd = js_stdio_option->Get(env()->fd_string())->Int32Value();
865 return AddStdioInheritFD(child_fd, inherit_fd);
868 assert(0 && "invalid child stdio type");
874 int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
875 assert(child_fd < stdio_count_);
876 assert(stdio_pipes_[child_fd] == NULL);
878 uv_stdio_containers_[child_fd].flags = UV_IGNORE;
884 int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
887 uv_buf_t input_buffer) {
888 assert(child_fd < stdio_count_);
889 assert(stdio_pipes_[child_fd] == NULL);
891 SyncProcessStdioPipe* h = new SyncProcessStdioPipe(this,
896 int r = h->Initialize(uv_loop_);
902 stdio_pipes_[child_fd] = h;
904 uv_stdio_containers_[child_fd].flags = h->uv_flags();
905 uv_stdio_containers_[child_fd].data.stream = h->uv_stream();
911 int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) {
912 assert(child_fd < stdio_count_);
913 assert(stdio_pipes_[child_fd] == NULL);
915 uv_stdio_containers_[child_fd].flags = UV_INHERIT_FD;
916 uv_stdio_containers_[child_fd].data.fd = inherit_fd;
922 bool SyncProcessRunner::IsSet(Local<Value> value) {
923 return !value->IsUndefined() && !value->IsNull();
927 template <typename t>
928 bool SyncProcessRunner::CheckRange(Local<Value> js_value) {
930 // Unsigned range check.
931 if (!js_value->IsUint32())
933 if (js_value->Uint32Value() & ~((t) ~0))
937 // Signed range check.
938 if (!js_value->IsInt32())
940 if (js_value->Int32Value() & ~((t) ~0))
948 int SyncProcessRunner::CopyJsString(Local<Value> js_value,
949 const char** target) {
950 Isolate* isolate = env()->isolate();
951 Local<String> js_string;
952 size_t size, written;
955 if (js_value->IsString())
956 js_string = js_value.As<String>();
958 js_string = js_value->ToString();
960 // Include space for null terminator byte.
961 size = StringBytes::StorageSize(isolate, js_string, UTF8) + 1;
963 buffer = new char[size];
965 written = StringBytes::Write(isolate, buffer, -1, js_string, UTF8);
966 buffer[written] = '\0';
973 int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
975 Isolate* isolate = env()->isolate();
976 Local<Array> js_array;
978 size_t list_size, data_size, data_offset;
982 if (!js_value->IsArray())
985 js_array = js_value.As<Array>()->Clone().As<Array>();
986 length = js_array->Length();
988 // Convert all array elements to string. Modify the js object itself if
989 // needed - it's okay since we cloned the original object.
990 for (uint32_t i = 0; i < length; i++) {
991 if (!js_array->Get(i)->IsString())
992 js_array->Set(i, js_array->Get(i)->ToString());
995 // Index has a pointer to every string element, plus one more for a final
997 list_size = (length + 1) * sizeof *list;
999 // Compute the length of all strings. Include room for null terminator
1000 // after every string. Align strings to cache lines.
1002 for (uint32_t i = 0; i < length; i++) {
1003 data_size += StringBytes::StorageSize(isolate, js_array->Get(i), UTF8) + 1;
1004 data_size = ROUND_UP(data_size, sizeof(void*)); // NOLINT(runtime/sizeof)
1007 buffer = new char[list_size + data_size];
1009 list = reinterpret_cast<char**>(buffer);
1010 data_offset = list_size;
1012 for (uint32_t i = 0; i < length; i++) {
1013 list[i] = buffer + data_offset;
1014 data_offset += StringBytes::Write(isolate,
1015 buffer + data_offset,
1019 buffer[data_offset++] = '\0';
1020 data_offset = ROUND_UP(data_offset,
1021 sizeof(void*)); // NOLINT(runtime/sizeof)
1024 list[length] = NULL;
1031 void SyncProcessRunner::ExitCallback(uv_process_t* handle,
1032 int64_t exit_status,
1034 SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1035 uv_close(reinterpret_cast<uv_handle_t*>(handle), NULL);
1036 self->OnExit(exit_status, term_signal);
1040 void SyncProcessRunner::KillTimerCallback(uv_timer_t* handle, int status) {
1041 SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1042 self->OnKillTimerTimeout(status);
1046 void SyncProcessRunner::KillTimerCloseCallback(uv_handle_t* handle) {
1052 NODE_MODULE_CONTEXT_AWARE_BUILTIN(spawn_sync,
1053 node::SyncProcessRunner::Initialize)