1+ // Copyright 2025, The max Contributors. All rights reserved.
2+ // Use of this source code is governed by a BSD-style license that can be
3+ // found in the LICENSE file.
4+
5+ #include < max/Hardware/CPU/TaskQueue.hpp>
6+
7+ #include < type_traits>
8+
9+ #include < utility>
10+
11+ namespace max {
12+ namespace Hardware {
13+ namespace CPU {
14+
15+ TaskQueue::TaskQueue (HANDLE wake_event) noexcept
16+ : task_queue_mutex_()
17+ , task_queue_()
18+ , wake_event_(std::move(wake_event))
19+ , shutting_down_(false )
20+ {
21+ }
22+
23+ TaskQueue::~TaskQueue () noexcept {
24+ BOOL result = CloseHandle (wake_event_);
25+ if (result == 0 ) {
26+ // GetLastError()
27+ }
28+ }
29+
30+ TaskQueue::AddTaskError TaskQueue::AddTask (std::unique_ptr<Task> task) noexcept {
31+ if (shutting_down_) {
32+ return AddTaskError::ShuttingDown;
33+ }
34+
35+ {
36+ std::lock_guard<std::mutex> task_queue_guard (task_queue_mutex_);
37+ task_queue_.push (std::move (task));
38+ BOOL result = SetEvent (wake_event_);
39+ if (result == 0 ) {
40+ // GetLastError()
41+ return AddTaskError::CouldNotSetEvent;
42+ }
43+ }
44+
45+ return AddTaskError::Okay;
46+ }
47+
48+ std::unique_ptr<Task> TaskQueue::TryPopTask () noexcept {
49+ std::lock_guard<std::mutex> task_queue_guard (task_queue_mutex_);
50+
51+ BOOL result = ResetEvent (wake_event_);
52+ if (result == 0 ) {
53+ // GetLastError
54+ return nullptr ;
55+ }
56+
57+ if (task_queue_.empty ()) {
58+ return nullptr ;
59+ }
60+
61+ std::unique_ptr<Task> task = std::move (task_queue_.front ());
62+ task_queue_.pop ();
63+ return task;
64+ }
65+
66+ TaskQueue::WaitForEventError TaskQueue::WaitForEvent () noexcept {
67+ auto result = WaitForMultipleObjects (1 , &wake_event_, TRUE , INFINITE);
68+ if (result != WAIT_OBJECT_0) {
69+ return WaitForEventError::CouldNotWait;
70+ } else {
71+ result = ResetEvent (wake_event_);
72+ if (result == 0 ) {
73+ // GetLastError()
74+ return WaitForEventError::CouldNotResetEvent;
75+ }
76+ }
77+
78+ return WaitForEventError::Okay;
79+ }
80+
81+ TaskQueue::ShutdownError TaskQueue::Shutdown () noexcept {
82+ std::lock_guard<std::mutex> task_queue_guard (task_queue_mutex_);
83+
84+ shutting_down_ = true ;
85+ BOOL result = SetEvent (wake_event_);
86+ if (result == 0 ) {
87+ // GetLastError()
88+ return ShutdownError::CouldNotSetEvent;
89+ }
90+
91+ return ShutdownError::Okay;
92+ }
93+
94+ std::expected<std::unique_ptr<TaskQueue>, CreateTaskQueueError> CreateTaskQueue () noexcept {
95+ HANDLE wake_event = CreateEvent (NULL , TRUE , FALSE , TEXT (" wake_event_" ));
96+ if (wake_event == NULL ) {
97+ // GetLastError()
98+ return std::unexpected (CreateTaskQueueError::CouldNotCreate);
99+ }
100+
101+ return std::make_unique<TaskQueue>(std::move (wake_event));
102+ }
103+
104+ void TaskRunnerLoop (TaskQueue* task_queue) noexcept {
105+ bool continue_looping = true ;
106+ do {
107+ auto task = task_queue->TryPopTask ();
108+ if (task) {
109+ task->Run ();
110+ }
111+ else {
112+ if (task_queue->shutting_down_ ) {
113+ continue_looping = false ;
114+ }
115+ else {
116+ task_queue->WaitForEvent ();
117+ }
118+ }
119+ } while (continue_looping);
120+ }
121+
122+ } // namespace CPU
123+ } // namespace Hardware
124+ } // namespace max
0 commit comments