Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kernel: queue, fifo: Add cancel_wait operation. #26

Merged
merged 1 commit into from
May 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,20 @@ struct k_queue {
*/
extern void k_queue_init(struct k_queue *queue);

/**
* @brief Cancel waiting on a queue.
*
* This routine causes first thread pending on @a queue, if any, to
* return from k_queue_get() call with NULL value (as if timeout expired).
*
* @note Can be called by ISRs.
*
* @param queue Address of the queue.
*
* @return N/A
*/
extern void k_queue_cancel_wait(struct k_queue *queue);

/**
* @brief Append an element to the end of a queue.
*
Expand Down Expand Up @@ -1445,6 +1459,22 @@ struct k_fifo {
#define k_fifo_init(fifo) \
k_queue_init((struct k_queue *) fifo)

/**
* @brief Cancel waiting on a fifo.
*
* This routine causes first thread pending on @a fifo, if any, to
* return from k_fifo_get() call with NULL value (as if timeout
* expired).
*
* @note Can be called by ISRs.
*
* @param fifo Address of the fifo.
*
* @return N/A
*/
#define k_fifo_cancel_wait(fifo) \
k_queue_cancel_wait((struct k_queue *) fifo)

/**
* @brief Add an element to a fifo.
*
Expand Down
25 changes: 25 additions & 0 deletions kernel/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ static inline int handle_poll_event(struct k_queue *queue)
#endif
}

void k_queue_cancel_wait(struct k_queue *queue)
{
struct k_thread *first_pending_thread;
unsigned int key;

key = irq_lock();

first_pending_thread = _unpend_first_thread(&queue->wait_q);

if (first_pending_thread) {
prepare_thread_to_run(first_pending_thread, NULL);
if (!_is_in_isr() && _must_switch_threads()) {
(void)_Swap(key);
return;
}
} else {
if (handle_poll_event(queue)) {
(void)_Swap(key);
return;
}
}

irq_unlock(key);
}

void k_queue_insert(struct k_queue *queue, void *prev, void *data)
{
struct k_thread *first_pending_thread;
Expand Down
3 changes: 2 additions & 1 deletion tests/kernel/fifo/test_fifo_api/src/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include $(ZEPHYR_BASE)/tests/Makefile.test

obj-y = main.o test_fifo_contexts.o test_fifo_fail.o test_fifo_loop.o
obj-y = main.o test_fifo_contexts.o test_fifo_fail.o test_fifo_loop.o \
test_fifo_cancel.o
2 changes: 2 additions & 0 deletions tests/kernel/fifo/test_fifo_api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extern void test_fifo_thread2isr(void);
extern void test_fifo_isr2thread(void);
extern void test_fifo_get_fail(void);
extern void test_fifo_loop(void);
extern void test_fifo_cancel_wait(void);
extern void test_fifo_is_empty_thread(void);
extern void test_fifo_is_empty_isr(void);

Expand All @@ -29,6 +30,7 @@ void test_main(void *p1, void *p2, void *p3)
ztest_unit_test(test_fifo_isr2thread),
ztest_unit_test(test_fifo_get_fail),
ztest_unit_test(test_fifo_loop),
ztest_unit_test(test_fifo_cancel_wait),
ztest_unit_test(test_fifo_is_empty_thread),
ztest_unit_test(test_fifo_is_empty_isr));
ztest_run_test_suite(test_fifo_api);
Expand Down
56 changes: 56 additions & 0 deletions tests/kernel/fifo/test_fifo_api/src/test_fifo_cancel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "test_fifo.h"

#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
#define LIST_LEN 2
/**TESTPOINT: init via K_FIFO_DEFINE*/
K_FIFO_DEFINE(kfifo_c);

struct k_fifo fifo_c;

static char __noinit __stack tstack[STACK_SIZE];

static void t_cancel_wait_entry(void *p1, void *p2, void *p3)
{
k_sleep(50);
k_fifo_cancel_wait((struct k_fifo *)p1);
}

static void tfifo_thread_thread(struct k_fifo *pfifo)
{
k_tid_t tid = k_thread_spawn(tstack, STACK_SIZE,
t_cancel_wait_entry, pfifo, NULL, NULL,
K_PRIO_PREEMPT(0), 0, 0);
u32_t start_t = k_uptime_get_32();
void *ret = k_fifo_get(pfifo, 500);
u32_t dur = k_uptime_get_32() - start_t;
/* While we observed the side effect of the last statement
* ( call to k_fifo_cancel_wait) of the thread, it's not fact
* that it returned, within the thread. Then it may happen
* that the test runner below will try to create another
* thread in the same stack space, then 1st thread returns
* from the call, leading to crash.
*/
k_thread_abort(tid);
zassert_is_null(ret,
"k_fifo_get didn't get 'timeout expired' status");
/* 61 includes fuzz factor */
zassert_true(dur < 61,
"k_fifo_get didn't get cancelled in expected timeframe");
}

/*test cases*/
void test_fifo_cancel_wait(void)
{
/**TESTPOINT: init via k_fifo_init*/
k_fifo_init(&fifo_c);
tfifo_thread_thread(&fifo_c);

/**TESTPOINT: test K_FIFO_DEFINEed fifo*/
tfifo_thread_thread(&kfifo_c);
}