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