| 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(); | 
|  |