blob: 8ecfb873f0cb1c2f98773a345de7be4997139004 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "dart-pkg/zircon/sdk_ext/handle_waiter.h"
#include <lib/async/default.h>
#include "dart-pkg/zircon/sdk_ext/handle.h"
#include "src/lib/fxl/logging.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/dart_binding_macros.h"
#include "third_party/tonic/dart_library_natives.h"
#include "third_party/tonic/dart_message_handler.h"
#include "third_party/tonic/logging/dart_invoke.h"
using tonic::DartInvokeField;
using tonic::DartState;
using tonic::ToDart;
namespace zircon {
namespace dart {
IMPLEMENT_WRAPPERTYPEINFO(zircon, HandleWaiter);
#define FOR_EACH_BINDING(V) V(HandleWaiter, Cancel)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
void HandleWaiter::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
}
fxl::RefPtr<HandleWaiter> HandleWaiter::Create(Handle* handle,
zx_signals_t signals,
Dart_Handle callback) {
return fxl::MakeRefCounted<HandleWaiter>(handle, signals, callback);
}
HandleWaiter::HandleWaiter(Handle* handle, zx_signals_t signals,
Dart_Handle callback)
: wait_(this, handle->handle(), signals),
handle_(handle),
callback_(DartState::Current(), callback) {
FXL_CHECK(handle_ != nullptr);
FXL_CHECK(handle_->is_valid());
zx_status_t status = wait_.Begin(async_get_default_dispatcher());
FXL_DCHECK(status == ZX_OK);
}
HandleWaiter::~HandleWaiter() { Cancel(); }
void HandleWaiter::Cancel() {
FXL_DCHECK(wait_.is_pending() == !!handle_);
if (handle_) {
// Cancel the wait.
wait_.Cancel();
// Release this object from the handle and clear handle_.
handle_->ReleaseWaiter(this);
handle_ = nullptr;
}
FXL_DCHECK(!wait_.is_pending());
}
void HandleWaiter::OnWaitComplete(async_dispatcher_t* dispatcher,
async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
FXL_DCHECK(handle_);
FXL_DCHECK(!callback_.is_empty());
// Hold a reference to this object.
fxl::RefPtr<HandleWaiter> ref(this);
// Remove this waiter from the handle.
handle_->ReleaseWaiter(this);
// Clear handle_.
handle_ = nullptr;
auto state = callback_.dart_state().lock();
FXL_DCHECK(state);
DartState::Scope scope(state);
std::vector<Dart_Handle> args{ToDart(status), ToDart(signal->observed)};
FXL_DCHECK(!callback_.is_empty());
Dart_Handle result =
Dart_InvokeClosure(callback_.Release(), args.size(), args.data());
// If there was an uncaught error from the callback propagate it out.
if (tonic::LogIfError(result)) {
state->message_handler().UnhandledError(result);
}
}
} // namespace dart
} // namespace zircon