163 lines
4.9 KiB
C++
163 lines
4.9 KiB
C++
#include "foundation/task_queue.h"
|
|
#include "test_harness.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace {
|
|
|
|
struct NestedPushPayload {
|
|
pp::foundation::TaskQueue* queue = nullptr;
|
|
std::vector<int>* order = nullptr;
|
|
};
|
|
|
|
struct MarkerPayload {
|
|
std::vector<int>* order = nullptr;
|
|
int marker = 0;
|
|
};
|
|
|
|
struct HandoffPayload {
|
|
pp::foundation::TaskQueue* ui_queue = nullptr;
|
|
std::vector<int>* order = nullptr;
|
|
int worker_marker = 0;
|
|
MarkerPayload* ui_marker = nullptr;
|
|
};
|
|
|
|
void nested_push_task(void* user_data) noexcept
|
|
{
|
|
auto* payload = static_cast<NestedPushPayload*>(user_data);
|
|
payload->order->push_back(1);
|
|
payload->queue->push(pp::foundation::TaskItem { .callback = [](void* callback_data) noexcept {
|
|
auto* inner = static_cast<std::vector<int>*>(callback_data);
|
|
inner->push_back(2);
|
|
}, .user_data = payload->order, .id = 2 });
|
|
}
|
|
|
|
void record_marker_task(void* user_data) noexcept
|
|
{
|
|
auto* payload = static_cast<MarkerPayload*>(user_data);
|
|
payload->order->push_back(payload->marker);
|
|
}
|
|
|
|
void handoff_to_ui_queue_task(void* user_data) noexcept
|
|
{
|
|
const auto payload = static_cast<HandoffPayload*>(user_data);
|
|
payload->order->push_back(payload->worker_marker);
|
|
payload->ui_queue->push(pp::foundation::TaskItem {
|
|
.callback = record_marker_task,
|
|
.user_data = payload->ui_marker,
|
|
.id = static_cast<std::uint64_t>(payload->worker_marker),
|
|
});
|
|
}
|
|
|
|
void runs_nested_push_tasks_deterministically(pp::tests::Harness& harness)
|
|
{
|
|
pp::foundation::TaskQueue queue;
|
|
std::vector<int> order;
|
|
NestedPushPayload payload { .queue = &queue, .order = &order };
|
|
|
|
PP_EXPECT(harness, queue.push(pp::foundation::TaskItem {
|
|
.callback = nested_push_task,
|
|
.user_data = &payload,
|
|
.id = 1
|
|
}).ok());
|
|
|
|
PP_EXPECT(harness, queue.run_all() == 2U);
|
|
PP_EXPECT(harness, order.size() == 2U);
|
|
PP_EXPECT(harness, order[0] == 1);
|
|
PP_EXPECT(harness, order[1] == 2);
|
|
PP_EXPECT(harness, queue.empty());
|
|
}
|
|
|
|
void worker_to_ui_queue_handoff_is_ordered(pp::tests::Harness& harness)
|
|
{
|
|
pp::foundation::TaskQueue worker_queue;
|
|
pp::foundation::TaskQueue ui_queue;
|
|
std::vector<int> order;
|
|
|
|
MarkerPayload marker_payloads[] = {
|
|
{ .order = &order, .marker = 2 },
|
|
{ .order = &order, .marker = 3 },
|
|
};
|
|
HandoffPayload worker_payloads[] = {
|
|
{
|
|
.ui_queue = &ui_queue,
|
|
.order = &order,
|
|
.worker_marker = 1,
|
|
.ui_marker = &marker_payloads[0],
|
|
},
|
|
{
|
|
.ui_queue = &ui_queue,
|
|
.order = &order,
|
|
.worker_marker = 4,
|
|
.ui_marker = &marker_payloads[1],
|
|
},
|
|
};
|
|
|
|
PP_EXPECT(harness, worker_queue.push(pp::foundation::TaskItem {
|
|
.callback = handoff_to_ui_queue_task,
|
|
.user_data = &worker_payloads[0],
|
|
.id = 1,
|
|
}).ok());
|
|
PP_EXPECT(harness, worker_queue.push(pp::foundation::TaskItem {
|
|
.callback = handoff_to_ui_queue_task,
|
|
.user_data = &worker_payloads[1],
|
|
.id = 2,
|
|
}).ok());
|
|
|
|
PP_EXPECT(harness, worker_queue.run_all() == 2U);
|
|
PP_EXPECT(harness, order.size() == 2U);
|
|
PP_EXPECT(harness, order[0] == 1);
|
|
PP_EXPECT(harness, order[1] == 4);
|
|
PP_EXPECT(harness, worker_queue.empty());
|
|
PP_EXPECT(harness, !ui_queue.empty());
|
|
|
|
PP_EXPECT(harness, ui_queue.run_all() == 2U);
|
|
PP_EXPECT(harness, order.size() == 4U);
|
|
PP_EXPECT(harness, order[2] == 2);
|
|
PP_EXPECT(harness, order[3] == 3);
|
|
PP_EXPECT(harness, ui_queue.empty());
|
|
}
|
|
|
|
void stress_batch_push_and_overflow_reported(pp::tests::Harness& harness)
|
|
{
|
|
constexpr std::size_t batch_size = 32U;
|
|
pp::foundation::TaskQueue queue(batch_size);
|
|
|
|
int counter = 0;
|
|
for (std::size_t i = 0U; i < batch_size; ++i)
|
|
{
|
|
PP_EXPECT(harness, queue.push(pp::foundation::TaskItem {
|
|
.callback = [](void* user_data) noexcept
|
|
{
|
|
++*static_cast<int*>(user_data);
|
|
},
|
|
.user_data = &counter,
|
|
.id = static_cast<std::uint64_t>(i + 1),
|
|
}).ok());
|
|
}
|
|
|
|
const auto overflow = queue.push(pp::foundation::TaskItem {
|
|
.callback = [](void* user_data) noexcept
|
|
{
|
|
++*static_cast<int*>(user_data);
|
|
},
|
|
.user_data = &counter,
|
|
.id = batch_size + 1U,
|
|
});
|
|
PP_EXPECT(harness, !overflow.ok());
|
|
PP_EXPECT(harness, queue.run_all() == batch_size);
|
|
PP_EXPECT(harness, counter == static_cast<int>(batch_size));
|
|
PP_EXPECT(harness, queue.empty());
|
|
}
|
|
|
|
}
|
|
|
|
int main()
|
|
{
|
|
pp::tests::Harness harness;
|
|
harness.run("nested pushes are executed deterministically", runs_nested_push_tasks_deterministically);
|
|
harness.run("worker to UI queue handoff preserves order", worker_to_ui_queue_handoff_is_ordered);
|
|
harness.run("stress batch push reports overflow and drains deterministically", stress_batch_push_and_overflow_reported);
|
|
return harness.finish();
|
|
}
|