• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "handle.h"
6 
7 #include <algorithm>
8 
9 #include "third_party/tonic/dart_binding_macros.h"
10 #include "third_party/tonic/dart_class_library.h"
11 
12 using tonic::ToDart;
13 
14 namespace zircon {
15 namespace dart {
16 
17 IMPLEMENT_WRAPPERTYPEINFO(zircon, Handle);
18 
Handle(zx_handle_t handle)19 Handle::Handle(zx_handle_t handle) : handle_(handle) {
20   tonic::DartState* state = tonic::DartState::Current();
21   FML_DCHECK(state);
22   Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon"));
23   FML_DCHECK(!tonic::LogIfError(zircon_lib));
24 
25   Dart_Handle on_wait_completer_type =
26       Dart_GetClass(zircon_lib, ToDart("_OnWaitCompleteClosure"));
27   FML_DCHECK(!tonic::LogIfError(on_wait_completer_type));
28   on_wait_completer_type_.Set(state, on_wait_completer_type);
29 
30   Dart_Handle async_lib = Dart_LookupLibrary(ToDart("dart:async"));
31   FML_DCHECK(!tonic::LogIfError(async_lib));
32   async_lib_.Set(state, async_lib);
33 
34   Dart_Handle closure_string = ToDart("_closure");
35   FML_DCHECK(!tonic::LogIfError(closure_string));
36   closure_string_.Set(state, closure_string);
37 
38   Dart_Handle schedule_microtask_string = ToDart("scheduleMicrotask");
39   FML_DCHECK(!tonic::LogIfError(schedule_microtask_string));
40   schedule_microtask_string_.Set(state, schedule_microtask_string);
41 }
42 
~Handle()43 Handle::~Handle() {
44   if (is_valid()) {
45     zx_status_t status = Close();
46     FML_DCHECK(status == ZX_OK);
47   }
48 }
49 
Create(zx_handle_t handle)50 fml::RefPtr<Handle> Handle::Create(zx_handle_t handle) {
51   return fml::MakeRefCounted<Handle>(handle);
52 }
53 
CreateInvalid()54 Dart_Handle Handle::CreateInvalid() {
55   return ToDart(Create(ZX_HANDLE_INVALID));
56 }
57 
ReleaseHandle()58 zx_handle_t Handle::ReleaseHandle() {
59   FML_DCHECK(is_valid());
60 
61   zx_handle_t handle = handle_;
62   handle_ = ZX_HANDLE_INVALID;
63   while (waiters_.size()) {
64     // HandleWaiter::Cancel calls Handle::ReleaseWaiter which removes the
65     // HandleWaiter from waiters_.
66     FML_DCHECK(waiters_.back()->is_pending());
67     waiters_.back()->Cancel();
68   }
69 
70   FML_DCHECK(!is_valid());
71 
72   return handle;
73 }
74 
Close()75 zx_status_t Handle::Close() {
76   if (is_valid()) {
77     zx_handle_t handle = ReleaseHandle();
78     return zx_handle_close(handle);
79   }
80   return ZX_ERR_BAD_HANDLE;
81 }
82 
AsyncWait(zx_signals_t signals,Dart_Handle callback)83 fml::RefPtr<HandleWaiter> Handle::AsyncWait(zx_signals_t signals,
84                                             Dart_Handle callback) {
85   if (!is_valid()) {
86     FML_LOG(WARNING) << "Attempt to wait on an invalid handle.";
87     return nullptr;
88   }
89 
90   fml::RefPtr<HandleWaiter> waiter =
91       HandleWaiter::Create(this, signals, callback);
92   waiters_.push_back(waiter.get());
93 
94   return waiter;
95 }
96 
ReleaseWaiter(HandleWaiter * waiter)97 void Handle::ReleaseWaiter(HandleWaiter* waiter) {
98   FML_DCHECK(waiter);
99   auto iter = std::find(waiters_.cbegin(), waiters_.cend(), waiter);
100   FML_DCHECK(iter != waiters_.cend());
101   FML_DCHECK(*iter == waiter);
102   waiters_.erase(iter);
103 }
104 
Duplicate(uint32_t rights)105 Dart_Handle Handle::Duplicate(uint32_t rights) {
106   if (!is_valid()) {
107     return ToDart(Create(ZX_HANDLE_INVALID));
108   }
109 
110   zx_handle_t out_handle;
111   zx_status_t status = zx_handle_duplicate(handle_, rights, &out_handle);
112   if (status != ZX_OK) {
113     return ToDart(Create(ZX_HANDLE_INVALID));
114   }
115   return ToDart(Create(out_handle));
116 }
117 
ScheduleCallback(tonic::DartPersistentValue callback,zx_status_t status,const zx_packet_signal_t * signal)118 void Handle::ScheduleCallback(tonic::DartPersistentValue callback,
119                               zx_status_t status,
120                               const zx_packet_signal_t* signal) {
121   auto state = callback.dart_state().lock();
122   FML_DCHECK(state);
123   tonic::DartState::Scope scope(state);
124 
125   // Make a new _OnWaitCompleteClosure(callback, status, signal->observed).
126   FML_DCHECK(!callback.is_empty());
127   std::vector<Dart_Handle> constructor_args{callback.Release(), ToDart(status),
128                                             ToDart(signal->observed)};
129   Dart_Handle on_wait_complete_closure =
130       Dart_New(on_wait_completer_type_.Get(), Dart_Null(),
131                constructor_args.size(), constructor_args.data());
132   FML_DCHECK(!tonic::LogIfError(on_wait_complete_closure));
133 
134   // The _callback field contains the thunk:
135   // () => callback(status, signal->observed)
136   Dart_Handle closure =
137       Dart_GetField(on_wait_complete_closure, closure_string_.Get());
138   FML_DCHECK(!tonic::LogIfError(closure));
139 
140   // Put the thunk on the microtask queue by calling scheduleMicrotask().
141   std::vector<Dart_Handle> sm_args{closure};
142   Dart_Handle sm_result =
143       Dart_Invoke(async_lib_.Get(), schedule_microtask_string_.Get(),
144                   sm_args.size(), sm_args.data());
145   FML_DCHECK(!tonic::LogIfError(sm_result));
146 }
147 
148 // clang-format: off
149 
150 #define FOR_EACH_STATIC_BINDING(V) V(Handle, CreateInvalid)
151 
152 #define FOR_EACH_BINDING(V) \
153   V(Handle, handle)         \
154   V(Handle, is_valid)       \
155   V(Handle, Close)          \
156   V(Handle, AsyncWait)      \
157   V(Handle, Duplicate)
158 
159 // clang-format: on
160 
161 // Tonic is missing a comma.
162 #define DART_REGISTER_NATIVE_STATIC_(CLASS, METHOD) \
163   DART_REGISTER_NATIVE_STATIC(CLASS, METHOD),
164 
165 FOR_EACH_STATIC_BINDING(DART_NATIVE_CALLBACK_STATIC)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)166 FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
167 
168 void Handle::RegisterNatives(tonic::DartLibraryNatives* natives) {
169   natives->Register({FOR_EACH_STATIC_BINDING(DART_REGISTER_NATIVE_STATIC_)
170                          FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
171 }
172 
173 }  // namespace dart
174 }  // namespace zircon
175