fix: make StreamSubscriber ref counted (#17221)

It is owned by URLRequestStreamJob on the IO thread once request starts,
but if the ownership was abondoned while transfering it to IO thread
which is possible when a request is aborted, then we need to make sure
its destroyed on the right thread to avoid lock in v8.
This commit is contained in:
Robo 2019-03-07 20:50:03 +05:30 коммит произвёл GitHub
Родитель b575631bb0
Коммит d4d6b9862f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 37 добавлений и 24 удалений

Просмотреть файл

@ -19,12 +19,15 @@ namespace mate {
StreamSubscriber::StreamSubscriber(
v8::Isolate* isolate,
v8::Local<v8::Object> emitter,
base::WeakPtr<atom::URLRequestStreamJob> url_job)
: isolate_(isolate),
base::WeakPtr<atom::URLRequestStreamJob> url_job,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
: base::RefCountedDeleteOnSequence<StreamSubscriber>(ui_task_runner),
isolate_(isolate),
emitter_(isolate, emitter),
url_job_(url_job),
weak_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(ui_task_runner->RunsTasksInCurrentSequence());
auto weak_self = weak_factory_.GetWeakPtr();
On("data", base::Bind(&StreamSubscriber::OnData, weak_self));
On("end", base::Bind(&StreamSubscriber::OnEnd, weak_self));
@ -32,13 +35,12 @@ StreamSubscriber::StreamSubscriber(
}
StreamSubscriber::~StreamSubscriber() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
RemoveAllListeners();
}
void StreamSubscriber::On(const std::string& event,
EventCallback&& callback) { // NOLINT
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
DCHECK(js_handlers_.find(event) == js_handlers_.end());
v8::Locker locker(isolate_);
@ -52,7 +54,7 @@ void StreamSubscriber::On(const std::string& event,
}
void StreamSubscriber::Off(const std::string& event) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
DCHECK(js_handlers_.find(event) != js_handlers_.end());
v8::Locker locker(isolate_);
@ -96,6 +98,7 @@ void StreamSubscriber::OnError(mate::Arguments* args) {
}
void StreamSubscriber::RemoveAllListeners() {
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
v8::Locker locker(isolate_);
v8::Isolate::Scope isolate_scope(isolate_);
v8::HandleScope handle_scope(isolate_);

Просмотреть файл

@ -11,6 +11,8 @@
#include <vector>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "v8/include/v8.h"
@ -23,17 +25,25 @@ namespace mate {
class Arguments;
class StreamSubscriber {
class StreamSubscriber
: public base::RefCountedDeleteOnSequence<StreamSubscriber> {
public:
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
StreamSubscriber(v8::Isolate* isolate,
v8::Local<v8::Object> emitter,
base::WeakPtr<atom::URLRequestStreamJob> url_job);
~StreamSubscriber();
base::WeakPtr<atom::URLRequestStreamJob> url_job,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
private:
friend class base::DeleteHelper<StreamSubscriber>;
friend class base::RefCountedDeleteOnSequence<StreamSubscriber>;
using JSHandlersMap = std::map<std::string, v8::Global<v8::Value>>;
using EventCallback = base::Callback<void(mate::Arguments* args)>;
~StreamSubscriber();
void On(const std::string& event, EventCallback&& callback); // NOLINT
void Off(const std::string& event);

Просмотреть файл

@ -17,6 +17,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "content/public/browser/browser_task_traits.h"
#include "native_mate/dictionary.h"
@ -84,14 +85,14 @@ void BeforeStartInUI(base::WeakPtr<URLRequestStreamJob> job,
return;
}
auto subscriber = std::make_unique<mate::StreamSubscriber>(
args->isolate(), data.GetHandle(), job);
auto subscriber = base::MakeRefCounted<mate::StreamSubscriber>(
args->isolate(), data.GetHandle(), job,
base::ThreadTaskRunnerHandle::Get());
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&URLRequestStreamJob::StartAsync, job,
std::move(subscriber), base::RetainedRef(response_headers),
ended, error));
base::BindOnce(&URLRequestStreamJob::StartAsync, job, subscriber,
base::RetainedRef(response_headers), ended, error));
}
} // namespace
@ -106,10 +107,7 @@ URLRequestStreamJob::URLRequestStreamJob(net::URLRequest* request,
weak_factory_(this) {}
URLRequestStreamJob::~URLRequestStreamJob() {
if (subscriber_) {
content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
std::move(subscriber_));
}
DCHECK(!subscriber_ || subscriber_->HasOneRef());
}
void URLRequestStreamJob::Start() {
@ -123,7 +121,7 @@ void URLRequestStreamJob::Start() {
}
void URLRequestStreamJob::StartAsync(
std::unique_ptr<mate::StreamSubscriber> subscriber,
scoped_refptr<mate::StreamSubscriber> subscriber,
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool ended,
int error) {
@ -135,7 +133,7 @@ void URLRequestStreamJob::StartAsync(
ended_ = ended;
response_headers_ = response_headers;
subscriber_ = std::move(subscriber);
subscriber_ = subscriber;
request_start_time_ = base::TimeTicks::Now();
NotifyHeadersComplete();
}
@ -194,12 +192,14 @@ int URLRequestStreamJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
}
void URLRequestStreamJob::DoneReading() {
content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
std::move(subscriber_));
write_buffer_.clear();
}
void URLRequestStreamJob::DoneReadingRedirectResponse() {
if (subscriber_) {
DCHECK(subscriber_->HasAtLeastOneRef());
subscriber_ = nullptr;
}
DoneReading();
}

Просмотреть файл

@ -24,7 +24,7 @@ class URLRequestStreamJob : public JsAsker, public net::URLRequestJob {
net::NetworkDelegate* network_delegate);
~URLRequestStreamJob() override;
void StartAsync(std::unique_ptr<mate::StreamSubscriber> subscriber,
void StartAsync(scoped_refptr<mate::StreamSubscriber> subscriber,
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool ended,
int error);
@ -62,7 +62,7 @@ class URLRequestStreamJob : public JsAsker, public net::URLRequestJob {
base::TimeTicks request_start_time_;
base::TimeTicks response_start_time_;
scoped_refptr<net::HttpResponseHeaders> response_headers_;
std::unique_ptr<mate::StreamSubscriber> subscriber_;
scoped_refptr<mate::StreamSubscriber> subscriber_;
base::WeakPtrFactory<URLRequestStreamJob> weak_factory_;