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 "flutter/runtime/dart_vm_lifecycle.h" |
6 | |
7 | #include <mutex> |
8 | |
9 | namespace flutter { |
10 | |
11 | // We need to explicitly put the constructor and destructor of the DartVM in the |
12 | // critical section. All accesses (not just const members) to the global VM |
13 | // object weak pointer are behind this mutex. |
14 | static std::mutex gVMMutex; |
15 | static std::weak_ptr<DartVM> gVM; |
16 | static std::shared_ptr<DartVM>* gVMLeak; |
17 | |
18 | // We are going to be modifying more than just the control blocks of the |
19 | // following weak pointers (in the |Create| case where an old VM could not be |
20 | // reused). Ideally, we would use |std::atomic<std::weak_ptr<T>>| specialization |
21 | // but that is only available since C++20. We don't expect contention on these |
22 | // locks so we just use one mutex for all. |
23 | static std::mutex gVMDependentsMutex; |
24 | static std::weak_ptr<const DartVMData> gVMData; |
25 | static std::weak_ptr<ServiceProtocol> gVMServiceProtocol; |
26 | static std::weak_ptr<IsolateNameServer> gVMIsolateNameServer; |
27 | |
28 | DartVMRef::DartVMRef(std::shared_ptr<DartVM> vm) : vm_(vm) {} |
29 | |
30 | DartVMRef::DartVMRef(DartVMRef&& other) = default; |
31 | |
32 | DartVMRef::~DartVMRef() { |
33 | if (!vm_) { |
34 | // If there is no valid VM (possible via a move), there is no way that the |
35 | // decrement on the shared pointer can cause a collection. Avoid acquiring |
36 | // the lifecycle lock in this case. This is just working around a |
37 | // pessimization and not required for correctness. |
38 | return; |
39 | } |
40 | std::scoped_lock lifecycle_lock(gVMMutex); |
41 | vm_.reset(); |
42 | } |
43 | |
44 | DartVMRef DartVMRef::Create(Settings settings, |
45 | fml::RefPtr<DartSnapshot> vm_snapshot, |
46 | fml::RefPtr<DartSnapshot> isolate_snapshot) { |
47 | std::scoped_lock lifecycle_lock(gVMMutex); |
48 | |
49 | if (!settings.leak_vm) { |
50 | FML_CHECK(!gVMLeak) |
51 | << "Launch settings indicated that the VM should shut down in the " |
52 | "process when done but a previous launch asked the VM to leak in " |
53 | "the same process. For proper VM shutdown, all VM launches must " |
54 | "indicate that they should shut down when done." ; |
55 | } |
56 | |
57 | // If there is already a running VM in the process, grab a strong reference to |
58 | // it. |
59 | if (auto vm = gVM.lock()) { |
60 | FML_DLOG(WARNING) << "Attempted to create a VM in a process where one was " |
61 | "already running. Ignoring arguments for current VM " |
62 | "create call and reusing the old VM." ; |
63 | // There was already a running VM in the process, |
64 | return DartVMRef{std::move(vm)}; |
65 | } |
66 | |
67 | std::scoped_lock dependents_lock(gVMDependentsMutex); |
68 | |
69 | gVMData.reset(); |
70 | gVMServiceProtocol.reset(); |
71 | gVMIsolateNameServer.reset(); |
72 | gVM.reset(); |
73 | |
74 | // If there is no VM in the process. Initialize one, hold the weak reference |
75 | // and pass a strong reference to the caller. |
76 | auto isolate_name_server = std::make_shared<IsolateNameServer>(); |
77 | auto vm = DartVM::Create(std::move(settings), // |
78 | std::move(vm_snapshot), // |
79 | std::move(isolate_snapshot), // |
80 | isolate_name_server // |
81 | ); |
82 | |
83 | if (!vm) { |
84 | FML_LOG(ERROR) << "Could not create Dart VM instance." ; |
85 | return {nullptr}; |
86 | } |
87 | |
88 | gVMData = vm->GetVMData(); |
89 | gVMServiceProtocol = vm->GetServiceProtocol(); |
90 | gVMIsolateNameServer = isolate_name_server; |
91 | gVM = vm; |
92 | |
93 | if (settings.leak_vm) { |
94 | gVMLeak = new std::shared_ptr<DartVM>(vm); |
95 | } |
96 | |
97 | return DartVMRef{std::move(vm)}; |
98 | } |
99 | |
100 | bool DartVMRef::IsInstanceRunning() { |
101 | std::scoped_lock lock(gVMMutex); |
102 | return !gVM.expired(); |
103 | } |
104 | |
105 | std::shared_ptr<const DartVMData> DartVMRef::GetVMData() { |
106 | std::scoped_lock lock(gVMDependentsMutex); |
107 | return gVMData.lock(); |
108 | } |
109 | |
110 | std::shared_ptr<ServiceProtocol> DartVMRef::GetServiceProtocol() { |
111 | std::scoped_lock lock(gVMDependentsMutex); |
112 | return gVMServiceProtocol.lock(); |
113 | } |
114 | |
115 | std::shared_ptr<IsolateNameServer> DartVMRef::GetIsolateNameServer() { |
116 | std::scoped_lock lock(gVMDependentsMutex); |
117 | return gVMIsolateNameServer.lock(); |
118 | } |
119 | |
120 | DartVM* DartVMRef::GetRunningVM() { |
121 | std::scoped_lock lock(gVMMutex); |
122 | auto vm = gVM.lock().get(); |
123 | FML_CHECK(vm) << "Caller assumed VM would be running when it wasn't" ; |
124 | return vm; |
125 | } |
126 | |
127 | } // namespace flutter |
128 | |