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

Side by Side Diff: src/d8.cc

Issue 1208733002: Fix cluster-fuzz regression when getting message from Worker (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: don't remove Worker from workers_ on terminate Created 5 years, 6 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/d8-worker.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 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 198
199 #ifndef V8_SHARED 199 #ifndef V8_SHARED
200 CounterMap* Shell::counter_map_; 200 CounterMap* Shell::counter_map_;
201 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; 201 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
202 CounterCollection Shell::local_counters_; 202 CounterCollection Shell::local_counters_;
203 CounterCollection* Shell::counters_ = &local_counters_; 203 CounterCollection* Shell::counters_ = &local_counters_;
204 base::Mutex Shell::context_mutex_; 204 base::Mutex Shell::context_mutex_;
205 const base::TimeTicks Shell::kInitialTicks = 205 const base::TimeTicks Shell::kInitialTicks =
206 base::TimeTicks::HighResolutionNow(); 206 base::TimeTicks::HighResolutionNow();
207 Persistent<Context> Shell::utility_context_; 207 Persistent<Context> Shell::utility_context_;
208 base::Mutex Shell::workers_mutex_;
209 bool Shell::allow_new_workers_ = true;
208 i::List<Worker*> Shell::workers_; 210 i::List<Worker*> Shell::workers_;
209 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; 211 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
210 #endif // !V8_SHARED 212 #endif // !V8_SHARED
211 213
212 Persistent<Context> Shell::evaluation_context_; 214 Persistent<Context> Shell::evaluation_context_;
213 ArrayBuffer::Allocator* Shell::array_buffer_allocator; 215 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
214 ShellOptions Shell::options; 216 ShellOptions Shell::options;
215 const char* Shell::kPrompt = "d8> "; 217 const char* Shell::kPrompt = "d8> ";
216 218
217 #ifndef V8_SHARED 219 #ifndef V8_SHARED
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 688
687 #ifndef V8_SHARED 689 #ifndef V8_SHARED
688 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { 690 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
689 Isolate* isolate = args.GetIsolate(); 691 Isolate* isolate = args.GetIsolate();
690 HandleScope handle_scope(isolate); 692 HandleScope handle_scope(isolate);
691 if (args.Length() < 1 || !args[0]->IsFunction()) { 693 if (args.Length() < 1 || !args[0]->IsFunction()) {
692 Throw(args.GetIsolate(), "1st argument must be function"); 694 Throw(args.GetIsolate(), "1st argument must be function");
693 return; 695 return;
694 } 696 }
695 697
696 Worker* worker = new Worker; 698 {
697 args.This()->SetInternalField(0, External::New(isolate, worker)); 699 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_);
698 workers_.Add(worker); 700 if (!allow_new_workers_) return;
699 701
700 String::Utf8Value function_string(args[0]->ToString()); 702 Worker* worker = new Worker;
701 worker->StartExecuteInThread(isolate, *function_string); 703 args.This()->SetInternalField(0, External::New(isolate, worker));
704 workers_.Add(worker);
705
706 String::Utf8Value function_string(args[0]->ToString());
707 worker->StartExecuteInThread(isolate, *function_string);
708 }
702 } 709 }
703 710
704 711
705 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 712 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
706 Isolate* isolate = args.GetIsolate(); 713 Isolate* isolate = args.GetIsolate();
707 HandleScope handle_scope(isolate); 714 HandleScope handle_scope(isolate);
708 Local<Context> context = isolate->GetCurrentContext(); 715 Local<Context> context = isolate->GetCurrentContext();
709 716
710 if (args.Length() < 1) { 717 if (args.Length() < 1) {
711 Throw(isolate, "Invalid argument"); 718 Throw(isolate, "Invalid argument");
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 HandleScope handle_scope(isolate); 793 HandleScope handle_scope(isolate);
787 Local<Value> this_value = args.This()->GetInternalField(0); 794 Local<Value> this_value = args.This()->GetInternalField(0);
788 if (!this_value->IsExternal()) { 795 if (!this_value->IsExternal()) {
789 Throw(isolate, "this is not a Worker"); 796 Throw(isolate, "this is not a Worker");
790 return; 797 return;
791 } 798 }
792 799
793 Worker* worker = 800 Worker* worker =
794 static_cast<Worker*>(Local<External>::Cast(this_value)->Value()); 801 static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
795 worker->Terminate(); 802 worker->Terminate();
796 workers_.RemoveElement(worker);
797 delete worker;
798 } 803 }
799 #endif // !V8_SHARED 804 #endif // !V8_SHARED
800 805
801 806
802 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { 807 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
803 int exit_code = args[0]->Int32Value(); 808 int exit_code = args[0]->Int32Value();
804 OnExit(args.GetIsolate()); 809 OnExit(args.GetIsolate());
805 exit(exit_code); 810 exit(exit_code);
806 } 811 }
807 812
(...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after
1613 void SerializationDataQueue::Clear() { 1618 void SerializationDataQueue::Clear() {
1614 base::LockGuard<base::Mutex> lock_guard(&mutex_); 1619 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1615 for (int i = 0; i < data_.length(); ++i) { 1620 for (int i = 0; i < data_.length(); ++i) {
1616 delete data_[i]; 1621 delete data_[i];
1617 } 1622 }
1618 data_.Clear(); 1623 data_.Clear();
1619 } 1624 }
1620 1625
1621 1626
1622 Worker::Worker() 1627 Worker::Worker()
1623 : in_semaphore_(0), out_semaphore_(0), thread_(NULL), script_(NULL) {} 1628 : in_semaphore_(0),
1629 out_semaphore_(0),
1630 thread_(NULL),
1631 script_(NULL),
1632 state_(IDLE) {}
1624 1633
1625 1634
1626 Worker::~Worker() { Cleanup(); } 1635 Worker::~Worker() { Cleanup(); }
1627 1636
1628 1637
1629 void Worker::StartExecuteInThread(Isolate* isolate, 1638 void Worker::StartExecuteInThread(Isolate* isolate,
1630 const char* function_string) { 1639 const char* function_string) {
1631 if (thread_) { 1640 DCHECK(base::NoBarrier_Load(&state_) == IDLE);
1632 Throw(isolate, "Only one worker allowed");
1633 return;
1634 }
1635
1636 static const char format[] = "(%s).call(this);"; 1641 static const char format[] = "(%s).call(this);";
1637 size_t len = strlen(function_string) + sizeof(format); 1642 size_t len = strlen(function_string) + sizeof(format);
1638 1643
1639 script_ = new char[len + 1]; 1644 script_ = new char[len + 1];
1640 i::Vector<char> vec(script_, static_cast<int>(len + 1)); 1645 i::Vector<char> vec(script_, static_cast<int>(len + 1));
1641 i::SNPrintF(vec, format, function_string); 1646 i::SNPrintF(vec, format, function_string);
1642 1647
1648 base::NoBarrier_Store(&state_, RUNNING);
1643 thread_ = new WorkerThread(this); 1649 thread_ = new WorkerThread(this);
1644 thread_->Start(); 1650 thread_->Start();
1645 } 1651 }
1646 1652
1647 1653
1648 void Worker::PostMessage(SerializationData* data) { 1654 void Worker::PostMessage(SerializationData* data) {
1649 in_queue_.Enqueue(data); 1655 in_queue_.Enqueue(data);
1650 in_semaphore_.Signal(); 1656 in_semaphore_.Signal();
1651 } 1657 }
1652 1658
1653 1659
1654 SerializationData* Worker::GetMessage() { 1660 SerializationData* Worker::GetMessage() {
1655 SerializationData* data; 1661 SerializationData* data = NULL;
1656 while (!out_queue_.Dequeue(&data)) { 1662 while (!out_queue_.Dequeue(&data)) {
1663 if (base::NoBarrier_Load(&state_) != RUNNING) break;
1657 out_semaphore_.Wait(); 1664 out_semaphore_.Wait();
1658 } 1665 }
1659 1666
1660 return data; 1667 return data;
1661 } 1668 }
1662 1669
1663 1670
1664 void Worker::Terminate() { 1671 void Worker::Terminate() {
1665 if (thread_ == NULL) return; 1672 if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) {
1666 PostMessage(NULL); 1673 // Post NULL to wake the Worker thread message loop.
1667 thread_->Join(); 1674 PostMessage(NULL);
1668 Cleanup(); 1675 thread_->Join();
1676 }
1669 } 1677 }
1670 1678
1671 1679
1672 void Worker::ExecuteInThread() { 1680 void Worker::ExecuteInThread() {
1673 Isolate::CreateParams create_params; 1681 Isolate::CreateParams create_params;
1674 create_params.array_buffer_allocator = Shell::array_buffer_allocator; 1682 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1675 Isolate* isolate = Isolate::New(create_params); 1683 Isolate* isolate = Isolate::New(create_params);
1676 { 1684 {
1677 Isolate::Scope iscope(isolate); 1685 Isolate::Scope iscope(isolate);
1678 { 1686 {
(...skipping 12 matching lines...) Expand all
1691 Handle<Function> postmessage_fun; 1699 Handle<Function> postmessage_fun;
1692 if (postmessage_fun_template->GetFunction(context) 1700 if (postmessage_fun_template->GetFunction(context)
1693 .ToLocal(&postmessage_fun)) { 1701 .ToLocal(&postmessage_fun)) {
1694 global->Set(String::NewFromUtf8(isolate, "postMessage"), 1702 global->Set(String::NewFromUtf8(isolate, "postMessage"),
1695 postmessage_fun); 1703 postmessage_fun);
1696 } 1704 }
1697 1705
1698 // First run the script 1706 // First run the script
1699 Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed"); 1707 Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed");
1700 Handle<String> source = String::NewFromUtf8(isolate, script_); 1708 Handle<String> source = String::NewFromUtf8(isolate, script_);
1701 Shell::ExecuteString(isolate, source, file_name, false, true); 1709 if (Shell::ExecuteString(isolate, source, file_name, true, true)) {
1702 1710 // Get the message handler
1703 // Get the message handler 1711 Handle<Value> onmessage =
1704 Handle<Value> onmessage = 1712 global->Get(String::NewFromUtf8(isolate, "onmessage"));
1705 global->Get(String::NewFromUtf8(isolate, "onmessage")); 1713 if (onmessage->IsFunction()) {
1706 if (onmessage->IsFunction()) { 1714 Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage);
1707 Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage); 1715 // Now wait for messages
1708 // Now wait for messages 1716 bool done = false;
1709 bool done = false; 1717 while (!done) {
1710 while (!done) { 1718 in_semaphore_.Wait();
1711 in_semaphore_.Wait(); 1719 SerializationData* data;
1712 SerializationData* data; 1720 if (!in_queue_.Dequeue(&data)) continue;
1713 if (!in_queue_.Dequeue(&data)) continue; 1721 if (data == NULL) {
1714 if (data == NULL) { 1722 done = true;
1715 done = true; 1723 break;
1716 break; 1724 }
1725 int offset = 0;
1726 Local<Value> data_value;
1727 if (Shell::DeserializeValue(isolate, *data, &offset)
1728 .ToLocal(&data_value)) {
1729 Handle<Value> argv[] = {data_value};
1730 (void)onmessage_fun->Call(context, global, 1, argv);
1731 }
1732 delete data;
1717 } 1733 }
1718 int offset = 0;
1719 Local<Value> data_value;
1720 if (Shell::DeserializeValue(isolate, *data, &offset)
1721 .ToLocal(&data_value)) {
1722 Handle<Value> argv[] = {data_value};
1723 (void)onmessage_fun->Call(context, global, 1, argv);
1724 }
1725 delete data;
1726 } 1734 }
1727 } 1735 }
1728 } 1736 }
1729 } 1737 }
1730 Shell::CollectGarbage(isolate); 1738 Shell::CollectGarbage(isolate);
1731 } 1739 }
1732 isolate->Dispose(); 1740 isolate->Dispose();
1741
1742 if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) {
1743 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1744 out_queue_.Enqueue(NULL);
1745 out_semaphore_.Signal();
1746 }
1733 } 1747 }
1734 1748
1735 1749
1736 void Worker::Cleanup() { 1750 void Worker::Cleanup() {
1737 delete thread_; 1751 delete thread_;
1738 thread_ = NULL; 1752 thread_ = NULL;
1739 delete[] script_; 1753 delete[] script_;
1740 script_ = NULL; 1754 script_ = NULL;
1741 in_queue_.Clear(); 1755 in_queue_.Clear();
1742 out_queue_.Clear(); 1756 out_queue_.Clear();
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after
2185 } 2199 }
2186 default: 2200 default:
2187 UNREACHABLE(); 2201 UNREACHABLE();
2188 } 2202 }
2189 2203
2190 return scope.Escape(result); 2204 return scope.Escape(result);
2191 } 2205 }
2192 2206
2193 2207
2194 void Shell::CleanupWorkers() { 2208 void Shell::CleanupWorkers() {
2195 for (int i = 0; i < workers_.length(); ++i) { 2209 // Make a copy of workers_, because we don't want to call Worker::Terminate
2196 Worker* worker = workers_[i]; 2210 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2211 // create a new Worker, it would deadlock.
2212 i::List<Worker*> workers_copy;
2213 {
2214 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_);
2215 allow_new_workers_ = false;
2216 workers_copy.AddAll(workers_);
2217 workers_.Clear();
2218 }
2219
2220 for (int i = 0; i < workers_copy.length(); ++i) {
2221 Worker* worker = workers_copy[i];
2197 worker->Terminate(); 2222 worker->Terminate();
2198 delete worker; 2223 delete worker;
2199 } 2224 }
2200 workers_.Clear(); 2225
2226 // Now that all workers are terminated, we can re-enable Worker creation.
2227 {
2228 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_);
2229 allow_new_workers_ = true;
2230 }
2201 2231
2202 for (int i = 0; i < externalized_shared_contents_.length(); ++i) { 2232 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2203 const SharedArrayBuffer::Contents& contents = 2233 const SharedArrayBuffer::Contents& contents =
2204 externalized_shared_contents_[i]; 2234 externalized_shared_contents_[i];
2205 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); 2235 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2206 } 2236 }
2207 externalized_shared_contents_.Clear(); 2237 externalized_shared_contents_.Clear();
2208 } 2238 }
2209 2239
2210 2240
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
2399 } 2429 }
2400 2430
2401 } // namespace v8 2431 } // namespace v8
2402 2432
2403 2433
2404 #ifndef GOOGLE3 2434 #ifndef GOOGLE3
2405 int main(int argc, char* argv[]) { 2435 int main(int argc, char* argv[]) {
2406 return v8::Shell::Main(argc, argv); 2436 return v8::Shell::Main(argc, argv);
2407 } 2437 }
2408 #endif 2438 #endif
OLDNEW
« no previous file with comments | « src/d8.h ('k') | test/mjsunit/d8-worker.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698