Index: src/d8.cc |
diff --git a/src/d8.cc b/src/d8.cc |
index 83bbd7e20f79933fea1539790e665dcfccf283da..2b1832a28e6c7e5ccba73900cebfc0346d8851f5 100644 |
--- a/src/d8.cc |
+++ b/src/d8.cc |
@@ -19,6 +19,7 @@ |
#ifndef V8_SHARED |
#include <algorithm> |
+#include <vector> |
#endif // !V8_SHARED |
#ifdef V8_SHARED |
@@ -1612,6 +1613,7 @@ void SerializationDataQueue::Enqueue(SerializationData* data) { |
bool SerializationDataQueue::Dequeue(SerializationData** data) { |
base::LockGuard<base::Mutex> lock_guard(&mutex_); |
+ *data = NULL; |
if (data_.is_empty()) return false; |
*data = data_.Remove(0); |
return true; |
@@ -1638,7 +1640,8 @@ Worker::Worker() |
out_semaphore_(0), |
thread_(NULL), |
script_(NULL), |
- state_(IDLE) {} |
+ state_(IDLE), |
+ join_called_(false) {} |
Worker::~Worker() { Cleanup(); } |
@@ -1665,6 +1668,8 @@ void Worker::PostMessage(SerializationData* data) { |
SerializationData* Worker::GetMessage() { |
SerializationData* data = NULL; |
while (!out_queue_.Dequeue(&data)) { |
+ // If the worker is no longer running, and there are no messages in the |
+ // queue, don't expect any more messages from it. |
if (base::NoBarrier_Load(&state_) != RUNNING) break; |
out_semaphore_.Wait(); |
} |
@@ -1675,9 +1680,21 @@ SerializationData* Worker::GetMessage() { |
void Worker::Terminate() { |
if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) { |
- // Post NULL to wake the Worker thread message loop. |
+ // Post NULL to wake the Worker thread message loop, and tell it to stop |
+ // running. |
PostMessage(NULL); |
+ } |
+} |
+ |
+ |
+void Worker::WaitForThread() { |
+ Terminate(); |
+ |
+ if (base::NoBarrier_CompareAndSwap(&join_called_, false, true) == false) { |
thread_->Join(); |
+ } else { |
+ // Tried to call join twice. |
+ UNREACHABLE(); |
} |
} |
@@ -1718,13 +1735,11 @@ void Worker::ExecuteInThread() { |
if (onmessage->IsFunction()) { |
Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage); |
// Now wait for messages |
- bool done = false; |
- while (!done) { |
+ while (true) { |
in_semaphore_.Wait(); |
SerializationData* data; |
if (!in_queue_.Dequeue(&data)) continue; |
if (data == NULL) { |
- done = true; |
break; |
} |
int offset = 0; |
@@ -1744,11 +1759,9 @@ void Worker::ExecuteInThread() { |
} |
isolate->Dispose(); |
- if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) { |
- // Post NULL to wake the thread waiting on GetMessage() if there is one. |
- out_queue_.Enqueue(NULL); |
- out_semaphore_.Signal(); |
- } |
+ // Post NULL to wake the thread waiting on GetMessage() if there is one. |
+ out_queue_.Enqueue(NULL); |
+ out_semaphore_.Signal(); |
} |
@@ -2146,18 +2159,12 @@ MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate, |
break; |
case kSerializationTagString: { |
int length = data.Read<int>(offset); |
- static char s_buffer[128]; |
- char* p = s_buffer; |
- bool allocated = false; |
- if (length > static_cast<int>(sizeof(s_buffer))) { |
- p = new char[length]; |
- allocated = true; |
- } |
- data.ReadMemory(p, length, offset); |
- MaybeLocal<String> str = |
- String::NewFromUtf8(isolate, p, String::kNormalString, length); |
+ CHECK(length >= 0); |
+ std::vector<char> buffer(length + 1); // + 1 so it is never empty. |
+ data.ReadMemory(&buffer[0], length, offset); |
+ MaybeLocal<String> str = String::NewFromUtf8( |
+ isolate, &buffer[0], String::kNormalString, length); |
if (!str.IsEmpty()) result = str.ToLocalChecked(); |
- if (allocated) delete[] p; |
break; |
} |
case kSerializationTagArray: { |
@@ -2229,7 +2236,7 @@ void Shell::CleanupWorkers() { |
for (int i = 0; i < workers_copy.length(); ++i) { |
Worker* worker = workers_copy[i]; |
- worker->Terminate(); |
+ worker->WaitForThread(); |
delete worker; |
} |