-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add WebWorker API #1261
Closed
Closed
[WIP] Add WebWorker API #1261
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
f02ff21
define WebWorker on isolate
bartlomieju e3e1908
format
bartlomieju 6ba0106
start porting WorkerNew
bartlomieju 48a3977
update BUILD.gn with worker files
bartlomieju b52c00a
remove String forward declaration error
bartlomieju c21f552
use Deno Worker
bartlomieju 03e3a4c
copy copyright from V8
bartlomieju a8ca36a
remove FOpen, ReadChars
bartlomieju 28ec6eb
remove unused static
bartlomieju 8e9c36a
copy SerializationData, WorkerThread
bartlomieju 494cb68
handle scope properly
bartlomieju d0fe985
add simple test case for worker
bartlomieju File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
/// Copyright 2012 the V8 project authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
#include <errno.h> | ||
bartlomieju marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/stat.h> | ||
|
||
#include <algorithm> | ||
#include <fstream> | ||
#include <unordered_map> | ||
#include <utility> | ||
#include <vector> | ||
|
||
#include "third_party/v8/include/v8.h" | ||
#include "third_party/v8/src/d8.h" | ||
#include "third_party/v8/src/objects.h" | ||
#include "third_party/v8/src/objects/string.h" | ||
#include "third_party/v8/src/utils.h" | ||
|
||
#include "worker.h" | ||
#include "file_util.h" | ||
|
||
const int kMaxWorkers = 100; | ||
|
||
namespace deno { | ||
|
||
static v8::Local<v8::Value> Throw(v8::Isolate* isolate, const char* message) { | ||
return isolate->ThrowException( | ||
v8::String::NewFromUtf8(isolate, message, v8::NewStringType::kNormal) | ||
.ToLocalChecked()); | ||
} | ||
|
||
static v8::Local<v8::Value> GetValue(v8::Isolate* isolate, v8::Local<v8::Context> context, | ||
v8::Local<v8::Object> object, const char* property) { | ||
v8::Local<v8::String> v8_str = | ||
v8::String::NewFromUtf8(isolate, property, v8::NewStringType::kNormal) | ||
.ToLocalChecked(); | ||
return object->Get(context, v8_str).ToLocalChecked(); | ||
} | ||
|
||
class ExternalOwningOneByteStringResource | ||
: public v8::String::ExternalOneByteStringResource { | ||
public: | ||
ExternalOwningOneByteStringResource() : length_(0) {} | ||
ExternalOwningOneByteStringResource(std::unique_ptr<const char[]> data, | ||
size_t length) | ||
: data_(std::move(data)), length_(length) {} | ||
const char* data() const override { return data_.get(); } | ||
size_t length() const override { return length_; } | ||
|
||
private: | ||
std::unique_ptr<const char[]> data_; | ||
size_t length_; | ||
}; | ||
|
||
|
||
// Reads a file into a v8 string. | ||
v8::Local<v8::String> ReadFile(v8::Isolate* isolate, const char* name) { | ||
int size = 0; | ||
|
||
std::string file_contents; | ||
CHECK(deno::ReadFileToString(name, &file_contents)); | ||
char* chars = (char*)file_contents.c_str(); | ||
size = (int)strlen(chars); | ||
if (chars == nullptr) return v8::Local<v8::String>(); | ||
v8::Local<v8::String> result; | ||
|
||
if (i::FLAG_use_external_strings && i::String::IsAscii(chars, size)) { | ||
v8::String::ExternalOneByteStringResource* resource = | ||
new ExternalOwningOneByteStringResource( | ||
std::unique_ptr<const char[]>(chars), size); | ||
result = v8::String::NewExternalOneByte(isolate, resource).ToLocalChecked(); | ||
} else { | ||
result = v8::String::NewFromUtf8(isolate, chars, v8::NewStringType::kNormal, size) | ||
.ToLocalChecked(); | ||
delete[] chars; | ||
} | ||
return result; | ||
} | ||
|
||
v8::base::LazyMutex workers_mutex_; | ||
bool allow_new_workers_ = true; | ||
std::vector<deno::Worker*> workers_; | ||
|
||
void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||
v8::Isolate* isolate = args.GetIsolate(); | ||
v8::HandleScope handle_scope(isolate); | ||
if (args.Length() < 1 || !args[0]->IsString()) { | ||
Throw(args.GetIsolate(), "1st argument must be string"); | ||
return; | ||
} | ||
|
||
// d8 honors `options={type: string}`, which means the first argument is | ||
// not a filename but string of script to be run. | ||
bool load_from_file = true; | ||
if (args.Length() > 1 && args[1]->IsObject()) { | ||
v8::Local<v8::Object> object = args[1].As<v8::Object>(); | ||
v8::Local<v8::Context> context = isolate->GetCurrentContext(); | ||
v8::Local<v8::Value> value = GetValue(args.GetIsolate(), context, object, "type"); | ||
if (value->IsString()) { | ||
v8::Local<v8::String> worker_type = value->ToString(context).ToLocalChecked(); | ||
v8::String::Utf8Value str(isolate, worker_type); | ||
if (strcmp("string", *str) == 0) { | ||
load_from_file = false; | ||
} else if (strcmp("classic", *str) == 0) { | ||
load_from_file = true; | ||
} else { | ||
Throw(args.GetIsolate(), "Unsupported worker type"); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
v8::Local<v8::Value> source; | ||
if (load_from_file) { | ||
v8::String::Utf8Value filename(args.GetIsolate(), args[0]); | ||
source = ReadFile(args.GetIsolate(), *filename); | ||
if (source.IsEmpty()) { | ||
Throw(args.GetIsolate(), "Error loading worker script"); | ||
return; | ||
} | ||
} else { | ||
source = args[0]; | ||
} | ||
|
||
if (!args.IsConstructCall()) { | ||
Throw(args.GetIsolate(), "Worker must be constructed with new"); | ||
return; | ||
} | ||
|
||
{ | ||
v8::base::LockGuard<v8::base::Mutex> lock_guard(workers_mutex_.Pointer()); | ||
if (workers_.size() >= kMaxWorkers) { | ||
Throw(args.GetIsolate(), "Too many workers, I won't let you create more"); | ||
return; | ||
} | ||
|
||
// Initialize the embedder field to nullptr; 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, nullptr); | ||
|
||
if (!allow_new_workers_) return; | ||
|
||
Worker* worker = new Worker; | ||
args.Holder()->SetAlignedPointerInInternalField(0, worker); | ||
workers_.push_back(worker); | ||
|
||
v8::String::Utf8Value script(args.GetIsolate(), source); | ||
if (!*script) { | ||
Throw(args.GetIsolate(), "Can't get worker script"); | ||
return; | ||
} | ||
worker->StartExecuteInThread(*script); | ||
} | ||
} | ||
|
||
bool SerializationDataQueue::IsEmpty() { | ||
// base::LockGuard<base::Mutex> lock_guard(&mutex_); | ||
// return data_.empty(); | ||
return true; | ||
} | ||
|
||
|
||
void SerializationDataQueue::Clear() { | ||
// base::LockGuard<base::Mutex> lock_guard(&mutex_); | ||
// data_.clear(); | ||
} | ||
|
||
Worker::Worker() | ||
: in_semaphore_(0), | ||
out_semaphore_(0), | ||
thread_(nullptr), | ||
script_(nullptr), | ||
running_(false) {} | ||
|
||
Worker::~Worker() { | ||
delete thread_; | ||
thread_ = nullptr; | ||
delete[] script_; | ||
script_ = nullptr; | ||
in_queue_.Clear(); | ||
out_queue_.Clear(); | ||
} | ||
|
||
void Worker::StartExecuteInThread(const char* script) { | ||
running_ = true; | ||
script_ = i::StrDup(script); | ||
thread_ = new WorkerThread(this); | ||
thread_->Start(); | ||
} | ||
|
||
void Worker::ExecuteInThread() { | ||
|
||
} | ||
// void WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||
// v8::Isolate* isolate = args.GetIsolate(); | ||
// v8::HandleScope handle_scope(isolate); | ||
|
||
// if (args.Length() < 1) { | ||
// Throw(isolate, "Invalid argument"); | ||
// return; | ||
// } | ||
|
||
// Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); | ||
// if (!worker) { | ||
// return; | ||
// } | ||
|
||
// v8::Local<Value> message = args[0]; | ||
// v8::Local<Value> transfer = | ||
// args.Length() >= 2 ? args[1] : v8::Local<Value>::Cast(Undefined(isolate)); | ||
// std::unique_ptr<SerializationData> data = | ||
// SerializeValue(isolate, message, transfer); | ||
// if (data) { | ||
// worker->PostMessage(std::move(data)); | ||
// } | ||
// } | ||
|
||
|
||
// void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||
// v8::Isolate* isolate = args.GetIsolate(); | ||
// v8::HandleScope handle_scope(isolate); | ||
// Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); | ||
// if (!worker) { | ||
// return; | ||
// } | ||
|
||
// std::unique_ptr<SerializationData> data = worker->GetMessage(); | ||
// if (data) { | ||
// v8::Local<Value> value; | ||
// if (DeserializeValue(isolate, std::move(data)).ToLocal(&value)) { | ||
// args.GetReturnValue().Set(value); | ||
// } | ||
// } | ||
// } | ||
|
||
|
||
// void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { | ||
// Isolate* isolate = args.GetIsolate(); | ||
// HandleScope handle_scope(isolate); | ||
// Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); | ||
// if (!worker) { | ||
// return; | ||
// } | ||
|
||
// worker->Terminate(); | ||
// } | ||
|
||
} // namespace "deno" | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works. I would consider using our existing
deno::InitializeContext
for setting up the global variables... However using a ObjectTemplate is probably a better option - and how D8 is doing it - so don't worry about this nit for now.