diff --git a/tests/kernel/critical/Makefile b/tests/kernel/critical/Makefile new file mode 100644 index 00000000000..4de50f93d4d --- /dev/null +++ b/tests/kernel/critical/Makefile @@ -0,0 +1,4 @@ +BOARD ?= qemu_x86 +CONF_FILE = prj.conf + +include ${ZEPHYR_BASE}/Makefile.inc diff --git a/tests/kernel/critical/README.txt b/tests/kernel/critical/README.txt new file mode 100644 index 00000000000..1373a613720 --- /dev/null +++ b/tests/kernel/critical/README.txt @@ -0,0 +1,48 @@ +Title: Offload to the Kernel offload workqueue + +Description: + +This test verifies that the kernel offload workqueue operates as +expected. + +This test has two tasks that increment a counter. The routine that +increments the counter is invoked from workqueue due to the two tasks +calling using it. The final result of the counter is expected +to be the the number of times work item was called to increment +the counter. + +This is done with time slicing both disabled and enabled to ensure that the +result always matches the number of times the workqueue is called. + +-------------------------------------------------------------------------------- + +Building and Running Project: + +This microkernel project outputs to the console. It can be built and executed +on QEMU as follows: + + make qemu + +-------------------------------------------------------------------------------- + +Troubleshooting: + +Problems caused by out-dated project information can be addressed by +issuing one of the following commands then rebuilding the project: + + make clean # discard results of previous builds + # but keep existing configuration info +or + make pristine # discard results of previous builds + # and restore pre-defined configuration info + +-------------------------------------------------------------------------------- + +Sample Output: + +Running test suite kernel_critical_test +tc_start() - test_critical +=================================================================== +PASS - test_critical. +=================================================================== +PROJECT EXECUTION SUCCESSFUL diff --git a/tests/kernel/critical/prj.conf b/tests/kernel/critical/prj.conf new file mode 100644 index 00000000000..f4058ca9780 --- /dev/null +++ b/tests/kernel/critical/prj.conf @@ -0,0 +1,2 @@ +CONFIG_NUM_TASK_PRIORITIES=50 +CONFIG_ZTEST=y diff --git a/tests/kernel/critical/src/Makefile b/tests/kernel/critical/src/Makefile new file mode 100644 index 00000000000..4889eef03e6 --- /dev/null +++ b/tests/kernel/critical/src/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -I${ZEPHYR_BASE}/tests/include +include $(ZEPHYR_BASE)/tests/Makefile.test + +obj-y = critical.o diff --git a/tests/kernel/critical/src/critical.c b/tests/kernel/critical/src/critical.c new file mode 100644 index 00000000000..73698cb7b4d --- /dev/null +++ b/tests/kernel/critical/src/critical.c @@ -0,0 +1,200 @@ +/* critical.c - test the offload workqueue API */ + +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * DESCRIPTION + * This module tests the offload workqueue. + */ + +#include +#include +#include + +#define NUM_MILLISECONDS 5000 +#define TEST_TIMEOUT 20000 + +static uint32_t criticalVar; +static uint32_t altTaskIterations; + +static struct k_work_q offload_work_q; +static char __stack offload_work_q_stack[CONFIG_OFFLOAD_WORKQUEUE_STACK_SIZE]; + +#define STACK_SIZE 1024 +static char __stack stack1[STACK_SIZE]; +static char __stack stack2[STACK_SIZE]; + +K_SEM_DEFINE(ALT_SEM, 0, UINT_MAX); +K_SEM_DEFINE(REGRESS_SEM, 0, UINT_MAX); +K_SEM_DEFINE(TEST_SEM, 0, UINT_MAX); + +/** + * + * @brief Routine to be called from a workqueue + * + * This routine increments the global variable . + * + * @return 0 + */ + +void criticalRtn(struct k_work *unused) +{ + volatile uint32_t x; + + ARG_UNUSED(unused); + + x = criticalVar; + criticalVar = x + 1; + +} + +/** + * + * @brief Common code for invoking offload work + * + * @param count number of critical section calls made thus far + * + * @return number of critical section calls made by task + */ + +uint32_t criticalLoop(uint32_t count) +{ + int64_t mseconds; + + mseconds = k_uptime_get(); + while (k_uptime_get() < mseconds + NUM_MILLISECONDS) { + struct k_work work_item; + + k_work_init(&work_item, criticalRtn); + k_work_submit_to_queue(&offload_work_q, &work_item); + count++; + } + + return count; +} + +/** + * + * @brief Alternate task + * + * This routine invokes the workqueue many times. + * + * @return N/A + */ + +void AlternateTask(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + k_sem_take(&ALT_SEM, K_FOREVER); /* Wait to be activated */ + + altTaskIterations = criticalLoop(altTaskIterations); + + k_sem_give(®RESS_SEM); + + k_sem_take(&ALT_SEM, K_FOREVER); /* Wait to be re-activated */ + + altTaskIterations = criticalLoop(altTaskIterations); + + k_sem_give(®RESS_SEM); +} + +/** + * + * @brief Regression task + * + * This routine calls invokes the workqueue many times. It also checks to + * ensure that the number of times it is called matches the global variable + * . + * + * @return N/A + */ + +void RegressionTask(void *arg1, void *arg2, void *arg3) +{ + uint32_t nCalls = 0; + + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + k_sem_give(&ALT_SEM); /* Activate AlternateTask() */ + + nCalls = criticalLoop(nCalls); + + /* Wait for AlternateTask() to complete */ + assert_true(k_sem_take(®RESS_SEM, TEST_TIMEOUT) == 0, + "Timed out waiting for REGRESS_SEM"); + + assert_equal(criticalVar, nCalls + altTaskIterations, + "Unexpected value for "); + + k_sched_time_slice_set(10, 10); + + k_sem_give(&ALT_SEM); /* Re-activate AlternateTask() */ + + nCalls = criticalLoop(nCalls); + + /* Wait for AlternateTask() to finish */ + assert_true(k_sem_take(®RESS_SEM, TEST_TIMEOUT) == 0, + "Timed out waiting for REGRESS_SEM"); + + assert_equal(criticalVar, nCalls + altTaskIterations, + "Unexpected value for "); + + k_sem_give(&TEST_SEM); + +} + +static void init_objects(void) +{ + criticalVar = 0; + altTaskIterations = 0; + k_work_q_start(&offload_work_q, + offload_work_q_stack, + sizeof(offload_work_q_stack), + CONFIG_OFFLOAD_WORKQUEUE_PRIORITY); +} + +static void start_threads(void) +{ + k_thread_spawn(stack1, STACK_SIZE, + AlternateTask, NULL, NULL, NULL, + K_PRIO_PREEMPT(12), 0, 0); + + k_thread_spawn(stack2, STACK_SIZE, + RegressionTask, NULL, NULL, NULL, + K_PRIO_PREEMPT(12), 0, 0); +} + +void test_critical(void) +{ + init_objects(); + start_threads(); + + assert_true(k_sem_take(&TEST_SEM, TEST_TIMEOUT * 2) == 0, + "Timed out waiting for TEST_SEM"); +} + +void test_main(void) +{ + ztest_test_suite(kernel_critical_test, ztest_unit_test(test_critical)); + + ztest_run_test_suite(kernel_critical_test); +} diff --git a/tests/kernel/critical/testcase.ini b/tests/kernel/critical/testcase.ini new file mode 100644 index 00000000000..fc3e56d847c --- /dev/null +++ b/tests/kernel/critical/testcase.ini @@ -0,0 +1,2 @@ +[test] +tags = core bat_commit