Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: src/d8.cc

Issue 1255563002: [d8 Workers] Fix bug creating Worker during main thread termination (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: typo Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/d8.h ('k') | test/mjsunit/regress/regress-crbug-511880.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 5
6 // Defined when linking against shared lib on Windows. 6 // Defined when linking against shared lib on Windows.
7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED) 7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED)
8 #define V8_SHARED 8 #define V8_SHARED
9 #endif 9 #endif
10 10
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 void* AllocateUninitialized(size_t length) override { 98 void* AllocateUninitialized(size_t length) override {
99 return length > 10 * MB ? malloc(1) : malloc(length); 99 return length > 10 * MB ? malloc(1) : malloc(length);
100 } 100 }
101 void Free(void* p, size_t) override { free(p); } 101 void Free(void* p, size_t) override { free(p); }
102 }; 102 };
103 103
104 104
105 v8::Platform* g_platform = NULL; 105 v8::Platform* g_platform = NULL;
106 106
107 107
108 static Local<Value> Throw(Isolate* isolate, const char* message) {
109 return isolate->ThrowException(
110 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
111 .ToLocalChecked());
112 }
113
114
108 #ifndef V8_SHARED 115 #ifndef V8_SHARED
109 bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) { 116 bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
110 for (int i = 0; i < list.length(); ++i) { 117 for (int i = 0; i < list.length(); ++i) {
111 if (list[i]->StrictEquals(object)) { 118 if (list[i]->StrictEquals(object)) {
112 return true; 119 return true;
113 } 120 }
114 } 121 }
115 return false; 122 return false;
116 } 123 }
124
125
126 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
127 if (object->InternalFieldCount() != 1) {
128 Throw(isolate, "this is not a Worker");
129 return NULL;
130 }
131
132 Worker* worker =
133 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
134 if (worker == NULL) {
135 Throw(isolate, "Worker is defunct because main thread is terminating");
136 return NULL;
137 }
138
139 return worker;
140 }
117 #endif // !V8_SHARED 141 #endif // !V8_SHARED
118 142
119 143
120 } // namespace 144 } // namespace
121 145
122 146
123 static Local<Value> Throw(Isolate* isolate, const char* message) {
124 return isolate->ThrowException(
125 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
126 .ToLocalChecked());
127 }
128
129
130
131 class PerIsolateData { 147 class PerIsolateData {
132 public: 148 public:
133 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) { 149 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
134 HandleScope scope(isolate); 150 HandleScope scope(isolate);
135 isolate->SetData(0, this); 151 isolate->SetData(0, this);
136 } 152 }
137 153
138 ~PerIsolateData() { 154 ~PerIsolateData() {
139 isolate_->SetData(0, NULL); // Not really needed, just to be sure... 155 isolate_->SetData(0, NULL); // Not really needed, just to be sure...
140 } 156 }
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { 695 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
680 Isolate* isolate = args.GetIsolate(); 696 Isolate* isolate = args.GetIsolate();
681 HandleScope handle_scope(isolate); 697 HandleScope handle_scope(isolate);
682 if (args.Length() < 1 || !args[0]->IsString()) { 698 if (args.Length() < 1 || !args[0]->IsString()) {
683 Throw(args.GetIsolate(), "1st argument must be string"); 699 Throw(args.GetIsolate(), "1st argument must be string");
684 return; 700 return;
685 } 701 }
686 702
687 { 703 {
688 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); 704 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
705 // Initialize the internal field to NULL; if we return early without
706 // creating a new Worker (because the main thread is terminating) we can
707 // early-out from the instance calls.
708 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
709
689 if (!allow_new_workers_) return; 710 if (!allow_new_workers_) return;
690 711
691 Worker* worker = new Worker; 712 Worker* worker = new Worker;
692 args.This()->SetInternalField(0, External::New(isolate, worker)); 713 args.Holder()->SetAlignedPointerInInternalField(0, worker);
693 workers_.Add(worker); 714 workers_.Add(worker);
694 715
695 String::Utf8Value script(args[0]); 716 String::Utf8Value script(args[0]);
696 if (!*script) { 717 if (!*script) {
697 Throw(args.GetIsolate(), "Can't get worker script"); 718 Throw(args.GetIsolate(), "Can't get worker script");
698 return; 719 return;
699 } 720 }
700 worker->StartExecuteInThread(isolate, *script); 721 worker->StartExecuteInThread(*script);
701 } 722 }
702 } 723 }
703 724
704 725
705 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 726 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
706 Isolate* isolate = args.GetIsolate(); 727 Isolate* isolate = args.GetIsolate();
707 HandleScope handle_scope(isolate); 728 HandleScope handle_scope(isolate);
708 Local<Context> context = isolate->GetCurrentContext(); 729 Local<Context> context = isolate->GetCurrentContext();
709 Local<Value> this_value;
710 730
711 if (args.Length() < 1) { 731 if (args.Length() < 1) {
712 Throw(isolate, "Invalid argument"); 732 Throw(isolate, "Invalid argument");
713 return; 733 return;
714 } 734 }
715 735
716 if (args.This()->InternalFieldCount() > 0) { 736 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
717 this_value = args.This()->GetInternalField(0); 737 if (!worker) {
718 }
719 if (this_value.IsEmpty()) {
720 Throw(isolate, "this is not a Worker");
721 return; 738 return;
722 } 739 }
723 740
724 Worker* worker =
725 static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
726
727 Local<Value> message = args[0]; 741 Local<Value> message = args[0];
728 ObjectList to_transfer; 742 ObjectList to_transfer;
729 if (args.Length() >= 2) { 743 if (args.Length() >= 2) {
730 if (!args[1]->IsArray()) { 744 if (!args[1]->IsArray()) {
731 Throw(isolate, "Transfer list must be an Array"); 745 Throw(isolate, "Transfer list must be an Array");
732 return; 746 return;
733 } 747 }
734 748
735 Local<Array> transfer = Local<Array>::Cast(args[1]); 749 Local<Array> transfer = Local<Array>::Cast(args[1]);
736 uint32_t length = transfer->Length(); 750 uint32_t length = transfer->Length();
(...skipping 18 matching lines...) Expand all
755 worker->PostMessage(data); 769 worker->PostMessage(data);
756 } else { 770 } else {
757 delete data; 771 delete data;
758 } 772 }
759 } 773 }
760 774
761 775
762 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 776 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
763 Isolate* isolate = args.GetIsolate(); 777 Isolate* isolate = args.GetIsolate();
764 HandleScope handle_scope(isolate); 778 HandleScope handle_scope(isolate);
765 Local<Value> this_value; 779 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
766 if (args.This()->InternalFieldCount() > 0) { 780 if (!worker) {
767 this_value = args.This()->GetInternalField(0);
768 }
769 if (this_value.IsEmpty()) {
770 Throw(isolate, "this is not a Worker");
771 return; 781 return;
772 } 782 }
773 783
774 Worker* worker =
775 static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
776
777 SerializationData* data = worker->GetMessage(); 784 SerializationData* data = worker->GetMessage();
778 if (data) { 785 if (data) {
779 int offset = 0; 786 int offset = 0;
780 Local<Value> data_value; 787 Local<Value> data_value;
781 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) { 788 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
782 args.GetReturnValue().Set(data_value); 789 args.GetReturnValue().Set(data_value);
783 } 790 }
784 delete data; 791 delete data;
785 } 792 }
786 } 793 }
787 794
788 795
789 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { 796 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
790 Isolate* isolate = args.GetIsolate(); 797 Isolate* isolate = args.GetIsolate();
791 HandleScope handle_scope(isolate); 798 HandleScope handle_scope(isolate);
792 Local<Value> this_value; 799 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
793 if (args.This()->InternalFieldCount() > 0) { 800 if (!worker) {
794 this_value = args.This()->GetInternalField(0);
795 }
796 if (this_value.IsEmpty()) {
797 Throw(isolate, "this is not a Worker");
798 return; 801 return;
799 } 802 }
800 803
801 Worker* worker =
802 static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
803 worker->Terminate(); 804 worker->Terminate();
804 } 805 }
805 #endif // !V8_SHARED 806 #endif // !V8_SHARED
806 807
807 808
808 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) { 809 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
809 int exit_code = (*args)[0] 810 int exit_code = (*args)[0]
810 ->Int32Value(args->GetIsolate()->GetCurrentContext()) 811 ->Int32Value(args->GetIsolate()->GetCurrentContext())
811 .FromMaybe(0); 812 .FromMaybe(0);
812 #ifndef V8_SHARED 813 #ifndef V8_SHARED
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
1127 String::NewFromUtf8(isolate, "now", NewStringType::kNormal) 1128 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1128 .ToLocalChecked(), 1129 .ToLocalChecked(),
1129 FunctionTemplate::New(isolate, PerformanceNow)); 1130 FunctionTemplate::New(isolate, PerformanceNow));
1130 global_template->Set( 1131 global_template->Set(
1131 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal) 1132 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1132 .ToLocalChecked(), 1133 .ToLocalChecked(),
1133 performance_template); 1134 performance_template);
1134 1135
1135 Local<FunctionTemplate> worker_fun_template = 1136 Local<FunctionTemplate> worker_fun_template =
1136 FunctionTemplate::New(isolate, WorkerNew); 1137 FunctionTemplate::New(isolate, WorkerNew);
1138 Local<Signature> worker_signature =
1139 Signature::New(isolate, worker_fun_template);
1140 worker_fun_template->SetClassName(
1141 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1142 .ToLocalChecked());
1137 worker_fun_template->PrototypeTemplate()->Set( 1143 worker_fun_template->PrototypeTemplate()->Set(
1138 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal) 1144 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1139 .ToLocalChecked(), 1145 .ToLocalChecked(),
1140 FunctionTemplate::New(isolate, WorkerTerminate)); 1146 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1147 worker_signature));
1141 worker_fun_template->PrototypeTemplate()->Set( 1148 worker_fun_template->PrototypeTemplate()->Set(
1142 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal) 1149 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1143 .ToLocalChecked(), 1150 .ToLocalChecked(),
1144 FunctionTemplate::New(isolate, WorkerPostMessage)); 1151 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1152 worker_signature));
1145 worker_fun_template->PrototypeTemplate()->Set( 1153 worker_fun_template->PrototypeTemplate()->Set(
1146 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal) 1154 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1147 .ToLocalChecked(), 1155 .ToLocalChecked(),
1148 FunctionTemplate::New(isolate, WorkerGetMessage)); 1156 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1157 worker_signature));
1149 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1); 1158 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1150 global_template->Set( 1159 global_template->Set(
1151 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal) 1160 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1152 .ToLocalChecked(), 1161 .ToLocalChecked(),
1153 worker_fun_template); 1162 worker_fun_template);
1154 #endif // !V8_SHARED 1163 #endif // !V8_SHARED
1155 1164
1156 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate); 1165 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
1157 AddOSMethods(isolate, os_templ); 1166 AddOSMethods(isolate, os_templ);
1158 global_template->Set( 1167 global_template->Set(
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after
1637 } 1646 }
1638 data_.Clear(); 1647 data_.Clear();
1639 } 1648 }
1640 1649
1641 1650
1642 Worker::Worker() 1651 Worker::Worker()
1643 : in_semaphore_(0), 1652 : in_semaphore_(0),
1644 out_semaphore_(0), 1653 out_semaphore_(0),
1645 thread_(NULL), 1654 thread_(NULL),
1646 script_(NULL), 1655 script_(NULL),
1647 state_(IDLE), 1656 running_(false) {}
1648 join_called_(false) {}
1649 1657
1650 1658
1651 Worker::~Worker() { 1659 Worker::~Worker() {
1652 delete thread_; 1660 delete thread_;
1653 thread_ = NULL; 1661 thread_ = NULL;
1654 delete[] script_; 1662 delete[] script_;
1655 script_ = NULL; 1663 script_ = NULL;
1656 in_queue_.Clear(); 1664 in_queue_.Clear();
1657 out_queue_.Clear(); 1665 out_queue_.Clear();
1658 } 1666 }
1659 1667
1660 1668
1661 void Worker::StartExecuteInThread(Isolate* isolate, const char* script) { 1669 void Worker::StartExecuteInThread(const char* script) {
1662 if (base::NoBarrier_CompareAndSwap(&state_, IDLE, RUNNING) == IDLE) { 1670 running_ = true;
1663 script_ = i::StrDup(script); 1671 script_ = i::StrDup(script);
1664 thread_ = new WorkerThread(this); 1672 thread_ = new WorkerThread(this);
1665 thread_->Start(); 1673 thread_->Start();
1666 } else {
1667 // Somehow the Worker was started twice.
1668 UNREACHABLE();
1669 }
1670 } 1674 }
1671 1675
1672 1676
1673 void Worker::PostMessage(SerializationData* data) { 1677 void Worker::PostMessage(SerializationData* data) {
1674 in_queue_.Enqueue(data); 1678 in_queue_.Enqueue(data);
1675 in_semaphore_.Signal(); 1679 in_semaphore_.Signal();
1676 } 1680 }
1677 1681
1678 1682
1679 SerializationData* Worker::GetMessage() { 1683 SerializationData* Worker::GetMessage() {
1680 SerializationData* data = NULL; 1684 SerializationData* data = NULL;
1681 while (!out_queue_.Dequeue(&data)) { 1685 while (!out_queue_.Dequeue(&data)) {
1682 // If the worker is no longer running, and there are no messages in the 1686 // If the worker is no longer running, and there are no messages in the
1683 // queue, don't expect any more messages from it. 1687 // queue, don't expect any more messages from it.
1684 if (base::NoBarrier_Load(&state_) != RUNNING) break; 1688 if (!base::NoBarrier_Load(&running_)) break;
1685 out_semaphore_.Wait(); 1689 out_semaphore_.Wait();
1686 } 1690 }
1687 return data; 1691 return data;
1688 } 1692 }
1689 1693
1690 1694
1691 void Worker::Terminate() { 1695 void Worker::Terminate() {
1692 if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) { 1696 base::NoBarrier_Store(&running_, false);
1693 // Post NULL to wake the Worker thread message loop, and tell it to stop 1697 // Post NULL to wake the Worker thread message loop, and tell it to stop
1694 // running. 1698 // running.
1695 PostMessage(NULL); 1699 PostMessage(NULL);
1696 }
1697 } 1700 }
1698 1701
1699 1702
1700 void Worker::WaitForThread() { 1703 void Worker::WaitForThread() {
1701 Terminate(); 1704 Terminate();
1702 1705 thread_->Join();
1703 if (base::NoBarrier_CompareAndSwap(&join_called_, false, true) == false) {
1704 thread_->Join();
1705 } else {
1706 // Tried to call join twice.
1707 UNREACHABLE();
1708 }
1709 } 1706 }
1710 1707
1711 1708
1712 void Worker::ExecuteInThread() { 1709 void Worker::ExecuteInThread() {
1713 Isolate::CreateParams create_params; 1710 Isolate::CreateParams create_params;
1714 create_params.array_buffer_allocator = Shell::array_buffer_allocator; 1711 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1715 Isolate* isolate = Isolate::New(create_params); 1712 Isolate* isolate = Isolate::New(create_params);
1716 { 1713 {
1717 Isolate::Scope iscope(isolate); 1714 Isolate::Scope iscope(isolate);
1718 { 1715 {
(...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after
2454 } 2451 }
2455 2452
2456 } // namespace v8 2453 } // namespace v8
2457 2454
2458 2455
2459 #ifndef GOOGLE3 2456 #ifndef GOOGLE3
2460 int main(int argc, char* argv[]) { 2457 int main(int argc, char* argv[]) {
2461 return v8::Shell::Main(argc, argv); 2458 return v8::Shell::Main(argc, argv);
2462 } 2459 }
2463 #endif 2460 #endif
OLDNEW
« no previous file with comments | « src/d8.h ('k') | test/mjsunit/regress/regress-crbug-511880.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698