@@ -18,7 +18,7 @@ using v8::TaskPriority; |
18 | 18 | namespace { |
19 | 19 |
|
20 | 20 | struct PlatformWorkerData { |
21 | | - TaskQueue<Task>* task_queue; |
| 21 | + TaskQueue<TaskQueueEntry>* task_queue; |
22 | 22 | Mutex* platform_workers_mutex; |
23 | 23 | ConditionVariable* platform_workers_ready; |
24 | 24 | int* pending_platform_workers; |
@@ -53,7 +53,7 @@ static void PlatformWorkerThread(void* data) { |
53 | 53 | std::unique_ptr<PlatformWorkerData> |
54 | 54 | worker_data(static_cast<PlatformWorkerData*>(data)); |
55 | 55 |
|
56 | | - TaskQueue<Task>* pending_worker_tasks = worker_data->task_queue; |
| 56 | + TaskQueue<TaskQueueEntry>* pending_worker_tasks = worker_data->task_queue; |
57 | 57 | TRACE_EVENT_METADATA1("__metadata", "thread_name", "name", |
58 | 58 | "PlatformWorkerThread"); |
59 | 59 |
|
@@ -67,16 +67,17 @@ static void PlatformWorkerThread(void* data) { |
67 | 67 | bool debug_log_enabled = |
68 | 68 | worker_data->debug_log_level != PlatformDebugLogLevel::kNone; |
69 | 69 | int id = worker_data->id; |
70 | | - while (std::unique_ptr<Task> task = |
| 70 | + while (std::unique_ptr<TaskQueueEntry> entry = |
71 | 71 | pending_worker_tasks->Lock().BlockingPop()) { |
72 | 72 | if (debug_log_enabled) { |
73 | 73 | fprintf(stderr, |
74 | | - "\nPlatformWorkerThread %d running task %p\n", |
| 74 | + "\nPlatformWorkerThread %d running task %p %s\n", |
75 | 75 | id, |
76 | | - task.get()); |
| 76 | + entry->task.get(), |
| 77 | + GetTaskPriorityName(entry->priority)); |
77 | 78 | fflush(stderr); |
78 | 79 | } |
79 | | - task->Run(); |
| 80 | + entry->task->Run(); |
80 | 81 | pending_worker_tasks->Lock().NotifyOfCompletion(); |
81 | 82 | } |
82 | 83 | } |
@@ -92,8 +93,8 @@ static int GetActualThreadPoolSize(int thread_pool_size) { |
92 | 93 |
|
93 | 94 | class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
94 | 95 | public: |
95 | | - explicit DelayedTaskScheduler(TaskQueue<Task>* tasks) |
96 | | - : pending_worker_tasks_(tasks) {} |
| 96 | + explicit DelayedTaskScheduler(TaskQueue<TaskQueueEntry>* tasks) |
| 97 | + : pending_worker_tasks_(tasks) {} |
97 | 98 |
|
98 | 99 | std::unique_ptr<uv_thread_t> Start() { |
99 | 100 | auto start_thread = [](void* data) { |
@@ -107,16 +108,21 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
107 | 108 | return t; |
108 | 109 | } |
109 | 110 |
|
110 | | - void PostDelayedTask(std::unique_ptr<Task> task, double delay_in_seconds) { |
| 111 | + void PostDelayedTask(v8::TaskPriority priority, |
| 112 | + std::unique_ptr<Task> task, |
| 113 | + double delay_in_seconds) { |
111 | 114 | auto locked = tasks_.Lock(); |
112 | 115 |
|
| 116 | + auto entry = std::make_unique<TaskQueueEntry>(std::move(task), priority); |
| 117 | + auto delayed = std::make_unique<ScheduleTask>( |
| 118 | + this, std::move(entry), delay_in_seconds); |
| 119 | + |
113 | 120 | // The delayed task scheuler is on is own thread with its own loop that |
114 | 121 | // runs the timers for the scheduled tasks to pop the original task back |
115 | 122 | // into the the worker task queue. This first pushes the tasks that |
116 | 123 | // schedules the timers into the local task queue that will be flushed |
117 | 124 | // by the local event loop. |
118 | | - locked.Push(std::make_unique<ScheduleTask>( |
119 | | - this, std::move(task), delay_in_seconds)); |
| 125 | + locked.Push(std::move(delayed)); |
120 | 126 | uv_async_send(&flush_tasks_); |
121 | 127 | } |
122 | 128 |
|
@@ -144,10 +150,12 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
144 | 150 | DelayedTaskScheduler* scheduler = |
145 | 151 | ContainerOf(&DelayedTaskScheduler::loop_, flush_tasks->loop); |
146 | 152 |
|
147 | | - std::queue<std::unique_ptr<Task>> tasks_to_run = |
148 | | - scheduler->tasks_.Lock().PopAll(); |
| 153 | + auto tasks_to_run = scheduler->tasks_.Lock().PopAll(); |
149 | 154 | while (!tasks_to_run.empty()) { |
150 | | - std::unique_ptr<Task> task = std::move(tasks_to_run.front()); |
| 155 | + // We have to use const_cast because std::priority_queue::top() does not |
| 156 | + // return a movable item. |
| 157 | + std::unique_ptr<Task> task = |
| 158 | + std::move(const_cast<std::unique_ptr<Task>&>(tasks_to_run.top())); |
151 | 159 | tasks_to_run.pop(); |
152 | 160 | // This runs either the ScheduleTasks that scheduels the timers to |
153 | 161 | // pop the tasks back into the worker task runner queue, or the |
@@ -177,7 +185,7 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
177 | 185 | class ScheduleTask : public Task { |
178 | 186 | public: |
179 | 187 | ScheduleTask(DelayedTaskScheduler* scheduler, |
180 | | - std::unique_ptr<Task> task, |
| 188 | + std::unique_ptr<TaskQueueEntry> task, |
181 | 189 | double delay_in_seconds) |
182 | 190 | : scheduler_(scheduler), |
183 | 191 | task_(std::move(task)), |
@@ -194,7 +202,7 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
194 | 202 |
|
195 | 203 | private: |
196 | 204 | DelayedTaskScheduler* scheduler_; |
197 | | - std::unique_ptr<Task> task_; |
| 205 | + std::unique_ptr<TaskQueueEntry> task_; |
198 | 206 | double delay_in_seconds_; |
199 | 207 | }; |
200 | 208 |
|
@@ -205,20 +213,21 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler { |
205 | 213 | scheduler->TakeTimerTask(timer)); |
206 | 214 | } |
207 | 215 |
|
208 | | - std::unique_ptr<Task> TakeTimerTask(uv_timer_t* timer) { |
209 | | - std::unique_ptr<Task> task(static_cast<Task*>(timer->data)); |
| 216 | + std::unique_ptr<TaskQueueEntry> TakeTimerTask(uv_timer_t* timer) { |
| 217 | + std::unique_ptr<TaskQueueEntry> task_entry( |
| 218 | + static_cast<TaskQueueEntry*>(timer->data)); |
210 | 219 | uv_timer_stop(timer); |
211 | 220 | uv_close(reinterpret_cast<uv_handle_t*>(timer), [](uv_handle_t* handle) { |
212 | 221 | delete reinterpret_cast<uv_timer_t*>(handle); |
213 | 222 | }); |
214 | 223 | timers_.erase(timer); |
215 | | - return task; |
| 224 | + return task_entry; |
216 | 225 | } |
217 | 226 |
|
218 | 227 | uv_sem_t ready_; |
219 | 228 | // Task queue in the worker thread task runner, we push the delayed task back |
220 | 229 | // to it when the timer expires. |
221 | | - TaskQueue<Task>* pending_worker_tasks_; |
| 230 | + TaskQueue<TaskQueueEntry>* pending_worker_tasks_; |
222 | 231 |
|
223 | 232 | // Locally scheduled tasks to be poped into the worker task runner queue. |
224 | 233 | // It is flushed whenever the next closest timer expires. |
@@ -264,13 +273,20 @@ WorkerThreadsTaskRunner::WorkerThreadsTaskRunner( |
264 | 273 | } |
265 | 274 | } |
266 | 275 |
|
267 | | -void WorkerThreadsTaskRunner::PostTask(std::unique_ptr<Task> task) { |
268 | | - pending_worker_tasks_.Lock().Push(std::move(task)); |
| 276 | +void WorkerThreadsTaskRunner::PostTask(v8::TaskPriority priority, |
| 277 | + std::unique_ptr<v8::Task> task, |
| 278 | + const v8::SourceLocation& location) { |
| 279 | + auto entry = std::make_unique<TaskQueueEntry>(std::move(task), priority); |
| 280 | + pending_worker_tasks_.Lock().Push(std::move(entry)); |
269 | 281 | } |
270 | 282 |
|
271 | | -void WorkerThreadsTaskRunner::PostDelayedTask(std::unique_ptr<Task> task, |
272 | | - double delay_in_seconds) { |
273 | | - delayed_task_scheduler_->PostDelayedTask(std::move(task), delay_in_seconds); |
| 283 | +void WorkerThreadsTaskRunner::PostDelayedTask( |
| 284 | + v8::TaskPriority priority, |
| 285 | + std::unique_ptr<v8::Task> task, |
| 286 | + const v8::SourceLocation& location, |
| 287 | + double delay_in_seconds) { |
| 288 | + delayed_task_scheduler_->PostDelayedTask( |
| 289 | + priority, std::move(task), delay_in_seconds); |
274 | 290 | } |
275 | 291 |
|
276 | 292 | void WorkerThreadsTaskRunner::BlockingDrain() { |
@@ -330,7 +346,9 @@ void PerIsolatePlatformData::PostTaskImpl(std::unique_ptr<Task> task, |
330 | 346 |
|
331 | 347 | auto locked = foreground_tasks_.Lock(); |
332 | 348 | if (flush_tasks_ == nullptr) return; |
333 | | - locked.Push(std::move(task)); |
| 349 | + // All foreground tasks are treated as user blocking tasks. |
| 350 | + locked.Push(std::make_unique<TaskQueueEntry>( |
| 351 | + std::move(task), v8::TaskPriority::kUserBlocking)); |
334 | 352 | uv_async_send(flush_tasks_); |
335 | 353 | } |
336 | 354 |
|
@@ -356,6 +374,8 @@ void PerIsolatePlatformData::PostDelayedTaskImpl( |
356 | 374 | delayed->task = std::move(task); |
357 | 375 | delayed->platform_data = shared_from_this(); |
358 | 376 | delayed->timeout = delay_in_seconds; |
| 377 | + // All foreground tasks are treated as user blocking tasks. |
| 378 | + delayed->priority = v8::TaskPriority::kUserBlocking; |
359 | 379 | locked.Push(std::move(delayed)); |
360 | 380 | uv_async_send(flush_tasks_); |
361 | 381 | } |
@@ -562,11 +582,13 @@ void NodePlatform::DrainTasks(Isolate* isolate) { |
562 | 582 | bool PerIsolatePlatformData::FlushForegroundTasksInternal() { |
563 | 583 | bool did_work = false; |
564 | 584 |
|
565 | | - std::queue<std::unique_ptr<DelayedTask>> delayed_tasks_to_schedule = |
566 | | - foreground_delayed_tasks_.Lock().PopAll(); |
| 585 | + auto delayed_tasks_to_schedule = foreground_delayed_tasks_.Lock().PopAll(); |
567 | 586 | while (!delayed_tasks_to_schedule.empty()) { |
| 587 | + // We have to use const_cast because std::priority_queue::top() does not |
| 588 | + // return a movable item. |
568 | 589 | std::unique_ptr<DelayedTask> delayed = |
569 | | - std::move(delayed_tasks_to_schedule.front()); |
| 590 | + std::move(const_cast<std::unique_ptr<DelayedTask>&>( |
| 591 | + delayed_tasks_to_schedule.top())); |
570 | 592 | delayed_tasks_to_schedule.pop(); |
571 | 593 |
|
572 | 594 | did_work = true; |
@@ -591,17 +613,20 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() { |
591 | 613 | }); |
592 | 614 | } |
593 | 615 |
|
594 | | - std::queue<std::unique_ptr<Task>> tasks; |
| 616 | + TaskQueue<TaskQueueEntry>::PriorityQueue tasks; |
595 | 617 | { |
596 | 618 | auto locked = foreground_tasks_.Lock(); |
597 | 619 | tasks = locked.PopAll(); |
598 | 620 | } |
599 | 621 |
|
600 | 622 | while (!tasks.empty()) { |
601 | | - std::unique_ptr<Task> task = std::move(tasks.front()); |
| 623 | + // We have to use const_cast because std::priority_queue::top() does not |
| 624 | + // return a movable item. |
| 625 | + std::unique_ptr<TaskQueueEntry> entry = |
| 626 | + std::move(const_cast<std::unique_ptr<TaskQueueEntry>&>(tasks.top())); |
602 | 627 | tasks.pop(); |
603 | 628 | did_work = true; |
604 | | - RunForegroundTask(std::move(task)); |
| 629 | + RunForegroundTask(std::move(entry->task)); |
605 | 630 | } |
606 | 631 |
|
607 | 632 | return did_work; |
@@ -622,7 +647,7 @@ void NodePlatform::PostTaskOnWorkerThreadImpl( |
622 | 647 | } |
623 | 648 | fflush(stderr); |
624 | 649 | } |
625 | | - worker_thread_task_runner_->PostTask(std::move(task)); |
| 650 | + worker_thread_task_runner_->PostTask(priority, std::move(task), location); |
626 | 651 | } |
627 | 652 |
|
628 | 653 | void NodePlatform::PostDelayedTaskOnWorkerThreadImpl( |
@@ -642,8 +667,8 @@ void NodePlatform::PostDelayedTaskOnWorkerThreadImpl( |
642 | 667 | } |
643 | 668 | fflush(stderr); |
644 | 669 | } |
645 | | - worker_thread_task_runner_->PostDelayedTask(std::move(task), |
646 | | - delay_in_seconds); |
| 670 | + worker_thread_task_runner_->PostDelayedTask( |
| 671 | + priority, std::move(task), location, delay_in_seconds); |
647 | 672 | } |
648 | 673 |
|
649 | 674 | IsolatePlatformDelegate* NodePlatform::ForIsolate(Isolate* isolate) { |
@@ -742,7 +767,8 @@ std::unique_ptr<T> TaskQueue<T>::Locked::Pop() { |
742 | 767 | if (queue_->task_queue_.empty()) { |
743 | 768 | return std::unique_ptr<T>(nullptr); |
744 | 769 | } |
745 | | - std::unique_ptr<T> result = std::move(queue_->task_queue_.front()); |
| 770 | + std::unique_ptr<T> result = std::move( |
| 771 | + std::move(const_cast<std::unique_ptr<T>&>(queue_->task_queue_.top()))); |
746 | 772 | queue_->task_queue_.pop(); |
747 | 773 | return result; |
748 | 774 | } |
@@ -755,7 +781,8 @@ std::unique_ptr<T> TaskQueue<T>::Locked::BlockingPop() { |
755 | 781 | if (queue_->stopped_) { |
756 | 782 | return std::unique_ptr<T>(nullptr); |
757 | 783 | } |
758 | | - std::unique_ptr<T> result = std::move(queue_->task_queue_.front()); |
| 784 | + std::unique_ptr<T> result = std::move( |
| 785 | + std::move(const_cast<std::unique_ptr<T>&>(queue_->task_queue_.top()))); |
759 | 786 | queue_->task_queue_.pop(); |
760 | 787 | return result; |
761 | 788 | } |
@@ -781,8 +808,8 @@ void TaskQueue<T>::Locked::Stop() { |
781 | 808 | } |
782 | 809 |
|
783 | 810 | template <class T> |
784 | | -std::queue<std::unique_ptr<T>> TaskQueue<T>::Locked::PopAll() { |
785 | | - std::queue<std::unique_ptr<T>> result; |
| 811 | +TaskQueue<T>::PriorityQueue TaskQueue<T>::Locked::PopAll() { |
| 812 | + TaskQueue<T>::PriorityQueue result; |
786 | 813 | result.swap(queue_->task_queue_); |
787 | 814 | return result; |
788 | 815 | } |
|