6#if defined(DART_HOST_OS_MACOS)
42static void RemoveFromKqueue(intptr_t kqueue_fd_, DescriptorInfo* di) {
43 if (!di->tracked_by_kqueue()) {
46 const intptr_t kMaxChanges = 2;
47 struct kevent events[kMaxChanges];
48 EV_SET(events, di->fd(), EVFILT_READ, EV_DELETE, 0, 0,
nullptr);
50 EV_SET(events, di->fd(), EVFILT_WRITE, EV_DELETE, 0, 0,
nullptr);
52 di->set_tracked_by_kqueue(
false);
57static void AddToKqueue(intptr_t kqueue_fd_, DescriptorInfo* di) {
58 ASSERT(!di->tracked_by_kqueue());
59 const intptr_t kMaxChanges = 2;
61 struct kevent events[kMaxChanges];
63 if (!di->IsListeningSocket()) {
67 ASSERT(di->HasReadEvent() || di->HasWriteEvent());
70 if (di->HasReadEvent()) {
71 EV_SET(events + changes, di->fd(), EVFILT_READ,
flags, 0, 0, di);
75 if (di->HasWriteEvent()) {
76 EV_SET(events + changes, di->fd(), EVFILT_WRITE,
flags, 0, 0, di);
80 ASSERT(changes <= kMaxChanges);
82 kevent(kqueue_fd_, events, changes,
nullptr, 0,
nullptr));
92 di->set_tracked_by_kqueue(
true);
97 : socket_map_(&SimpleHashMap::SamePointerValue, 16) {
101 FATAL(
"Pipe creation failed");
103 if (!FDUtils::SetNonBlocking(interrupt_fds_[0])) {
104 FATAL(
"Failed to set pipe fd non-blocking\n");
106 if (!FDUtils::SetCloseOnExec(interrupt_fds_[0])) {
107 FATAL(
"Failed to set pipe fd close on exec\n");
109 if (!FDUtils::SetCloseOnExec(interrupt_fds_[1])) {
110 FATAL(
"Failed to set pipe fd close on exec\n");
115 if (kqueue_fd_ == -1) {
116 FATAL(
"Failed creating kqueue");
118 if (!FDUtils::SetCloseOnExec(kqueue_fd_)) {
119 FATAL(
"Failed to set kqueue fd close on exec\n");
123 EV_SET(&
event, interrupt_fds_[0], EVFILT_READ, EV_ADD, 0, 0,
nullptr);
129 Utils::StrError(errno, error_message,
kBufferSize);
130 FATAL(
"Failed adding interrupt fd to kqueue: %s\n", error_message);
134static void DeleteDescriptorInfo(
void*
info) {
135 DescriptorInfo* di =
reinterpret_cast<DescriptorInfo*
>(
info);
140EventHandlerImplementation::~EventHandlerImplementation() {
141 socket_map_.Clear(DeleteDescriptorInfo);
143 close(interrupt_fds_[0]);
144 close(interrupt_fds_[1]);
147void EventHandlerImplementation::UpdateKQueueInstance(intptr_t old_mask,
148 DescriptorInfo* di) {
149 intptr_t new_mask = di->Mask();
150 if (old_mask != 0 && new_mask == 0) {
151 RemoveFromKqueue(kqueue_fd_, di);
152 }
else if ((old_mask == 0) && (new_mask != 0)) {
153 AddToKqueue(kqueue_fd_, di);
154 }
else if ((old_mask != 0) && (new_mask != 0) && (old_mask != new_mask)) {
155 ASSERT(!di->IsListeningSocket());
156 RemoveFromKqueue(kqueue_fd_, di);
157 AddToKqueue(kqueue_fd_, di);
161DescriptorInfo* EventHandlerImplementation::GetDescriptorInfo(
166 GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd),
true);
168 DescriptorInfo* di =
reinterpret_cast<DescriptorInfo*
>(entry->value);
173 di =
new DescriptorInfoMultiple(fd);
175 di =
new DescriptorInfoSingle(fd);
183void EventHandlerImplementation::WakeupHandler(intptr_t
id,
186 InterruptMessage msg;
188 msg.dart_port = dart_port;
197 FATAL(
"Interrupt message failure: %s", strerror(errno));
199 FATAL(
"Interrupt message failure: expected to write %" Pd
200 " bytes, but wrote %" Pd ".",
206void EventHandlerImplementation::HandleInterruptFd() {
208 InterruptMessage msg[MAX_MESSAGES];
213 timeout_queue_.UpdateTimeout(msg[
i].dart_port, msg[
i].
data);
218 Socket* socket =
reinterpret_cast<Socket*
>(msg[
i].id);
219 RefCntReleaseScope<Socket> rs(socket);
220 if (socket->fd() == -1) {
226 ASSERT(!di->IsListeningSocket());
230 ASSERT(!di->IsListeningSocket());
237 Process::ClearSignalHandlerByFd(di->fd(), socket->isolate_port());
239 intptr_t old_mask = di->Mask();
242 di->RemovePort(
port);
244 intptr_t new_mask = di->Mask();
245 UpdateKQueueInstance(old_mask, di);
247 intptr_t fd = di->fd();
248 if (di->IsListeningSocket()) {
252 ListeningSocketRegistry* registry =
253 ListeningSocketRegistry::Instance();
255 MutexLocker locker(registry->mutex());
257 if (registry->CloseSafe(socket)) {
259 socket_map_.Remove(GetHashmapKeyFromFd(fd),
260 GetHashmapHashFromFd(fd));
267 socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
275 intptr_t old_mask = di->Mask();
277 UpdateKQueueInstance(old_mask, di);
283 intptr_t old_mask = di->Mask();
285 UpdateKQueueInstance(old_mask, di);
294static void PrintEventMask(intptr_t fd,
struct kevent*
event) {
295 Syslog::Print(
"%d ",
static_cast<int>(fd));
297 Syslog::Print(
"filter=0x%x:",
event->filter);
298 if (
event->filter == EVFILT_READ) {
299 Syslog::Print(
"EVFILT_READ ");
301 if (
event->filter == EVFILT_WRITE) {
302 Syslog::Print(
"EVFILT_WRITE ");
305 Syslog::Print(
"flags: %x: ",
event->flags);
306 if ((
event->flags & EV_EOF) != 0) {
307 Syslog::Print(
"EV_EOF ");
309 if ((
event->flags & EV_ERROR) != 0) {
310 Syslog::Print(
"EV_ERROR ");
312 if ((
event->flags & EV_CLEAR) != 0) {
313 Syslog::Print(
"EV_CLEAR ");
315 if ((
event->flags & EV_ADD) != 0) {
316 Syslog::Print(
"EV_ADD ");
318 if ((
event->flags & EV_DELETE) != 0) {
319 Syslog::Print(
"EV_DELETE ");
322 Syslog::Print(
"- fflags: %d ",
event->fflags);
323 Syslog::Print(
"- data: %ld ",
event->data);
324 Syslog::Print(
"(available %d) ",
325 static_cast<int>(FDUtils::AvailableBytes(fd)));
330intptr_t EventHandlerImplementation::GetEvents(
struct kevent*
event,
331 DescriptorInfo* di) {
333 PrintEventMask(di->fd(),
event);
335 intptr_t event_mask = 0;
336 if (di->IsListeningSocket()) {
339 if (
event->filter == EVFILT_READ) {
340 if ((
event->flags & EV_EOF) != 0) {
341 if (
event->fflags != 0) {
347 if (event_mask == 0) {
355 if (
event->filter == EVFILT_READ) {
357 if ((
event->flags & EV_EOF) != 0) {
358 if (
event->fflags != 0) {
364 }
else if (
event->filter == EVFILT_WRITE) {
366 if ((
event->flags & EV_EOF) != 0) {
367 if (
event->fflags != 0) {
379void EventHandlerImplementation::HandleEvents(
struct kevent* events,
int size) {
380 bool interrupt_seen =
false;
381 for (
int i = 0;
i <
size;
i++) {
383 if ((events[
i].
flags & EV_ERROR) != 0) {
387 FATAL(
"kevent failed %s\n", error_message);
389 if (events[
i].udata ==
nullptr) {
390 interrupt_seen =
true;
392 DescriptorInfo* di =
reinterpret_cast<DescriptorInfo*
>(events[
i].udata);
393 const intptr_t old_mask = di->Mask();
394 const intptr_t event_mask = GetEvents(events +
i, di);
396 di->NotifyAllDartPorts(event_mask);
397 UpdateKQueueInstance(old_mask, di);
398 }
else if (event_mask != 0) {
401 UpdateKQueueInstance(old_mask, di);
402 DartUtils::PostInt32(
port, event_mask);
406 if (interrupt_seen) {
413int64_t EventHandlerImplementation::GetTimeout() {
414 if (!timeout_queue_.HasTimeout()) {
418 timeout_queue_.CurrentTimeout() - TimerUtils::GetCurrentMonotonicMillis();
419 return (millis < 0) ? 0 : millis;
422void EventHandlerImplementation::HandleTimeout() {
423 if (timeout_queue_.HasTimeout()) {
424 int64_t millis = timeout_queue_.CurrentTimeout() -
425 TimerUtils::GetCurrentMonotonicMillis();
427 DartUtils::PostNull(timeout_queue_.CurrentPort());
428 timeout_queue_.RemoveCurrent();
433void EventHandlerImplementation::EventHandlerEntry(
uword args) {
434 const intptr_t kMaxEvents = 16;
435 struct kevent events[kMaxEvents];
436 EventHandler* handler =
reinterpret_cast<EventHandler*
>(
args);
437 EventHandlerImplementation* handler_impl = &handler->delegate_;
438 ASSERT(handler_impl !=
nullptr);
440 while (!handler_impl->shutdown_) {
441 int64_t millis = handler_impl->GetTimeout();
448 struct timespec*
timeout =
nullptr;
451 int32_t millis32 =
static_cast<int32_t
>(millis);
452 int32_t secs = millis32 / 1000;
454 ts.tv_nsec = (millis32 - (secs * 1000)) * 1000000;
460 handler_impl->kqueue_fd_,
nullptr, 0, events, kMaxEvents,
timeout));
464 Utils::StrError(errno, error_message,
kBufferSize);
465 FATAL(
"kevent failed %s\n", error_message);
467 handler_impl->HandleTimeout();
468 handler_impl->HandleEvents(events,
result);
471 DEBUG_ASSERT(ReferenceCounted<Socket>::instances() == 0);
472 handler->NotifyShutdownDone();
475void EventHandlerImplementation::Start(EventHandler* handler) {
476 int result = Thread::Start(
"dart:io EventHandler",
477 &EventHandlerImplementation::EventHandlerEntry,
478 reinterpret_cast<uword>(handler));
480 FATAL(
"Failed to start event handler thread %d",
result);
491 WakeupHandler(
id, dart_port,
data);
494void* EventHandlerImplementation::GetHashmapKeyFromFd(intptr_t fd) {
496 return reinterpret_cast<void*
>(fd + 1);
499uint32_t EventHandlerImplementation::GetHashmapHashFromFd(intptr_t fd) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static bool read(SkStream *stream, void *buffer, size_t amount)
static const size_t kBufferSize
#define DEBUG_ASSERT(cond)
static uint32_t WordHash(intptr_t key)
virtual intptr_t Mask()=0
EventHandlerImplementation()
#define IS_COMMAND(data, command_bit)
#define IS_LISTENING_SOCKET(data)
#define IS_SIGNAL_SOCKET(data)
#define TOKEN_COUNT(data)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
int SendData(MHD_Connection *connection, const SkData *data, const char *type, bool setContentDisposition, const char *dispositionString)
static constexpr intptr_t kTimerId
static constexpr intptr_t kShutdownId
static constexpr intptr_t kInfinityTimeout
static constexpr intptr_t kInterruptMessageSize
static void Shutdown(Dart_NativeArguments args)
constexpr int32_t kMaxInt32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
def timeout(deadline, cmd)
#define NO_RETRY_EXPECTED(expression)
#define VOID_NO_RETRY_EXPECTED(expression)
#define TEMP_FAILURE_RETRY(expression)
std::shared_ptr< const fml::Mapping > data