From dc3cf83bb63a5f7e4a5a6ae210de0a1b029c9101 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 18 Nov 2021 00:54:20 +0000 Subject: [PATCH] [vm] Allow the embedder to provide a task runner in lieu of the VM's thread pool. This allows the embedder to control the degree of parallelism and thread priorities. TEST=engine Bug: https://github.com/dart-lang/sdk/issues/44228 Change-Id: I4e8430749fcfbcbfc221c3733ee27ccbe6bcc1ae Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215941 Reviewed-by: Kaushik Iska Reviewed-by: Siva Annamalai Commit-Queue: Ryan Macnak --- runtime/bin/run_vm_tests.cc | 3 ++- runtime/include/dart_api.h | 50 ++++++++++++++++++++++++++++++++++++- runtime/vm/dart.cc | 25 +++++++++++++------ runtime/vm/dart.h | 18 +++++++++++-- runtime/vm/dart_api_impl.cc | 26 +++++++++++++------ runtime/vm/thread_pool.cc | 16 ++++++++++++ 6 files changed, 119 insertions(+), 19 deletions(-) diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc index ccd8144445d..d560dab733f 100644 --- a/runtime/bin/run_vm_tests.cc +++ b/runtime/bin/run_vm_tests.cc @@ -384,7 +384,8 @@ static int Main(int argc, const char** argv) { dart::bin::DartUtils::ReadFile, dart::bin::DartUtils::WriteFile, dart::bin::DartUtils::CloseFile, /*entropy_source=*/nullptr, /*get_service_assets=*/nullptr, start_kernel_isolate, - /*code_observer=*/nullptr); + /*code_observer=*/nullptr, /*post_task=*/nullptr, + /*post_task_data*/ nullptr); if (error != nullptr) { Syslog::PrintErr("Failed to initialize VM: %s\n", error); free(error); diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index b62c1a7a21d..5d189dfe828 100644 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -831,7 +831,7 @@ typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(); * The current version of the Dart_InitializeFlags. Should be incremented every * time Dart_InitializeFlags changes in a binary incompatible way. */ -#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000004) +#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000005) /** Forward declaration */ struct Dart_CodeObserver; @@ -857,6 +857,50 @@ typedef struct Dart_CodeObserver { Dart_OnNewCodeCallback on_new_code; } Dart_CodeObserver; +typedef struct _Dart_Task* Dart_Task; +typedef enum { + Dart_TaskPriority_Default, +} Dart_TaskPriority; +typedef struct { + /** + * Placeholder. + */ + Dart_TaskPriority priority; + /** + * Time after which the task should run according to the clock of + * Dart_TimelineGetMicros. + */ + int64_t time_point; +} Dart_TaskData; +/** + * Callback provided by the embedder that is used by the VM to eventually run + * various tasks. If no callback is provided, these tasks will run on a + * VM-internal thread pool. This callback allows the embedder to make its own + * choices around the scheduling of these tasks: when they run, how many threads + * are servicing these tasks, the priorities of said threads, etc. + * The callback can be invoked as early as during the Dart_Initialize call. + * + * \param post_task_data + * The data provided to Dart_InitializeParams.post_task_data. + * \param task + * A task that should eventually be passed to Dart_RunTask. + * \param task_data + * Hints about when the task should run. + */ +typedef void (*Dart_PostTaskCallback)(void* post_task_data, + Dart_Task task, + Dart_TaskData task_data); + +/** + * Runs a task given to the Dart_PostTaskCallback. Must not be called + * synchronously in response to any callback from the VM. In particular, must + * not be called synchronously by the implemention of a Dart native function + * or Dart_Post_TaskCallback. + * + * Requires there to be no current isolate or isolate group. + */ +DART_EXPORT void Dart_RunTask(Dart_Task task); + /** * Describes how to initialize the VM. Used with Dart_Initialize. * @@ -884,6 +928,8 @@ typedef struct Dart_CodeObserver { * See Dart_GetVMServiceAssetsArchive. * \param code_observer An external code observer callback function. * The observer can be invoked as early as during the Dart_Initialize() call. + * \param post_task A task scheduling callback function. + * See Dart_PostTaskCallback. */ typedef struct { int32_t version; @@ -903,6 +949,8 @@ typedef struct { Dart_GetVMServiceAssetsArchive get_service_assets; bool start_kernel_isolate; Dart_CodeObserver* code_observer; + Dart_PostTaskCallback post_task; + void* post_task_data; } Dart_InitializeParams; /** diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index 2dbd8d35326..7425dd659f2 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -69,6 +69,8 @@ Dart_FileWriteCallback Dart::file_write_callback_ = NULL; Dart_FileCloseCallback Dart::file_close_callback_ = NULL; Dart_EntropySource Dart::entropy_source_callback_ = NULL; Dart_GCEventCallback Dart::gc_event_callback_ = nullptr; +Dart_PostTaskCallback Dart::post_task_callback_ = nullptr; +void* Dart::post_task_data_ = nullptr; // Structure for managing read-only global handles allocation used for // creating global read-only handles that are pre created and initialized @@ -259,7 +261,9 @@ char* Dart::DartInit(const uint8_t* vm_isolate_snapshot, Dart_EntropySource entropy_source, Dart_GetVMServiceAssetsArchive get_service_assets, bool start_kernel_isolate, - Dart_CodeObserver* observer) { + Dart_CodeObserver* observer, + Dart_PostTaskCallback post_task, + void* post_task_data) { CheckOffsets(); if (!Flags::Initialized()) { @@ -294,6 +298,8 @@ char* Dart::DartInit(const uint8_t* vm_isolate_snapshot, set_thread_exit_callback(thread_exit); SetFileCallbacks(file_open, file_read, file_write, file_close); set_entropy_source_callback(entropy_source); + set_post_task_callback(post_task); + set_post_task_data(post_task_data); OS::Init(); NOT_IN_PRODUCT(CodeObservers::Init()); if (observer != nullptr) { @@ -531,18 +537,21 @@ char* Dart::Init(const uint8_t* vm_isolate_snapshot, Dart_EntropySource entropy_source, Dart_GetVMServiceAssetsArchive get_service_assets, bool start_kernel_isolate, - Dart_CodeObserver* observer) { + Dart_CodeObserver* observer, + Dart_PostTaskCallback post_task, + void* post_task_data) { if (!init_state_.SetInitializing()) { return Utils::StrDup( "Bad VM initialization state, " "already initialized or " "multiple threads initializing the VM."); } - char* retval = DartInit(vm_isolate_snapshot, instructions_snapshot, - create_group, initialize_isolate, shutdown, cleanup, - cleanup_group, thread_exit, file_open, file_read, - file_write, file_close, entropy_source, - get_service_assets, start_kernel_isolate, observer); + char* retval = + DartInit(vm_isolate_snapshot, instructions_snapshot, create_group, + initialize_isolate, shutdown, cleanup, cleanup_group, + thread_exit, file_open, file_read, file_write, file_close, + entropy_source, get_service_assets, start_kernel_isolate, + observer, post_task, post_task_data); if (retval != NULL) { init_state_.ResetInitializing(); return retval; @@ -823,6 +832,8 @@ char* Dart::Cleanup() { Service::SetEmbedderStreamCallbacks(NULL, NULL); #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) VirtualMemory::Cleanup(); + post_task_callback_ = nullptr; + post_task_data_ = nullptr; return NULL; } diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h index 9d0cdf1ec33..a8c4a56b28b 100644 --- a/runtime/vm/dart.h +++ b/runtime/vm/dart.h @@ -44,7 +44,9 @@ class Dart : public AllStatic { Dart_EntropySource entropy_source, Dart_GetVMServiceAssetsArchive get_service_assets, bool start_kernel_isolate, - Dart_CodeObserver* observer); + Dart_CodeObserver* observer, + Dart_PostTaskCallback post_task, + void* post_task_data); // Returns null if cleanup succeeds, otherwise returns an error message // (caller owns error message and has to free it). @@ -123,6 +125,14 @@ class Dart : public AllStatic { static void set_thread_exit_callback(Dart_ThreadExitCallback cback) { thread_exit_callback_ = cback; } + static Dart_PostTaskCallback post_task_callback() { + return post_task_callback_; + } + static void set_post_task_callback(Dart_PostTaskCallback cback) { + post_task_callback_ = cback; + } + static void* post_task_data() { return post_task_data_; } + static void set_post_task_data(void* data) { post_task_data_ = data; } static void SetFileCallbacks(Dart_FileOpenCallback file_open, Dart_FileReadCallback file_read, Dart_FileWriteCallback file_write, @@ -174,7 +184,9 @@ class Dart : public AllStatic { Dart_EntropySource entropy_source, Dart_GetVMServiceAssetsArchive get_service_assets, bool start_kernel_isolate, - Dart_CodeObserver* observer); + Dart_CodeObserver* observer, + Dart_PostTaskCallback post_task, + void* post_task_data); static constexpr const char* kVmIsolateName = "vm-isolate"; @@ -194,6 +206,8 @@ class Dart : public AllStatic { static Dart_FileCloseCallback file_close_callback_; static Dart_EntropySource entropy_source_callback_; static Dart_GCEventCallback gc_event_callback_; + static Dart_PostTaskCallback post_task_callback_; + static void* post_task_data_; }; } // namespace dart diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index 082476f4bee..fe7dcc4cb8c 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -1211,14 +1211,14 @@ DART_EXPORT char* Dart_Initialize(Dart_InitializeParams* params) { "Invalid Dart_InitializeParams version."); } - return Dart::Init(params->vm_snapshot_data, params->vm_snapshot_instructions, - params->create_group, params->initialize_isolate, - params->shutdown_isolate, params->cleanup_isolate, - params->cleanup_group, params->thread_exit, - params->file_open, params->file_read, params->file_write, - params->file_close, params->entropy_source, - params->get_service_assets, params->start_kernel_isolate, - params->code_observer); + return Dart::Init( + params->vm_snapshot_data, params->vm_snapshot_instructions, + params->create_group, params->initialize_isolate, + params->shutdown_isolate, params->cleanup_isolate, params->cleanup_group, + params->thread_exit, params->file_open, params->file_read, + params->file_write, params->file_close, params->entropy_source, + params->get_service_assets, params->start_kernel_isolate, + params->code_observer, params->post_task, params->post_task_data); } DART_EXPORT char* Dart_Cleanup() { @@ -2063,6 +2063,16 @@ DART_EXPORT bool Dart_RunLoopAsync(bool errors_are_fatal, return true; } +DART_EXPORT void Dart_RunTask(Dart_Task task) { + Thread* T = Thread::Current(); + Isolate* I = T == nullptr ? nullptr : T->isolate(); + CHECK_NO_ISOLATE(I); + API_TIMELINE_BEGIN_END(T); + ThreadPool::Task* task_impl = reinterpret_cast(task); + task_impl->Run(); + delete task_impl; +} + DART_EXPORT Dart_Handle Dart_HandleMessage() { Thread* T = Thread::Current(); Isolate* I = T->isolate(); diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc index 93df2ff57cf..f45055574d1 100644 --- a/runtime/vm/thread_pool.cc +++ b/runtime/vm/thread_pool.cc @@ -82,6 +82,22 @@ void ThreadPool::Shutdown() { } bool ThreadPool::RunImpl(std::unique_ptr task) { + Dart_PostTaskCallback post_task = Dart::post_task_callback(); + if (post_task != nullptr) { + { + MonitorLocker ml(&pool_monitor_); + if (shutting_down_) { + return false; + } + } + Dart_TaskData data; + data.priority = Dart_TaskPriority_Default; + data.time_point = 0; + post_task(Dart::post_task_data(), + reinterpret_cast(task.release()), data); + return true; + } + Worker* new_worker = nullptr; { MonitorLocker ml(&pool_monitor_);