v8::Platform* g_platform = NULL;
+static Local<Value> Throw(Isolate* isolate, const char* message) {
+ return isolate->ThrowException(
+ String::NewFromUtf8(isolate, message, NewStringType::kNormal)
+ .ToLocalChecked());
+}
+
+
#ifndef V8_SHARED
bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
for (int i = 0; i < list.length(); ++i) {
}
return false;
}
-#endif // !V8_SHARED
-} // namespace
+Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
+ if (object->InternalFieldCount() != 1) {
+ Throw(isolate, "this is not a Worker");
+ return NULL;
+ }
+ Worker* worker =
+ static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
+ if (worker == NULL) {
+ Throw(isolate, "Worker is defunct because main thread is terminating");
+ return NULL;
+ }
-static Local<Value> Throw(Isolate* isolate, const char* message) {
- return isolate->ThrowException(
- String::NewFromUtf8(isolate, message, NewStringType::kNormal)
- .ToLocalChecked());
+ return worker;
}
+#endif // !V8_SHARED
+} // namespace
+
class PerIsolateData {
public:
{
base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
+ // Initialize the internal field to NULL; if we return early without
+ // creating a new Worker (because the main thread is terminating) we can
+ // early-out from the instance calls.
+ args.Holder()->SetAlignedPointerInInternalField(0, NULL);
+
if (!allow_new_workers_) return;
Worker* worker = new Worker;
- args.This()->SetInternalField(0, External::New(isolate, worker));
+ args.Holder()->SetAlignedPointerInInternalField(0, worker);
workers_.Add(worker);
String::Utf8Value script(args[0]);
Throw(args.GetIsolate(), "Can't get worker script");
return;
}
- worker->StartExecuteInThread(isolate, *script);
+ worker->StartExecuteInThread(*script);
}
}
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
Local<Context> context = isolate->GetCurrentContext();
- Local<Value> this_value;
if (args.Length() < 1) {
Throw(isolate, "Invalid argument");
return;
}
- if (args.This()->InternalFieldCount() > 0) {
- this_value = args.This()->GetInternalField(0);
- }
- if (this_value.IsEmpty()) {
- Throw(isolate, "this is not a Worker");
+ Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker) {
return;
}
- Worker* worker =
- static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
-
Local<Value> message = args[0];
ObjectList to_transfer;
if (args.Length() >= 2) {
void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
- Local<Value> this_value;
- if (args.This()->InternalFieldCount() > 0) {
- this_value = args.This()->GetInternalField(0);
- }
- if (this_value.IsEmpty()) {
- Throw(isolate, "this is not a Worker");
+ Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker) {
return;
}
- Worker* worker =
- static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
-
SerializationData* data = worker->GetMessage();
if (data) {
int offset = 0;
void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
- Local<Value> this_value;
- if (args.This()->InternalFieldCount() > 0) {
- this_value = args.This()->GetInternalField(0);
- }
- if (this_value.IsEmpty()) {
- Throw(isolate, "this is not a Worker");
+ Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker) {
return;
}
- Worker* worker =
- static_cast<Worker*>(Local<External>::Cast(this_value)->Value());
worker->Terminate();
}
#endif // !V8_SHARED
Local<FunctionTemplate> worker_fun_template =
FunctionTemplate::New(isolate, WorkerNew);
+ Local<Signature> worker_signature =
+ Signature::New(isolate, worker_fun_template);
+ worker_fun_template->SetClassName(
+ String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
+ .ToLocalChecked());
worker_fun_template->PrototypeTemplate()->Set(
String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
.ToLocalChecked(),
- FunctionTemplate::New(isolate, WorkerTerminate));
+ FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
+ worker_signature));
worker_fun_template->PrototypeTemplate()->Set(
String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
.ToLocalChecked(),
- FunctionTemplate::New(isolate, WorkerPostMessage));
+ FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
+ worker_signature));
worker_fun_template->PrototypeTemplate()->Set(
String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
.ToLocalChecked(),
- FunctionTemplate::New(isolate, WorkerGetMessage));
+ FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
+ worker_signature));
worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
global_template->Set(
String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
out_semaphore_(0),
thread_(NULL),
script_(NULL),
- state_(IDLE),
- join_called_(false) {}
+ running_(false) {}
Worker::~Worker() {
}
-void Worker::StartExecuteInThread(Isolate* isolate, const char* script) {
- if (base::NoBarrier_CompareAndSwap(&state_, IDLE, RUNNING) == IDLE) {
- script_ = i::StrDup(script);
- thread_ = new WorkerThread(this);
- thread_->Start();
- } else {
- // Somehow the Worker was started twice.
- UNREACHABLE();
- }
+void Worker::StartExecuteInThread(const char* script) {
+ running_ = true;
+ script_ = i::StrDup(script);
+ thread_ = new WorkerThread(this);
+ thread_->Start();
}
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;
+ if (!base::NoBarrier_Load(&running_)) break;
out_semaphore_.Wait();
}
return data;
void Worker::Terminate() {
- if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) {
- // Post NULL to wake the Worker thread message loop, and tell it to stop
- // running.
- PostMessage(NULL);
- }
+ base::NoBarrier_Store(&running_, false);
+ // 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();
- }
+ thread_->Join();
}
Worker();
~Worker();
- void StartExecuteInThread(Isolate* isolate, const char* script);
+ // Run the given script on this Worker. This function should only be called
+ // once, and should only be called by the thread that created the Worker.
+ void StartExecuteInThread(const char* script);
// Post a message to the worker's incoming message queue. The worker will
// take ownership of the SerializationData.
+ // This function should only be called by the thread that created the Worker.
void PostMessage(SerializationData* data);
// Synchronously retrieve messages from the worker's outgoing message queue.
// If there is no message in the queue, block until a message is available.
// If there are no messages in the queue and the worker is no longer running,
// return nullptr.
+ // This function should only be called by the thread that created the Worker.
SerializationData* GetMessage();
// Terminate the worker's event loop. Messages from the worker that have been
// queued can still be read via GetMessage().
+ // This function can be called by any thread.
void Terminate();
// Terminate and join the thread.
+ // This function can be called by any thread.
void WaitForThread();
private:
Worker* worker_;
};
- enum State {
- IDLE, // The worker thread hasn't been started yet
- RUNNING, // The worker thread is running and hasn't been terminated
- TERMINATED // The worker thread has been terminated and will soon finish
- };
-
void ExecuteInThread();
static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
SerializationDataQueue out_queue_;
base::Thread* thread_;
char* script_;
- base::Atomic32 state_;
- base::Atomic32 join_called_;
+ base::Atomic32 running_;
};
#endif // !V8_SHARED