123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- /*
- * Copyright (c) 2010-2016 Wind River Systems, Inc.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- *
- * @brief dynamic-size QUEUE object.
- */
- #include <kernel.h>
- #include <kernel_structs.h>
- #include <toolchain.h>
- #include <wait_q.h>
- #include <ksched.h>
- #include <init.h>
- #include <syscall_handler.h>
- #include <kernel_internal.h>
- #include <sys/check.h>
- struct alloc_node {
- sys_sfnode_t node;
- void *data;
- };
- void *z_queue_node_peek(sys_sfnode_t *node, bool needs_free)
- {
- void *ret;
- if ((node != NULL) && (sys_sfnode_flags_get(node) != (uint8_t)0)) {
- /* If the flag is set, then the enqueue operation for this item
- * did a behind-the scenes memory allocation of an alloc_node
- * struct, which is what got put in the queue. Free it and pass
- * back the data pointer.
- */
- struct alloc_node *anode;
- anode = CONTAINER_OF(node, struct alloc_node, node);
- ret = anode->data;
- if (needs_free) {
- k_free(anode);
- }
- } else {
- /* Data was directly placed in the queue, the first word
- * reserved for the linked list. User mode isn't allowed to
- * do this, although it can get data sent this way.
- */
- ret = (void *)node;
- }
- return ret;
- }
- void z_impl_k_queue_init(struct k_queue *queue)
- {
- sys_sflist_init(&queue->data_q);
- queue->lock = (struct k_spinlock) {};
- z_waitq_init(&queue->wait_q);
- #if defined(CONFIG_POLL)
- sys_dlist_init(&queue->poll_events);
- #endif
- SYS_PORT_TRACING_OBJ_INIT(k_queue, queue);
- z_object_init(queue);
- }
- #ifdef CONFIG_USERSPACE
- static inline void z_vrfy_k_queue_init(struct k_queue *queue)
- {
- Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(queue, K_OBJ_QUEUE));
- z_impl_k_queue_init(queue);
- }
- #include <syscalls/k_queue_init_mrsh.c>
- #endif
- static void prepare_thread_to_run(struct k_thread *thread, void *data)
- {
- z_thread_return_value_set_with_data(thread, 0, data);
- z_ready_thread(thread);
- }
- static inline void handle_poll_events(struct k_queue *queue, uint32_t state)
- {
- #ifdef CONFIG_POLL
- z_handle_obj_poll_events(&queue->poll_events, state);
- #endif
- }
- void z_impl_k_queue_cancel_wait(struct k_queue *queue)
- {
- SYS_PORT_TRACING_OBJ_FUNC(k_queue, cancel_wait, queue);
- k_spinlock_key_t key = k_spin_lock(&queue->lock);
- struct k_thread *first_pending_thread;
- first_pending_thread = z_unpend_first_thread(&queue->wait_q);
- if (first_pending_thread != NULL) {
- prepare_thread_to_run(first_pending_thread, NULL);
- }
- handle_poll_events(queue, K_POLL_STATE_CANCELLED);
- z_reschedule(&queue->lock, key);
- }
- #ifdef CONFIG_USERSPACE
- static inline void z_vrfy_k_queue_cancel_wait(struct k_queue *queue)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- z_impl_k_queue_cancel_wait(queue);
- }
- #include <syscalls/k_queue_cancel_wait_mrsh.c>
- #endif
- static int32_t queue_insert(struct k_queue *queue, void *prev, void *data,
- bool alloc, bool is_append)
- {
- struct k_thread *first_pending_thread;
- k_spinlock_key_t key = k_spin_lock(&queue->lock);
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, queue_insert, queue, alloc);
- if (is_append) {
- prev = sys_sflist_peek_tail(&queue->data_q);
- }
- first_pending_thread = z_unpend_first_thread(&queue->wait_q);
- if (first_pending_thread != NULL) {
- SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_queue, queue_insert, queue, alloc, K_FOREVER);
- prepare_thread_to_run(first_pending_thread, data);
- z_reschedule(&queue->lock, key);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, queue_insert, queue, alloc, 0);
- return 0;
- }
- /* Only need to actually allocate if no threads are pending */
- if (alloc) {
- struct alloc_node *anode;
- anode = z_thread_malloc(sizeof(*anode));
- if (anode == NULL) {
- k_spin_unlock(&queue->lock, key);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, queue_insert, queue, alloc,
- -ENOMEM);
- return -ENOMEM;
- }
- anode->data = data;
- sys_sfnode_init(&anode->node, 0x1);
- data = anode;
- } else {
- sys_sfnode_init(data, 0x0);
- }
- SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_queue, queue_insert, queue, alloc, K_FOREVER);
- sys_sflist_insert(&queue->data_q, prev, data);
- handle_poll_events(queue, K_POLL_STATE_DATA_AVAILABLE);
- z_reschedule(&queue->lock, key);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, queue_insert, queue, alloc, 0);
- return 0;
- }
- void k_queue_insert(struct k_queue *queue, void *prev, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, insert, queue);
- (void)queue_insert(queue, prev, data, false, false);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, insert, queue);
- }
- void k_queue_append(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, append, queue);
- (void)queue_insert(queue, NULL, data, false, true);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append, queue);
- }
- void k_queue_prepend(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, prepend, queue);
- (void)queue_insert(queue, NULL, data, false, false);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, prepend, queue);
- }
- int32_t z_impl_k_queue_alloc_append(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, alloc_append, queue);
- int32_t ret = queue_insert(queue, NULL, data, true, true);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, alloc_append, queue, ret);
- return ret;
- }
- #ifdef CONFIG_USERSPACE
- static inline int32_t z_vrfy_k_queue_alloc_append(struct k_queue *queue,
- void *data)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_alloc_append(queue, data);
- }
- #include <syscalls/k_queue_alloc_append_mrsh.c>
- #endif
- int32_t z_impl_k_queue_alloc_prepend(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, alloc_prepend, queue);
- int32_t ret = queue_insert(queue, NULL, data, true, false);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, alloc_prepend, queue, ret);
- return ret;
- }
- #ifdef CONFIG_USERSPACE
- static inline int32_t z_vrfy_k_queue_alloc_prepend(struct k_queue *queue,
- void *data)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_alloc_prepend(queue, data);
- }
- #include <syscalls/k_queue_alloc_prepend_mrsh.c>
- #endif
- int k_queue_append_list(struct k_queue *queue, void *head, void *tail)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, append_list, queue);
- /* invalid head or tail of list */
- CHECKIF(head == NULL || tail == NULL) {
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append_list, queue, -EINVAL);
- return -EINVAL;
- }
- k_spinlock_key_t key = k_spin_lock(&queue->lock);
- struct k_thread *thread = NULL;
- if (head != NULL) {
- thread = z_unpend_first_thread(&queue->wait_q);
- }
- while ((head != NULL) && (thread != NULL)) {
- prepare_thread_to_run(thread, head);
- head = *(void **)head;
- thread = z_unpend_first_thread(&queue->wait_q);
- }
- if (head != NULL) {
- sys_sflist_append_list(&queue->data_q, head, tail);
- }
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, append_list, queue, 0);
- handle_poll_events(queue, K_POLL_STATE_DATA_AVAILABLE);
- z_reschedule(&queue->lock, key);
- return 0;
- }
- int k_queue_merge_slist(struct k_queue *queue, sys_slist_t *list)
- {
- int ret;
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, merge_slist, queue);
- /* list must not be empty */
- CHECKIF(sys_slist_is_empty(list)) {
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, -EINVAL);
- return -EINVAL;
- }
- /*
- * note: this works as long as:
- * - the slist implementation keeps the next pointer as the first
- * field of the node object type
- * - list->tail->next = NULL.
- * - sflist implementation only differs from slist by stuffing
- * flag bytes in the lower order bits of the data pointer
- * - source list is really an slist and not an sflist with flags set
- */
- ret = k_queue_append_list(queue, list->head, list->tail);
- CHECKIF(ret != 0) {
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, ret);
- return ret;
- }
- sys_slist_init(list);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, merge_slist, queue, 0);
- return 0;
- }
- void *z_impl_k_queue_get(struct k_queue *queue, k_timeout_t timeout)
- {
- k_spinlock_key_t key = k_spin_lock(&queue->lock);
- void *data;
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, get, queue, timeout);
- if (likely(!sys_sflist_is_empty(&queue->data_q))) {
- sys_sfnode_t *node;
- node = sys_sflist_get_not_empty(&queue->data_q);
- data = z_queue_node_peek(node, true);
- k_spin_unlock(&queue->lock, key);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout, data);
- return data;
- }
- SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_queue, get, queue, timeout);
- if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
- k_spin_unlock(&queue->lock, key);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout, NULL);
- return NULL;
- }
- int ret = z_pend_curr(&queue->lock, key, &queue->wait_q, timeout);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, get, queue, timeout,
- (ret != 0) ? NULL : _current->base.swap_data);
- return (ret != 0) ? NULL : _current->base.swap_data;
- }
- bool k_queue_remove(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, remove, queue);
- bool ret = sys_sflist_find_and_remove(&queue->data_q, (sys_sfnode_t *)data);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, remove, queue, ret);
- return ret;
- }
- bool k_queue_unique_append(struct k_queue *queue, void *data)
- {
- SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_queue, unique_append, queue);
- sys_sfnode_t *test;
- SYS_SFLIST_FOR_EACH_NODE(&queue->data_q, test) {
- if (test == (sys_sfnode_t *) data) {
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, unique_append, queue, false);
- return false;
- }
- }
- k_queue_append(queue, data);
- SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_queue, unique_append, queue, true);
- return true;
- }
- void *z_impl_k_queue_peek_head(struct k_queue *queue)
- {
- void *ret = z_queue_node_peek(sys_sflist_peek_head(&queue->data_q), false);
- SYS_PORT_TRACING_OBJ_FUNC(k_queue, peek_head, queue, ret);
- return ret;
- }
- void *z_impl_k_queue_peek_tail(struct k_queue *queue)
- {
- void *ret = z_queue_node_peek(sys_sflist_peek_tail(&queue->data_q), false);
- SYS_PORT_TRACING_OBJ_FUNC(k_queue, peek_tail, queue, ret);
- return ret;
- }
- #ifdef CONFIG_USERSPACE
- static inline void *z_vrfy_k_queue_get(struct k_queue *queue,
- k_timeout_t timeout)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_get(queue, timeout);
- }
- #include <syscalls/k_queue_get_mrsh.c>
- static inline int z_vrfy_k_queue_is_empty(struct k_queue *queue)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_is_empty(queue);
- }
- #include <syscalls/k_queue_is_empty_mrsh.c>
- static inline void *z_vrfy_k_queue_peek_head(struct k_queue *queue)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_peek_head(queue);
- }
- #include <syscalls/k_queue_peek_head_mrsh.c>
- static inline void *z_vrfy_k_queue_peek_tail(struct k_queue *queue)
- {
- Z_OOPS(Z_SYSCALL_OBJ(queue, K_OBJ_QUEUE));
- return z_impl_k_queue_peek_tail(queue);
- }
- #include <syscalls/k_queue_peek_tail_mrsh.c>
- #endif /* CONFIG_USERSPACE */
|