summaryrefslogtreecommitdiff
path: root/test/freertos/regression/txfr_queue_create_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/freertos/regression/txfr_queue_create_test.c')
-rw-r--r--test/freertos/regression/txfr_queue_create_test.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/test/freertos/regression/txfr_queue_create_test.c b/test/freertos/regression/txfr_queue_create_test.c
new file mode 100644
index 00000000..aa996070
--- /dev/null
+++ b/test/freertos/regression/txfr_queue_create_test.c
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * Copyright (C) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** FreeRTOS compatibility layer, queue creation resource accounting */
+/** */
+/**************************************************************************/
+
+/* xQueueCreate() takes two byte pool allocations, the descriptor and the
+ backing storage, and then creates two semaphores. Since a failure returns
+ NULL, the caller has no handle and cannot call vQueueDelete(), so anything
+ the layer fails to undo on the way out is lost for good. These checks pin
+ down the accounting on each of those paths.
+
+ The failure paths here are the ones reported in issue 570. */
+
+#include "txfr_test_harness.h"
+
+#include "queue.h"
+
+#define QUEUE_LENGTH 8u
+#define QUEUE_ITEM_SIZE 32u
+
+/* Storage for the static variant. */
+static StaticQueue_t queue_control_block;
+static uint8_t queue_storage[QUEUE_LENGTH * QUEUE_ITEM_SIZE];
+
+
+void txfr_test_body(void)
+{
+ QueueHandle_t queue;
+ TXFR_COUNTERS counters;
+ int i;
+ int cycles;
+
+ /* A successful creation takes both allocations and creates both
+ semaphores, and releases nothing. */
+ txfr_test_account_start(TXFR_INJECT_NONE, 0);
+ queue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreate returns a handle", queue != NULL);
+ txfr_test_check_counts("xQueueCreate accounting", &counters, 2, 0, 2, 0);
+
+ /* Deleting it gives both allocations back and deletes both semaphores. */
+ if(queue != NULL)
+ {
+ txfr_test_account_start(TXFR_INJECT_NONE, 0);
+ vQueueDelete(queue);
+ txfr_test_account_stop(&counters);
+ txfr_test_check_counts("vQueueDelete accounting", &counters, 0, 2, 0, 2);
+ }
+
+ /* The read semaphore fails. Nothing was created that needs deleting, but
+ both allocations must be released. */
+ txfr_test_account_start(TXFR_INJECT_SEMAPHORE_CREATE, 1);
+ queue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreate returns NULL on read_sem failure", queue == NULL);
+ txfr_test_check_counts("read_sem failure releases both allocations", &counters, 2, 2, 1, 0);
+
+ /* The write semaphore fails. The read semaphore already exists by then, so
+ it must be deleted as well as both allocations released. */
+ txfr_test_account_start(TXFR_INJECT_SEMAPHORE_CREATE, 2);
+ queue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreate returns NULL on write_sem failure", queue == NULL);
+ txfr_test_check_counts("write_sem failure unwinds read_sem and memory", &counters, 2, 2, 2, 1);
+
+ /* The static variant takes no allocations and creates both semaphores. */
+ txfr_test_account_start(TXFR_INJECT_NONE, 0);
+ queue = xQueueCreateStatic(QUEUE_LENGTH, QUEUE_ITEM_SIZE, queue_storage, &queue_control_block);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreateStatic returns a handle", queue != NULL);
+ txfr_test_check_counts("xQueueCreateStatic accounting", &counters, 0, 0, 2, 0);
+
+ if(queue != NULL)
+ {
+ txfr_test_account_start(TXFR_INJECT_NONE, 0);
+ vQueueDelete(queue);
+ txfr_test_account_stop(&counters);
+ txfr_test_check_counts("vQueueDelete on static queue", &counters, 0, 0, 0, 2);
+ }
+
+ /* The static variant owns no memory, but it still creates two semaphores
+ and still hands back nothing on failure, so the caller cannot call
+ vQueueDelete(). A read semaphore left behind here would stay registered
+ in the kernel, pointing into the caller's StaticQueue_t. */
+ txfr_test_account_start(TXFR_INJECT_SEMAPHORE_CREATE, 1);
+ queue = xQueueCreateStatic(QUEUE_LENGTH, QUEUE_ITEM_SIZE, queue_storage, &queue_control_block);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreateStatic returns NULL on read_sem failure", queue == NULL);
+ txfr_test_check_counts("static read_sem failure leaves nothing behind", &counters, 0, 0, 1, 0);
+
+ txfr_test_account_start(TXFR_INJECT_SEMAPHORE_CREATE, 2);
+ queue = xQueueCreateStatic(QUEUE_LENGTH, QUEUE_ITEM_SIZE, queue_storage, &queue_control_block);
+ txfr_test_account_stop(&counters);
+ txfr_test_check("xQueueCreateStatic returns NULL on write_sem failure", queue == NULL);
+ txfr_test_check_counts("static write_sem failure unwinds read_sem", &counters, 0, 0, 2, 1);
+
+ /* Repeated create and delete cycles must leave the pool able to serve the
+ same request. This would not catch a small leak on its own, which is why
+ the counts above are checked directly, but it does catch a descriptor
+ that is released to the wrong pool or released twice. */
+ cycles = 0;
+ for(i = 0; i < 64; i++)
+ {
+ queue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
+ if(queue == NULL)
+ {
+ break;
+ }
+
+ cycles++;
+ vQueueDelete(queue);
+ }
+ txfr_test_check("64 create and delete cycles succeed", cycles == 64);
+}