blob: 87ba14a30b4e6596b4765f5b332d4f4e17bc36da [file] [log] [blame]
// Copyright Microsoft and CHERIoT Contributors.
// SPDX-License-Identifier: MIT
#define TEST_NAME "Queue"
#include "tests.hh"
#include <debug.hh>
#include <errno.h>
#include <futex.h>
#include <queue.h>
#include <thread_pool.h>
#include <timeout.h>
using thread_pool::async;
static constexpr size_t ItemSize = 8;
static constexpr size_t MaxItems = 2;
static constexpr char Message[MaxItems][ItemSize] = {"TstMsg0", "TstMsg1"};
void test_queue()
{
static uint32_t futex;
char bytes[ItemSize];
static void *queue;
Timeout timeout{0, 0};
debug_log("Testing queue send operations");
int rv =
queue_create(&timeout, MALLOC_CAPABILITY, &queue, ItemSize, MaxItems);
TEST(rv == 0, "Queue creation failed with {}", rv);
rv = queue_send(&timeout, queue, Message[0]);
TEST(rv == 0, "Sending the first message failed with {}", rv);
rv = queue_send(&timeout, queue, Message[1]);
TEST(rv == 0, "Sending the second message failed with {}", rv);
// Queue is full, it should time out.
timeout.remaining = 5;
rv = queue_send(&timeout, queue, Message[1]);
TEST(rv == -ETIMEDOUT,
"Sending to a full queue didn't time out as expected, returned {}",
rv);
debug_log("Testing queue receive operations");
timeout.remaining = 10;
rv = queue_recv(&timeout, queue, bytes);
TEST(rv == 0, "Receiving the first message failed with {}", rv);
TEST(memcmp(Message[0], bytes, ItemSize) == 0,
"First message received but not as expected. Got {}",
bytes);
rv = queue_recv(&timeout, queue, bytes);
TEST(rv == 0, "Receiving the second message failed with {}", rv);
TEST(memcmp(Message[1], bytes, ItemSize) == 0,
"Second message received but not as expected. Got {}",
bytes);
timeout.remaining = 5;
rv = queue_recv(&timeout, queue, bytes);
TEST(
rv == -ETIMEDOUT,
"Receiving from an empty queue didn't time out as expected, returned {}",
rv);
debug_log("Testing queue deletion right underneath another thread");
async([]() {
char bytesForAsync[ItemSize];
Timeout infinity{0, UnlimitedTimeout};
/*
* This test waits on a queue indefinitely, but will be woken up by the
* queue_delete() in the main thread. After waking up, the queue object
* is dead and will trap, causing a force unwind in the scheduler
* compartment.
*/
int rv = queue_recv(&infinity, queue, bytesForAsync);
TEST(
rv == -1,
"queue_recv() should return -1 because the queue was freed() "
"underneath us and will trap then force unwind, but instead got {}",
rv);
futex = 1;
futex_wake(&futex, 1);
});
timeout.remaining = 20;
thread_sleep(&timeout);
rv = queue_delete(MALLOC_CAPABILITY, queue);
TEST(rv == 0, "Queue deletion failed with {}", rv);
// Wait until the async is done.
rv = futex_wait(&futex, 0);
TEST(rv == 0, "futex_wait() failed with {}", rv);
debug_log("All queue tests successful");
}