OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |