Chromium Code Reviews| Index: runtime/vm/kernel_isolate.cc |
| diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e6aa22d5b92e21d48b0c4a0e641ebd8e97b3b74a |
| --- /dev/null |
| +++ b/runtime/vm/kernel_isolate.cc |
| @@ -0,0 +1,266 @@ |
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +#include "vm/kernel_isolate.h" |
| + |
| +#include "vm/compiler.h" |
| +#include "vm/dart_api_impl.h" |
| +#include "vm/dart_entry.h" |
| +#include "vm/isolate.h" |
| +#include "vm/lockers.h" |
| +#include "vm/message.h" |
| +#include "vm/message_handler.h" |
| +#include "vm/native_entry.h" |
| +#include "vm/native_arguments.h" |
| +#include "vm/object.h" |
| +#include "vm/object_store.h" |
| +#include "vm/port.h" |
| +#include "vm/service.h" |
| +#include "vm/symbols.h" |
| +#include "vm/thread_pool.h" |
| +#include "vm/timeline.h" |
| + |
| +namespace dart { |
| + |
| +#if !defined(DART_PRECOMPILED_RUNTIME) |
| + |
| +#define Z (T->zone()) |
| + |
| +DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests."); |
| + |
| + |
| +const char* KernelIsolate::kName = "kernel-service"; |
| +Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL; |
| +Monitor* KernelIsolate::monitor_ = NULL; |
| +Isolate* KernelIsolate::isolate_ = NULL; |
| +bool KernelIsolate::initializing_ = true; |
| +bool KernelIsolate::shutting_down_ = false; |
| +Dart_Port KernelIsolate::kernel_port_ = ILLEGAL_PORT; |
| + |
| + |
| +class RunKernelTask : public ThreadPool::Task { |
| + public: |
| + virtual void Run() { |
| + ASSERT(Isolate::Current() == NULL); |
| + |
| +#ifndef PRODUCT |
| + TimelineDurationScope tds(Timeline::GetVMStream(), "KernelIsolateStartup"); |
| +#endif // !PRODUCT |
| + char* error = NULL; |
| + Isolate* isolate = NULL; |
| + |
| + Dart_IsolateCreateCallback create_callback = |
| + KernelIsolate::create_callback(); |
| + |
| + if (create_callback == NULL) { |
| + KernelIsolate::FinishedInitializing(); |
| + return; |
| + } |
| + |
| + Dart_IsolateFlags api_flags; |
| + Isolate::FlagsInitialize(&api_flags); |
| + |
| + isolate = reinterpret_cast<Isolate*>(create_callback( |
| + KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error)); |
| + if (isolate == NULL) { |
| + if (FLAG_trace_kernel) { |
| + OS::PrintErr("kernel-service: Isolate creation error: %s\n", error); |
| + } |
| + KernelIsolate::SetKernelIsolate(NULL); |
| + KernelIsolate::FinishedInitializing(); |
| + KernelIsolate::FinishedExiting(); |
|
siva
2016/12/02 20:59:38
we seem to grab the lock thrice and do a notifyAll
hausner
2016/12/03 01:29:00
Eliminated one state and one call. I don't think t
|
| + return; |
| + } |
| + |
| + bool got_unwind; |
| + { |
| + ASSERT(Isolate::Current() == NULL); |
| + StartIsolateScope start_scope(isolate); |
| + got_unwind = RunMain(isolate); |
| + } |
| + |
| + if (got_unwind) { |
| + ShutdownIsolate(reinterpret_cast<uword>(isolate)); |
|
siva
2016/12/02 20:59:38
initializing state should be set to false here?
I
hausner
2016/12/03 01:29:00
Done.
|
| + return; |
| + } |
| + |
| + KernelIsolate::FinishedInitializing(); |
| + |
| + // isolate_ was set as side effect of create callback. |
| + ASSERT(KernelIsolate::isolate_ == isolate); |
|
siva
2016/12/02 20:59:38
This is an unlocked access, probably ok but maybe
hausner
2016/12/03 01:29:00
Done. The friending is still necessary, for some p
|
| + |
| + isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate, |
| + reinterpret_cast<uword>(isolate)); |
| + } |
| + |
| + protected: |
| + static void ShutdownIsolate(uword parameter) { |
| + if (FLAG_trace_kernel) { |
| + OS::Print("kernel-service: ShutdownIsolate\n"); |
| + } |
| + Isolate* I = reinterpret_cast<Isolate*>(parameter); |
| + ASSERT(KernelIsolate::IsKernelIsolate(I)); |
| + KernelIsolate::SetKernelIsolate(NULL); |
| + KernelIsolate::SetLoadPort(ILLEGAL_PORT); |
| + I->WaitForOutstandingSpawns(); |
| + { |
| + // Print the error if there is one. This may execute dart code to |
| + // print the exception object, so we need to use a StartIsolateScope. |
| + ASSERT(Isolate::Current() == NULL); |
| + StartIsolateScope start_scope(I); |
| + Thread* T = Thread::Current(); |
| + ASSERT(I == T->isolate()); |
| + StackZone zone(T); |
| + HandleScope handle_scope(T); |
| + Error& error = Error::Handle(Z); |
| + error = T->sticky_error(); |
| + if (!error.IsNull() && !error.IsUnwindError()) { |
| + OS::PrintErr("kernel-service: Error: %s\n", error.ToErrorCString()); |
| + } |
| + error = I->sticky_error(); |
| + if (!error.IsNull() && !error.IsUnwindError()) { |
| + OS::PrintErr("kernel-service: Error: %s\n", error.ToErrorCString()); |
| + } |
| + Dart::RunShutdownCallback(); |
| + } |
| + // Shut the isolate down. |
| + Dart::ShutdownIsolate(I); |
| + if (FLAG_trace_kernel) { |
| + OS::Print("kernel-service: Shutdown.\n"); |
| + } |
| + KernelIsolate::FinishedExiting(); |
| + } |
| + |
| + bool RunMain(Isolate* I) { |
| + Thread* T = Thread::Current(); |
| + ASSERT(I == T->isolate()); |
| + StackZone zone(T); |
| + HANDLESCOPE(T); |
| + // Invoke main which will return the port to which load requests are sent. |
| + const Library& root_library = |
| + Library::Handle(Z, I->object_store()->root_library()); |
| + if (root_library.IsNull()) { |
| + if (FLAG_trace_kernel) { |
| + OS::Print("kernel-service: Embedder did not install a script."); |
| + } |
| + // Kernel isolate is not supported by embedder. |
| + return false; |
| + } |
| + ASSERT(!root_library.IsNull()); |
| + const String& entry_name = String::Handle(Z, String::New("main")); |
| + ASSERT(!entry_name.IsNull()); |
| + const Function& entry = Function::Handle( |
| + Z, root_library.LookupFunctionAllowPrivate(entry_name)); |
| + if (entry.IsNull()) { |
| + // Kernel isolate is not supported by embedder. |
| + if (FLAG_trace_kernel) { |
| + OS::Print("kernel-service: Embedder did not provide a main function."); |
| + } |
| + return false; |
| + } |
| + ASSERT(!entry.IsNull()); |
| + const Object& result = Object::Handle( |
| + Z, DartEntry::InvokeFunction(entry, Object::empty_array())); |
| + ASSERT(!result.IsNull()); |
| + if (result.IsError()) { |
| + // Kernel isolate did not initialize properly. |
| + if (FLAG_trace_kernel) { |
| + const Error& error = Error::Cast(result); |
| + OS::Print("kernel-service: Calling main resulted in an error: %s", |
| + error.ToErrorCString()); |
| + } |
| + if (result.IsUnwindError()) { |
| + return true; |
| + } |
| + return false; |
| + } |
| + ASSERT(result.IsReceivePort()); |
| + const ReceivePort& rp = ReceivePort::Cast(result); |
| + KernelIsolate::SetLoadPort(rp.Id()); |
| + return false; |
| + } |
| +}; |
| + |
| + |
| +void KernelIsolate::Run() { |
| + ASSERT(monitor_ == NULL); |
| + monitor_ = new Monitor(); |
| + ASSERT(monitor_ != NULL); |
| + // Grab the isolate create callback here to avoid race conditions with tests |
| + // that change this after Dart_Initialize returns. |
| + create_callback_ = Isolate::CreateCallback(); |
| + Dart::thread_pool()->Run(new RunKernelTask()); |
| +} |
| + |
| + |
| +void KernelIsolate::InitCallback(Isolate* I) { |
| + Thread* T = Thread::Current(); |
| + ASSERT(I == T->isolate()); |
| + ASSERT(I != NULL); |
| + ASSERT(I->name() != NULL); |
| + if (strstr(I->name(), "kernel-service") == NULL) { |
| + // Not service isolate. |
| + return; |
| + } |
| + ASSERT(!Exists()); |
| + if (FLAG_trace_kernel) { |
| + OS::Print("kernel-service: InitCallback for %s.\n", I->name()); |
| + } |
| + SetKernelIsolate(I); |
| +} |
| + |
| + |
| +bool KernelIsolate::IsKernelIsolate(const Isolate* isolate) { |
| + MonitorLocker ml(monitor_); |
| + return isolate == isolate_; |
| +} |
| + |
| + |
| +bool KernelIsolate::IsRunning() { |
| + MonitorLocker ml(monitor_); |
| + return (kernel_port_ != ILLEGAL_PORT) && (isolate_ != NULL); |
| +} |
| + |
| + |
| +void KernelIsolate::FinishedExiting() { |
| + MonitorLocker ml(monitor_); |
| + shutting_down_ = false; |
| + ml.NotifyAll(); |
| +} |
| + |
| + |
| +bool KernelIsolate::Exists() { |
| + MonitorLocker ml(monitor_); |
| + return isolate_ != NULL; |
| +} |
| + |
| + |
| +void KernelIsolate::SetKernelIsolate(Isolate* isolate) { |
| + MonitorLocker ml(monitor_); |
| + isolate_ = isolate; |
| +} |
| + |
| +void KernelIsolate::SetLoadPort(Dart_Port port) { |
| + MonitorLocker ml(monitor_); |
| + kernel_port_ = port; |
| +} |
| + |
| +void KernelIsolate::FinishedInitializing() { |
| + MonitorLocker ml(monitor_); |
| + initializing_ = false; |
| + ml.NotifyAll(); |
| +} |
| + |
| + |
| +Dart_Port KernelIsolate::WaitForKernelPort() { |
| + MonitorLocker ml(monitor_); |
| + while (initializing_ && (kernel_port_ == ILLEGAL_PORT)) { |
| + ml.Wait(); |
| + } |
| + return kernel_port_; |
| +} |
| + |
| +#endif // DART_PRECOMPILED_RUNTIME |
| + |
| +} // namespace dart |