@@ -38,6 +38,40 @@ class RepostingTask : public v8::Task {
3838 node::NodePlatform* platform_;
3939};
4040
41+ class NoopTask : public v8 ::Task {
42+ public:
43+ void Run () final {}
44+ };
45+
46+ class PostDelayedTaskAfterShutdownStartsTask : public v8 ::Task {
47+ public:
48+ PostDelayedTaskAfterShutdownStartsTask (node::NodePlatform* platform,
49+ uv_sem_t * task_started,
50+ uv_sem_t * post_task)
51+ : platform_(platform),
52+ task_started_ (task_started),
53+ post_task_(post_task) {}
54+
55+ void Run () final {
56+ uv_sem_post (task_started_);
57+ uv_sem_wait (post_task_);
58+ uv_sleep (50 );
59+ platform_->PostDelayedTaskOnWorkerThreadImpl (v8::TaskPriority::kUserVisible ,
60+ std::make_unique<NoopTask>(),
61+ 1.0 ,
62+ v8::SourceLocation ());
63+ }
64+
65+ private:
66+ node::NodePlatform* platform_;
67+ uv_sem_t * task_started_;
68+ uv_sem_t * post_task_;
69+ };
70+
71+ static void ShutdownPlatform (void * arg) {
72+ static_cast <node::NodePlatform*>(arg)->Shutdown ();
73+ }
74+
4175class PlatformTest : public EnvironmentTestFixture {};
4276
4377TEST_F (PlatformTest, SkipNewTasksInFlushForegroundTasks) {
@@ -60,6 +94,40 @@ TEST_F(PlatformTest, SkipNewTasksInFlushForegroundTasks) {
6094 EXPECT_FALSE (platform->FlushForegroundTasks (isolate_));
6195}
6296
97+ // Regression test: a worker thread posting a delayed task concurrently with
98+ // platform shutdown must not call uv_async_send() on the scheduler's
99+ // flush_tasks_ handle after Stop() has begun closing it. The two semaphores
100+ // and the sleeps pin the ordering so the delayed task is posted only after
101+ // Shutdown() has run, which is the window that used to abort with
102+ // "Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)". The test passes
103+ // when shutdown completes without crashing.
104+ TEST_F (NodeZeroIsolateTestFixture, DelayedWorkerTaskDuringPlatformShutdown) {
105+ node::NodePlatform test_platform (1 , tracing_agent->GetTracingController ());
106+
107+ uv_sem_t task_started;
108+ uv_sem_t post_task;
109+ ASSERT_EQ (0 , uv_sem_init (&task_started, 0 ));
110+ ASSERT_EQ (0 , uv_sem_init (&post_task, 0 ));
111+
112+ test_platform.PostTaskOnWorkerThreadImpl (
113+ v8::TaskPriority::kUserBlocking ,
114+ std::make_unique<PostDelayedTaskAfterShutdownStartsTask>(
115+ &test_platform, &task_started, &post_task),
116+ v8::SourceLocation ());
117+
118+ uv_sem_wait (&task_started);
119+
120+ uv_thread_t shutdown_thread;
121+ ASSERT_EQ (
122+ 0 , uv_thread_create (&shutdown_thread, ShutdownPlatform, &test_platform));
123+ uv_sleep (50 );
124+ uv_sem_post (&post_task);
125+ ASSERT_EQ (0 , uv_thread_join (&shutdown_thread));
126+
127+ uv_sem_destroy (&post_task);
128+ uv_sem_destroy (&task_started);
129+ }
130+
63131// Tests the registration of an abstract `IsolatePlatformDelegate` instance as
64132// opposed to the more common `uv_loop_s*` version of `RegisterIsolate`.
65133TEST_F (NodeZeroIsolateTestFixture, IsolatePlatformDelegateTest) {
0 commit comments