static int do_test_multiple_waiters(void) { int ii; /* pend all fibers one the same lifo */ for (ii = 0; ii < NUM_WAITERS; ii++) { task_fiber_start(fiber_multi_waiters_stacks[ii], FIBER_STACKSIZE, fiber_multi_waiters, ii, 0, FIBER_PRIORITY, 0); } /* wake up all the fibers: the task is preempted each time */ for (ii = 0; ii < NUM_WAITERS; ii++) { nano_task_lifo_put(&multi_waiters, &multi_waiters_items[ii]); } /* reply_multi_waiters will have been given once for each fiber */ for (ii = 0; ii < NUM_WAITERS; ii++) { if (!nano_task_sem_take(&reply_multi_waiters, TICKS_NONE)) { TC_ERROR(" *** Cannot take sem supposedly given by waiters.\n"); return TC_FAIL; } } TC_PRINT("Task took multi-waiter reply semaphore %d times, as expected.\n", NUM_WAITERS); if (nano_task_lifo_get(&multi_waiters, TICKS_NONE)) { TC_ERROR(" *** multi_waiters should have been empty.\n"); return TC_FAIL; } return TC_PASS; }
int taskLifoWaitTest(void) { void *data; /* ptr to data retrieved from LIFO */ /* Wait on <taskWaitSem> in case fiber's print message blocked */ nano_fiber_sem_take(&taskWaitSem, TICKS_UNLIMITED); /* The fiber is waiting on the LIFO. Wake it. */ nano_task_lifo_put(&test_lifo, &lifoItem[0]); /* * The fiber ran, but is now blocked on the semaphore. Add an item to the * LIFO before giving the semaphore that wakes the fiber so that we can * cover the path of nano_fiber_lifo_get(TICKS_UNLIMITED) not waiting on * the LIFO. */ nano_task_lifo_put(&test_lifo, &lifoItem[2]); nano_task_sem_give(&fiberWaitSem); /* Check that the fiber got the correct item (lifoItem[0]) */ if (fiberDetectedFailure) { TC_ERROR(" *** nano_task_lifo_put()/nano_fiber_lifo_get() failure\n"); return TC_FAIL; } /* The LIFO is empty. This time the task will wait for the item. */ TC_PRINT("Task waiting on an empty LIFO\n"); data = nano_task_lifo_get(&test_lifo, TICKS_UNLIMITED); if (data != (void *) &lifoItem[1]) { TC_ERROR(" *** nano_task_lifo_get()/nano_fiber_lifo_put() failure\n"); return TC_FAIL; } data = nano_task_lifo_get(&test_lifo, TICKS_UNLIMITED); if (data != (void *) &lifoItem[3]) { TC_ERROR(" *** nano_task_lifo_get()/nano_fiber_lifo_put() failure\n"); return TC_FAIL; } /* Waiting on an empty LIFO passed for both fiber and task. */ return TC_PASS; }
void *nano_task_lifo_get_wait_timeout(struct nano_lifo *lifo, int32_t timeout_in_ticks) { int64_t cur_ticks, limit; unsigned int key; void *data; if (unlikely(TICKS_UNLIMITED == timeout_in_ticks)) { return nano_task_lifo_get_wait(lifo); } if (unlikely(TICKS_NONE == timeout_in_ticks)) { return nano_task_lifo_get(lifo); } key = irq_lock_inline(); cur_ticks = nano_tick_get(); limit = cur_ticks + timeout_in_ticks; while (cur_ticks < limit) { /* * Predict that the branch will be taken to break out of the loop. * There is little cost to a misprediction since that leads to idle. */ if (likely(lifo->list)) { data = lifo->list; lifo->list = *(void **)data; irq_unlock_inline(key); return data; } /* see explanation in nano_stack.c:nano_task_stack_pop_wait() */ nano_cpu_atomic_idle(key); key = irq_lock_inline(); cur_ticks = nano_tick_get(); } irq_unlock_inline(key); return NULL; }
/* the timeout test entry point */ static int test_timeout(void) { int64_t orig_ticks; int32_t timeout; int rv; void *packet, *scratch_packet; int test_data_size; int ii; struct reply_packet reply_packet; nano_lifo_init(&lifo_timeout[0]); nano_lifo_init(&lifo_timeout[1]); nano_fifo_init(&timeout_order_fifo); nano_fifo_init(&scratch_q_packets_fifo); for (ii = 0; ii < NUM_SCRATCH_Q_PACKETS; ii++) { scratch_q_packets[ii].data_if_needed = (void *)ii; nano_task_fifo_put(&scratch_q_packets_fifo, &scratch_q_packets[ii]); } /* test nano_task_lifo_get() with timeout */ timeout = 10; orig_ticks = sys_tick_get(); packet = nano_task_lifo_get(&lifo_timeout[0], timeout); if (packet) { TC_ERROR(" *** timeout of %d did not time out.\n", timeout); return TC_FAIL; } if ((sys_tick_get() - orig_ticks) < timeout) { TC_ERROR(" *** task did not wait long enough on timeout of %d.\n", timeout); return TC_FAIL; } /* test nano_task_lifo_get() with timeout of 0 */ packet = nano_task_lifo_get(&lifo_timeout[0], 0); if (packet) { TC_ERROR(" *** timeout of 0 did not time out.\n"); return TC_FAIL; } /* test nano_task_lifo_get() with timeout > 0 */ TC_PRINT("test nano_task_lifo_get() with timeout > 0\n"); timeout = 3; orig_ticks = sys_tick_get(); packet = nano_task_lifo_get(&lifo_timeout[0], timeout); if (packet) { TC_ERROR(" *** timeout of %d did not time out.\n", timeout); return TC_FAIL; } if (!is_timeout_in_range(orig_ticks, timeout)) { return TC_FAIL; } TC_PRINT("nano_task_lifo_get() timed out as expected\n"); /* * test nano_task_lifo_get() with a timeout and fiber that puts * data on the lifo on time */ timeout = 5; orig_ticks = sys_tick_get(); task_fiber_start(timeout_stacks[0], FIBER_STACKSIZE, test_fiber_put_timeout, (int)&lifo_timeout[0], timeout, FIBER_PRIORITY, 0); packet = nano_task_lifo_get(&lifo_timeout[0], (int)(timeout + 5)); if (!packet) { TC_ERROR(" *** data put in time did not return valid pointer.\n"); return TC_FAIL; } put_scratch_packet(packet); if (!is_timeout_in_range(orig_ticks, timeout)) { return TC_FAIL; } TC_PRINT("nano_task_lifo_get() got lifo in time, as expected\n"); /* * test nano_task_lifo_get() with TICKS_NONE and no data * unavailable. */ if (nano_task_lifo_get(&lifo_timeout[0], TICKS_NONE)) { TC_ERROR("task with TICKS_NONE got data, but shouldn't have\n"); return TC_FAIL; } TC_PRINT("task with TICKS_NONE did not get data, as expected\n"); /* * test nano_task_lifo_get() with TICKS_NONE and some data * available. */ scratch_packet = get_scratch_packet(); nano_task_lifo_put(&lifo_timeout[0], scratch_packet); if (!nano_task_lifo_get(&lifo_timeout[0], TICKS_NONE)) { TC_ERROR("task with TICKS_NONE did not get available data\n"); return TC_FAIL; } put_scratch_packet(scratch_packet); TC_PRINT("task with TICKS_NONE got available data, as expected\n"); /* * test nano_task_lifo_get() with TICKS_UNLIMITED and the * data available. */ TC_PRINT("Trying to take available data with TICKS_UNLIMITED:\n" " will hang the test if it fails.\n"); scratch_packet = get_scratch_packet(); nano_task_lifo_put(&lifo_timeout[0], scratch_packet); if (!nano_task_lifo_get(&lifo_timeout[0], TICKS_UNLIMITED)) { TC_ERROR(" *** This will never be hit!!! .\n"); return TC_FAIL; } put_scratch_packet(scratch_packet); TC_PRINT("task with TICKS_UNLIMITED got available data, as expected\n"); /* test fiber with timeout of TICKS_NONE not getting data on empty lifo */ task_fiber_start(timeout_stacks[0], FIBER_STACKSIZE, test_fiber_ticks_special_values, (int)&reply_packet, TICKS_NONE, FIBER_PRIORITY, 0); if (!nano_task_fifo_get(&timeout_order_fifo, TICKS_NONE)) { TC_ERROR(" *** fiber should have run and filled the fifo.\n"); return TC_FAIL; } if (reply_packet.reply != 0) { TC_ERROR(" *** fiber should not have obtained the data.\n"); return TC_FAIL; } TC_PRINT("fiber with TICKS_NONE did not get data, as expected\n"); /* test fiber with timeout of TICKS_NONE getting data when available */ scratch_packet = get_scratch_packet(); nano_task_lifo_put(&lifo_timeout[0], scratch_packet); task_fiber_start(timeout_stacks[0], FIBER_STACKSIZE, test_fiber_ticks_special_values, (int)&reply_packet, TICKS_NONE, FIBER_PRIORITY, 0); put_scratch_packet(scratch_packet); if (!nano_task_fifo_get(&timeout_order_fifo, TICKS_NONE)) { TC_ERROR(" *** fiber should have run and filled the fifo.\n"); return TC_FAIL; } if (reply_packet.reply != 1) { TC_ERROR(" *** fiber should have obtained the data.\n"); return TC_FAIL; } TC_PRINT("fiber with TICKS_NONE got available data, as expected\n"); /* test fiber with TICKS_UNLIMITED timeout getting data when availalble */ scratch_packet = get_scratch_packet(); nano_task_lifo_put(&lifo_timeout[0], scratch_packet); task_fiber_start(timeout_stacks[0], FIBER_STACKSIZE, test_fiber_ticks_special_values, (int)&reply_packet, TICKS_UNLIMITED, FIBER_PRIORITY, 0); put_scratch_packet(scratch_packet); if (!nano_task_fifo_get(&timeout_order_fifo, TICKS_NONE)) { TC_ERROR(" *** fiber should have run and filled the fifo.\n"); return TC_FAIL; } if (reply_packet.reply != 1) { TC_ERROR(" *** fiber should have obtained the data.\n"); return TC_FAIL; } TC_PRINT("fiber with TICKS_UNLIMITED got available data, as expected\n"); /* test multiple fibers pending on the same lifo with different timeouts */ test_data_size = ARRAY_SIZE(timeout_order_data); TC_PRINT("testing timeouts of %d fibers on same lifo\n", test_data_size); rv = test_multiple_fibers_pending(timeout_order_data, test_data_size); if (rv != TC_PASS) { TC_ERROR(" *** fibers did not time out in the right order\n"); return TC_FAIL; } /* test mult. fibers pending on different lifos with different timeouts */ test_data_size = ARRAY_SIZE(timeout_order_data_mult_lifo); TC_PRINT("testing timeouts of %d fibers on different lifos\n", test_data_size); rv = test_multiple_fibers_pending(timeout_order_data_mult_lifo, test_data_size); if (rv != TC_PASS) { TC_ERROR(" *** fibers did not time out in the right order\n"); return TC_FAIL; } /* * test multiple fibers pending on same lifo with different timeouts, but * getting the data in time, except the last one. */ test_data_size = ARRAY_SIZE(timeout_order_data); TC_PRINT("testing %d fibers timing out, but obtaining the data in time\n" "(except the last one, which times out)\n", test_data_size); rv = test_multiple_fibers_get_data(timeout_order_data, test_data_size); if (rv != TC_PASS) { TC_ERROR(" *** fibers did not get the data in the right order\n"); return TC_FAIL; } return TC_PASS; }
int taskLifoNonWaitTest(void) { void *data; /* ptr to data retrieved from LIFO */ /* * The fiber is presently waiting for <fiberWaitSem>. Populate the LIFO * before waking the fiber. */ TC_PRINT("Fiber to get LIFO items without waiting\n"); nano_task_lifo_put(&test_lifo, &lifoItem[2]); nano_task_lifo_put(&test_lifo, &lifoItem[3]); nano_task_sem_give(&fiberWaitSem); /* Wake the fiber */ /* Check that fiber received the items correctly */ if (fiberDetectedFailure) { TC_ERROR(" *** nano_task_lifo_put()/nano_fiber_lifo_get() failure\n"); return TC_FAIL; } /* Wait for the fiber to be ready */ nano_task_sem_take(&taskWaitSem, TICKS_UNLIMITED); data = nano_task_lifo_get(&test_lifo, TICKS_NONE); if (data != (void *) &lifoItem[1]) { TC_ERROR(" *** nano_task_lifo_get()/nano_fiber_lifo_put() failure\n"); return TC_FAIL; } data = nano_task_lifo_get(&test_lifo, TICKS_NONE); if (data != (void *) &lifoItem[0]) { TC_ERROR(" *** nano_task_lifo_get()/nano_fiber_lifo_put() failure\n"); return TC_FAIL; } data = nano_task_lifo_get(&test_lifo, TICKS_NONE); if (data != NULL) { TC_ERROR(" *** nano_task_lifo_get()/nano_fiber_lifo_put() failure\n"); return TC_FAIL; } /* * Software interrupts have been configured so that when invoked, * the ISR will add an item to the LIFO. The fiber (when unblocked) * trigger software interrupts to get the items from the LIFO from * within an ISR. * * Populate the LIFO. */ TC_PRINT("ISR to get LIFO items without waiting\n"); isrLifoInfo.data = &lifoItem[3]; _trigger_nano_isr_lifo_put(); isrLifoInfo.data = &lifoItem[1]; _trigger_nano_isr_lifo_put(); isrLifoInfo.data = NULL; /* Force NULL to ensure [data] changes */ nano_task_sem_give(&fiberWaitSem); /* Wake the fiber */ if (fiberDetectedFailure) { TC_ERROR(" *** nano_isr_lifo_put()/nano_isr_lifo_get() failure\n"); return TC_FAIL; } return TC_PASS; }
/** * * @brief The main test entry * * @return 1 if success and 0 on failure */ int lifo_test(void) { uint32_t t; int i = 0; int return_value = 0; int element[2]; int j; nano_fifo_init(&nanoFifo_sync); /* test get wait & put fiber functions */ fprintf(output_file, sz_test_case_fmt, "LIFO #1"); fprintf(output_file, sz_description, "\n\tnano_lifo_init" "\n\tnano_fiber_lifo_get(TICKS_UNLIMITED)" "\n\tnano_fiber_lifo_put"); printf(sz_test_start_fmt); lifo_test_init(); t = BENCH_START(); task_fiber_start(fiber_stack1, STACK_SIZE, lifo_fiber1, 0, NUMBER_OF_LOOPS, 3, 0); task_fiber_start(fiber_stack2, STACK_SIZE, lifo_fiber2, (int) &i, NUMBER_OF_LOOPS, 3, 0); t = TIME_STAMP_DELTA_GET(t); return_value += check_result(i, t); /* fibers have done their job, they can stop now safely: */ for (j = 0; j < 2; j++) { nano_task_fifo_put(&nanoFifo_sync, (void *) element); } /* test get/yield & put fiber functions */ fprintf(output_file, sz_test_case_fmt, "LIFO #2"); fprintf(output_file, sz_description, "\n\tnano_lifo_init" "\n\tnano_fiber_lifo_get(TICKS_UNLIMITED)" "\n\tnano_fiber_lifo_get(TICKS_NONE)" "\n\tnano_fiber_lifo_put" "\n\tfiber_yield"); printf(sz_test_start_fmt); lifo_test_init(); t = BENCH_START(); i = 0; task_fiber_start(fiber_stack1, STACK_SIZE, lifo_fiber1, 0, NUMBER_OF_LOOPS, 3, 0); task_fiber_start(fiber_stack2, STACK_SIZE, lifo_fiber3, (int) &i, NUMBER_OF_LOOPS, 3, 0); t = TIME_STAMP_DELTA_GET(t); return_value += check_result(i, t); /* fibers have done their job, they can stop now safely: */ for (j = 0; j < 2; j++) { nano_task_fifo_put(&nanoFifo_sync, (void *) element); } /* test get wait & put fiber/task functions */ fprintf(output_file, sz_test_case_fmt, "LIFO #3"); fprintf(output_file, sz_description, "\n\tnano_lifo_init" "\n\tnano_fiber_lifo_get(TICKS_UNLIMITED)" "\n\tnano_fiber_lifo_put" "\n\tnano_task_lifo_get(TICKS_UNLIMITED)" "\n\tnano_task_lifo_put"); printf(sz_test_start_fmt); lifo_test_init(); t = BENCH_START(); task_fiber_start(fiber_stack1, STACK_SIZE, lifo_fiber1, 0, NUMBER_OF_LOOPS, 3, 0); for (i = 0; i < NUMBER_OF_LOOPS / 2; i++) { int element[2]; int *pelement; element[1] = 2 * i; nano_task_lifo_put(&nanoLifo1, element); element[1] = 2 * i + 1; nano_task_lifo_put(&nanoLifo1, element); pelement = (int *)nano_task_lifo_get(&nanoLifo2, TICKS_UNLIMITED); if (pelement[1] != 2 * i + 1) { break; } pelement = (int *)nano_task_lifo_get(&nanoLifo2, TICKS_UNLIMITED); if (pelement[1] != 2 * i) { break; } } t = TIME_STAMP_DELTA_GET(t); return_value += check_result(i * 2, t); /* fibers have done their job, they can stop now safely: */ for (j = 0; j < 2; j++) { nano_task_fifo_put(&nanoFifo_sync, (void *) element); } return return_value; }