Index: runtime/vm/dart.cc |
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc |
index a838585dda8b87ca9d50bab6a9cb6b1364bd6cb1..90f5560eb782290bd9bf5f690e3d02be3b076543 100644 |
--- a/runtime/vm/dart.cc |
+++ b/runtime/vm/dart.cc |
@@ -38,6 +38,7 @@ DECLARE_FLAG(bool, trace_isolates); |
DECLARE_FLAG(bool, trace_time_all); |
DEFINE_FLAG(bool, keep_code, false, |
"Keep deoptimized code for profiling."); |
+DEFINE_FLAG(bool, shutdown, true, "Do a clean shutdown of the VM"); |
Isolate* Dart::vm_isolate_ = NULL; |
ThreadPool* Dart::thread_pool_ = NULL; |
@@ -196,38 +197,60 @@ const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot, |
} |
+// This waits until only the VM isolate remains in the list. |
+void Dart::WaitForIsolateShutdown() { |
+ ASSERT(!Isolate::creation_enabled_); |
+ MonitorLocker ml(Isolate::isolates_list_monitor_); |
+ while ((Isolate::isolates_list_head_ != NULL) && |
+ (Isolate::isolates_list_head_->next_ != NULL)) { |
+ ml.Wait(); |
+ } |
+ ASSERT(Isolate::isolates_list_head_ == Dart::vm_isolate()); |
+} |
+ |
+ |
const char* Dart::Cleanup() { |
- // Shutdown the service isolate before shutting down the thread pool. |
- ServiceIsolate::Shutdown(); |
-#if 0 |
- // Ideally we should shutdown the VM isolate here, but the thread pool |
- // shutdown does not seem to ensure that all the threads have stopped |
- // execution before it terminates, this results in racing isolates. |
+ ASSERT(Isolate::Current() == NULL); |
if (vm_isolate_ == NULL) { |
return "VM already terminated."; |
} |
- ASSERT(Isolate::Current() == NULL); |
+ // Shut down profiling. |
+ Profiler::Shutdown(); |
- delete thread_pool_; |
- thread_pool_ = NULL; |
+ if (FLAG_shutdown) { |
+ // Disable the creation of new isolates. |
+ Isolate::DisableIsolateCreation(); |
- // Set the VM isolate as current isolate. |
- Thread::EnsureInit(); |
- Thread::EnterIsolate(vm_isolate_); |
+ // Send the OOB Kill message to all remaining application isolates. |
+ Isolate::KillAllIsolates(); |
- // There is a planned and known asymmetry here: We exit one scope for the VM |
- // isolate to account for the scope that was entered in Dart_InitOnce. |
- Dart_ExitScope(); |
+ // Shutdown the service isolate. |
+ ServiceIsolate::Shutdown(); |
- ShutdownIsolate(); |
- vm_isolate_ = NULL; |
+ // Wait for all application isolates and the service isolate to shutdown |
+ // before shutting down the thread pool. |
+ WaitForIsolateShutdown(); |
- TargetCPUFeatures::Cleanup(); |
- StoreBuffer::ShutDown(); |
-#endif |
+ // Shutdown the thread pool. On return, all thread pool threads have exited. |
+ delete thread_pool_; |
+ thread_pool_ = NULL; |
+ |
+ // Set the VM isolate as current isolate. |
+ Thread::EnsureInit(); |
+ Thread::EnterIsolate(vm_isolate_); |
+ |
+ ShutdownIsolate(); |
+ vm_isolate_ = NULL; |
+ ASSERT(Isolate::IsolateListLength() == 0); |
+ |
+ TargetCPUFeatures::Cleanup(); |
+ StoreBuffer::ShutDown(); |
+ } else { |
+ // Shutdown the service isolate. |
+ ServiceIsolate::Shutdown(); |
+ } |
- Profiler::Shutdown(); |
CodeObservers::DeleteAll(); |
Timeline::Shutdown(); |
Metric::Cleanup(); |