| /* |
| * Copyright (c) 2016 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. |
| */ |
| |
| /* |
| * @file |
| * @brief Test nanokernel sleep and wakeup APIs |
| * |
| * This module tests the following sleep and wakeup scenarios: |
| * 1. fiber_sleep() without cancellation |
| * 2. fiber_sleep() cancelled via fiber_fiber_wakeup() |
| * 3. fiber_sleep() cancelled via isr_fiber_wakeup() |
| * 4. fiber_sleep() cancelled via task_fiber_wakeup() |
| * 5. task_sleep() - no cancellation exists |
| */ |
| |
| #include <tc_util.h> |
| #include <arch/cpu.h> |
| #include <misc/util.h> |
| #include <irq_offload.h> |
| #include <stdbool.h> |
| |
| #include <util_test_common.h> |
| |
| #define FIBER_STACKSIZE 256 |
| |
| #define TEST_FIBER_PRIORITY 4 |
| #define HELPER_FIBER_PRIORITY 10 |
| |
| #define ONE_SECOND (sys_clock_ticks_per_sec) |
| |
| static struct nano_sem test_fiber_sem; |
| static struct nano_sem helper_fiber_sem; |
| static struct nano_sem task_sem; |
| |
| static char __stack test_fiber_stack[FIBER_STACKSIZE]; |
| static char __stack helper_fiber_stack[FIBER_STACKSIZE]; |
| |
| static nano_thread_id_t test_fiber_id; |
| static nano_thread_id_t helper_fiber_id; |
| |
| static bool test_failure = true; /* Assume the test will fail */ |
| |
| static void test_objects_init(void) |
| { |
| nano_sem_init(&test_fiber_sem); |
| nano_sem_init(&helper_fiber_sem); |
| nano_sem_init(&task_sem); |
| |
| TC_PRINT("Nanokernel objects initialized\n"); |
| } |
| |
| static void align_to_tick_boundary(void) |
| { |
| uint32_t tick; |
| |
| tick = sys_tick_get_32(); |
| while (sys_tick_get_32() == tick) { |
| /* Busy wait to align to tick boundary */ |
| } |
| } |
| |
| static void test_fiber(int arg1, int arg2) |
| { |
| uint32_t start_tick; |
| uint32_t end_tick; |
| |
| nano_fiber_sem_take(&test_fiber_sem, TICKS_UNLIMITED); |
| |
| TC_PRINT("Testing normal expiration of fiber_sleep()\n"); |
| align_to_tick_boundary(); |
| |
| start_tick = sys_tick_get_32(); |
| fiber_sleep(ONE_SECOND); |
| end_tick = sys_tick_get_32(); |
| |
| if (end_tick != start_tick + ONE_SECOND) { |
| TC_ERROR(" *** fiber_sleep() slept for %d ticks not %d.", |
| end_tick - start_tick, ONE_SECOND); |
| |
| return; |
| } |
| |
| TC_PRINT("Testing fiber_sleep() + fiber_fiber_wakeup()\n"); |
| nano_fiber_sem_give(&helper_fiber_sem); /* Activate helper fiber */ |
| align_to_tick_boundary(); |
| |
| start_tick = sys_tick_get_32(); |
| fiber_sleep(ONE_SECOND); |
| end_tick = sys_tick_get_32(); |
| |
| if (end_tick > start_tick) { |
| TC_ERROR(" *** fiber_fiber_wakeup() took too long (%d ticks)\n", |
| end_tick - start_tick); |
| return; |
| } |
| |
| TC_PRINT("Testing fiber_sleep() + isr_fiber_wakeup()\n"); |
| nano_fiber_sem_give(&helper_fiber_sem); /* Activate helper fiber */ |
| align_to_tick_boundary(); |
| |
| start_tick = sys_tick_get_32(); |
| fiber_sleep(ONE_SECOND); |
| end_tick = sys_tick_get_32(); |
| |
| if (end_tick > start_tick) { |
| TC_ERROR(" *** isr_fiber_wakeup() took too long (%d ticks)\n", |
| end_tick - start_tick); |
| return; |
| } |
| |
| TC_PRINT("Testing fiber_sleep() + task_fiber_wakeup()\n"); |
| nano_task_sem_give(&task_sem); /* Activate task */ |
| align_to_tick_boundary(); |
| |
| start_tick = sys_tick_get_32(); |
| fiber_sleep(ONE_SECOND); /* Task will execute */ |
| end_tick = sys_tick_get_32(); |
| |
| if (end_tick > start_tick) { |
| TC_ERROR(" *** task_fiber_wakeup() took too long (%d ticks)\n", |
| end_tick - start_tick); |
| return; |
| } |
| |
| test_failure = false; |
| } |
| |
| static void irq_offload_isr(void *arg) |
| { |
| isr_fiber_wakeup((nano_thread_id_t) arg); |
| } |
| |
| static void helper_fiber(int arg1, int arg2) |
| { |
| nano_fiber_sem_take(&helper_fiber_sem, TICKS_UNLIMITED); |
| |
| /* Wake the test fiber */ |
| fiber_fiber_wakeup(test_fiber_id); |
| nano_fiber_sem_take(&helper_fiber_sem, TICKS_UNLIMITED); |
| |
| /* Wake the test fiber from an ISR */ |
| irq_offload(irq_offload_isr, (void *)test_fiber_id); |
| } |
| |
| void main(void) |
| { |
| int status = TC_FAIL; |
| uint32_t start_tick; |
| uint32_t end_tick; |
| |
| TC_START("Test Nanokernel Sleep and Wakeup APIs\n"); |
| |
| test_objects_init(); |
| |
| test_fiber_id = task_fiber_start(test_fiber_stack, FIBER_STACKSIZE, |
| test_fiber, 0, 0, TEST_FIBER_PRIORITY, 0); |
| TC_PRINT("Test fiber started: id = 0x%x\n", test_fiber_id); |
| |
| helper_fiber_id = task_fiber_start(helper_fiber_stack, FIBER_STACKSIZE, |
| helper_fiber, 0, 0, HELPER_FIBER_PRIORITY, 0); |
| TC_PRINT("Helper fiber started: id = 0x%x\n", helper_fiber_id); |
| |
| /* Activate test_fiber */ |
| nano_task_sem_give(&test_fiber_sem); |
| |
| /* Wait for test_fiber to activate us */ |
| nano_task_sem_take(&task_sem, TICKS_UNLIMITED); |
| |
| /* Wake the test fiber */ |
| task_fiber_wakeup(test_fiber_id); |
| |
| if (test_failure) { |
| goto done_tests; |
| } |
| |
| TC_PRINT("Testing nanokernel task_sleep()\n"); |
| align_to_tick_boundary(); |
| start_tick = sys_tick_get_32(); |
| task_sleep(ONE_SECOND); |
| end_tick = sys_tick_get_32(); |
| |
| if (end_tick - start_tick != ONE_SECOND) { |
| TC_ERROR("task_sleep() slept for %d ticks, not %d\n", |
| end_tick - start_tick, ONE_SECOND); |
| goto done_tests; |
| } |
| |
| status = TC_PASS; |
| |
| done_tests: |
| TC_END_REPORT(status); |
| } |