Jira: ZEP-932 Change-Id: I79eb4cb20cd0e0df60f71cb73969a76e2c929b8e Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
394 lines
7.9 KiB
C
394 lines
7.9 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <zephyr.h>
|
|
#include <nanokernel.h>
|
|
#include <tc_util.h>
|
|
#include <misc/util.h>
|
|
#include <misc/nano_work.h>
|
|
|
|
#define NUM_TEST_ITEMS 6
|
|
/* Each work item takes 100ms */
|
|
#define WORK_ITEM_WAIT 100
|
|
|
|
/*
|
|
* Wait 50ms between work submissions, to ensure co-op and prempt
|
|
* preempt thread submit alternatively.
|
|
*/
|
|
#define SUBMIT_WAIT 50
|
|
|
|
#define STACK_SIZE 1024
|
|
|
|
struct test_item {
|
|
int key;
|
|
struct k_delayed_work work;
|
|
};
|
|
|
|
static char __stack co_op_stack[STACK_SIZE];
|
|
|
|
static struct test_item tests[NUM_TEST_ITEMS];
|
|
|
|
static int results[NUM_TEST_ITEMS];
|
|
static int num_results;
|
|
|
|
static void work_handler(struct k_work *work)
|
|
{
|
|
struct test_item *ti = CONTAINER_OF(work, struct test_item, work);
|
|
|
|
TC_PRINT(" - Running test item %d\n", ti->key);
|
|
k_sleep(WORK_ITEM_WAIT);
|
|
|
|
results[num_results++] = ti->key;
|
|
}
|
|
|
|
static void test_items_init(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i++) {
|
|
tests[i].key = i + 1;
|
|
k_work_init(&tests[i].work.work, work_handler);
|
|
}
|
|
}
|
|
|
|
static void coop_work_main(int arg1, int arg2)
|
|
{
|
|
int i;
|
|
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
|
|
/* Let the preempt thread submit the first work item. */
|
|
k_sleep(SUBMIT_WAIT / 2);
|
|
|
|
for (i = 1; i < NUM_TEST_ITEMS; i += 2) {
|
|
TC_PRINT(" - Submitting work %d from coop thread\n", i + 1);
|
|
k_work_submit(&tests[i].work.work);
|
|
k_sleep(SUBMIT_WAIT);
|
|
}
|
|
}
|
|
|
|
static void test_items_submit(void)
|
|
{
|
|
int i;
|
|
|
|
k_thread_spawn(co_op_stack, STACK_SIZE,
|
|
(k_thread_entry_t)coop_work_main,
|
|
NULL, NULL,
|
|
NULL, K_PRIO_COOP(10), 0, 0);
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i += 2) {
|
|
TC_PRINT(" - Submitting work %d from preempt thread\n", i + 1);
|
|
k_work_submit(&tests[i].work.work);
|
|
k_sleep(SUBMIT_WAIT);
|
|
}
|
|
}
|
|
|
|
static int check_results(int num_tests)
|
|
{
|
|
int i;
|
|
|
|
if (num_results != num_tests) {
|
|
TC_ERROR("*** work items finished: %d (expected: %d)\n",
|
|
num_results, num_tests);
|
|
return TC_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < num_tests; i++) {
|
|
if (results[i] != i + 1) {
|
|
TC_ERROR("*** got result %d in position %d"
|
|
" (expected %d)\n",
|
|
results[i], i, i + 1);
|
|
return TC_FAIL;
|
|
}
|
|
}
|
|
|
|
return TC_PASS;
|
|
}
|
|
|
|
static int test_sequence(void)
|
|
{
|
|
TC_PRINT("Starting sequence test\n");
|
|
|
|
TC_PRINT(" - Initializing test items\n");
|
|
test_items_init();
|
|
|
|
TC_PRINT(" - Submitting test items\n");
|
|
test_items_submit();
|
|
|
|
TC_PRINT(" - Waiting for work to finish\n");
|
|
k_sleep((NUM_TEST_ITEMS + 1) * WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(NUM_TEST_ITEMS);
|
|
}
|
|
|
|
|
|
static void reset_results(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i++)
|
|
results[i] = 0;
|
|
|
|
num_results = 0;
|
|
}
|
|
|
|
static void resubmit_work_handler(struct k_work *work)
|
|
{
|
|
struct test_item *ti = CONTAINER_OF(work, struct test_item, work);
|
|
|
|
k_sleep(WORK_ITEM_WAIT);
|
|
|
|
results[num_results++] = ti->key;
|
|
|
|
if (ti->key < NUM_TEST_ITEMS) {
|
|
ti->key++;
|
|
TC_PRINT(" - Resubmitting work\n");
|
|
k_work_submit(work);
|
|
}
|
|
}
|
|
|
|
static int test_resubmit(void)
|
|
{
|
|
TC_PRINT("Starting resubmit test\n");
|
|
|
|
tests[0].key = 1;
|
|
tests[0].work.work.handler = resubmit_work_handler;
|
|
|
|
TC_PRINT(" - Submitting work\n");
|
|
k_work_submit(&tests[0].work.work);
|
|
|
|
TC_PRINT(" - Waiting for work to finish\n");
|
|
k_sleep((NUM_TEST_ITEMS + 1) * WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(NUM_TEST_ITEMS);
|
|
}
|
|
|
|
static void delayed_work_handler(struct k_work *work)
|
|
{
|
|
struct test_item *ti = CONTAINER_OF(work, struct test_item, work);
|
|
|
|
TC_PRINT(" - Running delayed test item %d\n", ti->key);
|
|
|
|
results[num_results++] = ti->key;
|
|
}
|
|
|
|
static void test_delayed_init(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i++) {
|
|
tests[i].key = i + 1;
|
|
k_delayed_work_init(&tests[i].work, delayed_work_handler);
|
|
}
|
|
}
|
|
|
|
static void coop_delayed_work_main(int arg1, int arg2)
|
|
{
|
|
int i;
|
|
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
|
|
/* Let the preempt thread submit the first work item. */
|
|
k_sleep(SUBMIT_WAIT / 2);
|
|
|
|
for (i = 1; i < NUM_TEST_ITEMS; i += 2) {
|
|
TC_PRINT(" - Submitting delayed work %d from"
|
|
" coop thread\n", i + 1);
|
|
k_delayed_work_submit(&tests[i].work,
|
|
(i + 1) * WORK_ITEM_WAIT);
|
|
}
|
|
}
|
|
|
|
static int test_delayed_submit(void)
|
|
{
|
|
int i;
|
|
|
|
k_thread_spawn(co_op_stack, STACK_SIZE,
|
|
(k_thread_entry_t)coop_delayed_work_main,
|
|
NULL, NULL, NULL, K_PRIO_COOP(10), 0, 0);
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i += 2) {
|
|
TC_PRINT(" - Submitting delayed work %d from"
|
|
" preempt thread\n", i + 1);
|
|
if (k_delayed_work_submit(&tests[i].work,
|
|
(i + 1) * WORK_ITEM_WAIT)) {
|
|
return TC_FAIL;
|
|
}
|
|
}
|
|
|
|
return TC_PASS;
|
|
}
|
|
|
|
static void coop_delayed_work_cancel_main(int arg1, int arg2)
|
|
{
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
|
|
k_delayed_work_submit(&tests[1].work, WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Cancel delayed work from coop thread\n");
|
|
k_delayed_work_cancel(&tests[1].work);
|
|
}
|
|
|
|
static int test_delayed_cancel(void)
|
|
{
|
|
TC_PRINT("Starting delayed cancel test\n");
|
|
|
|
k_delayed_work_submit(&tests[0].work, WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Cancel delayed work from preempt thread\n");
|
|
k_delayed_work_cancel(&tests[0].work);
|
|
|
|
k_thread_spawn(co_op_stack, STACK_SIZE,
|
|
(k_thread_entry_t)coop_delayed_work_cancel_main,
|
|
NULL, NULL, NULL, K_PRIO_COOP(10), 0, 0);
|
|
|
|
TC_PRINT(" - Waiting for work to finish\n");
|
|
k_sleep(2 * WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(0);
|
|
}
|
|
|
|
static void delayed_resubmit_work_handler(struct k_work *work)
|
|
{
|
|
struct test_item *ti = CONTAINER_OF(work, struct test_item, work);
|
|
|
|
results[num_results++] = ti->key;
|
|
|
|
if (ti->key < NUM_TEST_ITEMS) {
|
|
ti->key++;
|
|
TC_PRINT(" - Resubmitting delayed work\n");
|
|
k_delayed_work_submit(&ti->work, WORK_ITEM_WAIT);
|
|
}
|
|
}
|
|
|
|
static int test_delayed_resubmit(void)
|
|
{
|
|
TC_PRINT("Starting delayed resubmit test\n");
|
|
|
|
tests[0].key = 1;
|
|
k_delayed_work_init(&tests[0].work, delayed_resubmit_work_handler);
|
|
|
|
TC_PRINT(" - Submitting delayed work\n");
|
|
k_delayed_work_submit(&tests[0].work, WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Waiting for work to finish\n");
|
|
k_sleep((NUM_TEST_ITEMS + 1) * WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(NUM_TEST_ITEMS);
|
|
}
|
|
|
|
static void coop_delayed_work_resubmit(int arg1, int arg2)
|
|
{
|
|
int i;
|
|
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
|
|
for (i = 0; i < NUM_TEST_ITEMS; i++) {
|
|
volatile uint32_t uptime;
|
|
|
|
TC_PRINT(" - Resubmitting delayed work with 1 ms\n");
|
|
k_delayed_work_submit(&tests[0].work, 1);
|
|
|
|
/* Busy wait 1 ms to force a clash with workqueue */
|
|
uptime = k_uptime_get_32();
|
|
while (k_uptime_get_32() == uptime) {
|
|
}
|
|
}
|
|
}
|
|
|
|
static int test_delayed_resubmit_fiber(void)
|
|
{
|
|
TC_PRINT("Starting delayed resubmit from coop thread test\n");
|
|
|
|
tests[0].key = 1;
|
|
k_delayed_work_init(&tests[0].work, delayed_work_handler);
|
|
|
|
k_thread_spawn(co_op_stack, STACK_SIZE,
|
|
(k_thread_entry_t)coop_delayed_work_resubmit,
|
|
NULL, NULL, NULL, K_PRIO_COOP(10), 0, 0);
|
|
|
|
TC_PRINT(" - Waiting for work to finish\n");
|
|
k_sleep(NUM_TEST_ITEMS + 1);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(1);
|
|
}
|
|
|
|
static int test_delayed(void)
|
|
{
|
|
TC_PRINT("Starting delayed test\n");
|
|
|
|
TC_PRINT(" - Initializing delayed test items\n");
|
|
test_delayed_init();
|
|
|
|
TC_PRINT(" - Submitting delayed test items\n");
|
|
if (test_delayed_submit() != TC_PASS) {
|
|
return TC_FAIL;
|
|
}
|
|
|
|
TC_PRINT(" - Waiting for delayed work to finish\n");
|
|
k_sleep((NUM_TEST_ITEMS + 2) * WORK_ITEM_WAIT);
|
|
|
|
TC_PRINT(" - Checking results\n");
|
|
return check_results(NUM_TEST_ITEMS);
|
|
}
|
|
|
|
|
|
void main(void)
|
|
{
|
|
int status = TC_FAIL;
|
|
|
|
if (test_sequence() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
reset_results();
|
|
|
|
if (test_resubmit() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
reset_results();
|
|
|
|
if (test_delayed() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
reset_results();
|
|
|
|
if (test_delayed_resubmit() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
reset_results();
|
|
|
|
if (test_delayed_resubmit_fiber() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
reset_results();
|
|
|
|
if (test_delayed_cancel() != TC_PASS) {
|
|
goto end;
|
|
}
|
|
|
|
status = TC_PASS;
|
|
|
|
end:
|
|
TC_END_RESULT(status);
|
|
TC_END_REPORT(status);
|
|
}
|