blob: 8238cd56c42244b2e4172eb21467e068732b1f69 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "third_party/blink/renderer/modules/locks/lock.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/locks/lock_manager.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
namespace {
const char* kLockModeNameExclusive = "exclusive";
const char* kLockModeNameShared = "shared";
} // namespace
class Lock::ThenFunction final : public ScriptFunction {
public:
enum ResolveType {
Fulfilled,
Rejected,
};
static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
Lock* lock,
ResolveType type) {
ThenFunction* self =
MakeGarbageCollected<ThenFunction>(script_state, lock, type);
return self->BindToV8Function();
}
ThenFunction(ScriptState* script_state, Lock* lock, ResolveType type)
: ScriptFunction(script_state), lock_(lock), resolve_type_(type) {}
void Trace(blink::Visitor* visitor) override {
visitor->Trace(lock_);
ScriptFunction::Trace(visitor);
}
private:
ScriptValue Call(ScriptValue value) override {
DCHECK(lock_);
DCHECK(resolve_type_ == Fulfilled || resolve_type_ == Rejected);
lock_->ReleaseIfHeld();
if (resolve_type_ == Fulfilled)
lock_->resolver_->Resolve(value);
else
lock_->resolver_->Reject(value);
lock_ = nullptr;
return value;
}
Member<Lock> lock_;
ResolveType resolve_type_;
};
// static
Lock* Lock::Create(ScriptState* script_state,
const String& name,
mojom::blink::LockMode mode,
mojom::blink::LockHandleAssociatedPtr handle,
LockManager* manager) {
return MakeGarbageCollected<Lock>(script_state, name, mode, std::move(handle),
manager);
}
Lock::Lock(ScriptState* script_state,
const String& name,
mojom::blink::LockMode mode,
mojom::blink::LockHandleAssociatedPtr handle,
LockManager* manager)
: ContextLifecycleObserver(ExecutionContext::From(script_state)),
name_(name),
mode_(mode),
handle_(std::move(handle)),
manager_(manager) {
handle_.set_connection_error_handler(
WTF::Bind(&Lock::OnConnectionError, WrapWeakPersistent(this)));
}
Lock::~Lock() = default;
String Lock::mode() const {
return ModeToString(mode_);
}
void Lock::HoldUntil(ScriptPromise promise, ScriptPromiseResolver* resolver) {
DCHECK(handle_.is_bound());
DCHECK(!resolver_);
ScriptState* script_state = resolver->GetScriptState();
resolver_ = resolver;
promise.Then(
ThenFunction::CreateFunction(script_state, this, ThenFunction::Fulfilled),
ThenFunction::CreateFunction(script_state, this, ThenFunction::Rejected));
}
// static
mojom::blink::LockMode Lock::StringToMode(const String& string) {
if (string == kLockModeNameShared)
return mojom::blink::LockMode::SHARED;
if (string == kLockModeNameExclusive)
return mojom::blink::LockMode::EXCLUSIVE;
NOTREACHED();
return mojom::blink::LockMode::SHARED;
}
// static
String Lock::ModeToString(mojom::blink::LockMode mode) {
switch (mode) {
case mojom::blink::LockMode::SHARED:
return kLockModeNameShared;
case mojom::blink::LockMode::EXCLUSIVE:
return kLockModeNameExclusive;
}
NOTREACHED();
return g_empty_string;
}
void Lock::ContextDestroyed(ExecutionContext* context) {
ReleaseIfHeld();
}
void Lock::Trace(blink::Visitor* visitor) {
ContextLifecycleObserver::Trace(visitor);
ScriptWrappable::Trace(visitor);
visitor->Trace(resolver_);
visitor->Trace(manager_);
}
void Lock::ReleaseIfHeld() {
if (handle_) {
// Drop the mojo pipe; this releases the lock on the back end.
handle_.reset();
// Let the lock manager know that this instance can be collected.
manager_->OnLockReleased(this);
}
}
void Lock::OnConnectionError() {
resolver_->Reject(DOMException::Create(
DOMExceptionCode::kAbortError,
"Lock broken by another request with the 'steal' option."));
}
} // namespace blink