blob: 5ee62aa2302e282ad281a4eca587bf722727e865 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "flutter/runtime/dart_vm_initializer.h"
#include <atomic>
#include "flutter/fml/logging.h"
#include "flutter/fml/synchronization/shared_mutex.h"
#include "flutter/fml/trace_event.h"
// Tracks whether Dart has been initialized and if it is safe to call Dart
// APIs.
static std::atomic<bool> gDartInitialized;
void DartVMInitializer::Initialize(Dart_InitializeParams* params) {
FML_DCHECK(!gDartInitialized);
char* error = Dart_Initialize(params);
if (error) {
FML_LOG(FATAL) << "Error while initializing the Dart VM: " << error;
::free(error);
} else {
gDartInitialized = true;
}
fml::tracing::TraceSetTimelineEventHandler(LogDartTimelineEvent);
}
void DartVMInitializer::Cleanup() {
FML_DCHECK(gDartInitialized);
// Dart_TimelineEvent is unsafe during a concurrent call to Dart_Cleanup
// because Dart_Cleanup will destroy the timeline recorder. Clear the
// initialized flag so that future calls to LogDartTimelineEvent will not
// call Dart_TimelineEvent.
//
// Note that this is inherently racy. If a thread sees that gDartInitialized
// is set and proceeds to call Dart_TimelineEvent shortly before another
// thread calls Dart_Cleanup, then the Dart_TimelineEvent call may crash
// if Dart_Cleanup deletes the timeline before Dart_TimelineEvent completes.
// In practice this is unlikely because Dart_Cleanup does significant other
// work before deleting the timeline.
//
// The engine can not safely guard Dart_Cleanup and LogDartTimelineEvent with
// a lock due to the risk of deadlocks. Dart_Cleanup waits for various
// Dart-owned threads to shut down. If one of those threads invokes an engine
// callback that calls LogDartTimelineEvent while the Dart_Cleanup thread owns
// the lock, then Dart_Cleanup would deadlock.
gDartInitialized = false;
char* error = Dart_Cleanup();
if (error) {
FML_LOG(FATAL) << "Error while cleaning up the Dart VM: " << error;
::free(error);
}
}
void DartVMInitializer::LogDartTimelineEvent(const char* label,
int64_t timestamp0,
int64_t timestamp1_or_async_id,
Dart_Timeline_Event_Type type,
intptr_t argument_count,
const char** argument_names,
const char** argument_values) {
if (gDartInitialized) {
Dart_TimelineEvent(label, timestamp0, timestamp1_or_async_id, type,
argument_count, argument_names, argument_values);
}
}