text: /*
   * Copyright (c) 2017 Intel Corporation
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #include "test_queue.h"
  
  #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
  #define LIST_LEN 2
  /**TESTPOINT: init via K_QUEUE_DEFINE*/
  K_QUEUE_DEFINE(kqueue);
  
  K_HEAP_DEFINE(mem_pool_fail, 8 + 128);
  K_HEAP_DEFINE(mem_pool_pass, 64 * 4 + 128);
  
  struct k_queue queue;
  static qdata_t data[LIST_LEN];
  static qdata_t data_p[LIST_LEN];
  static qdata_t data_l[LIST_LEN];
  static qdata_t data_sl[LIST_LEN];
  
  static qdata_t *data_append;
  static qdata_t *data_prepend;
  
  static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
  static struct k_thread tdata;
  static K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
  static struct k_thread tdata1;
  static struct k_sem end_sema;
  
  static void tqueue_append(struct k_queue *pqueue)
  {
  	k_queue_insert(pqueue, k_queue_peek_tail(pqueue),
  		       (void *)&data[0]);
  
  	for (int i = 1; i < LIST_LEN; i++) {
  		/**TESTPOINT: queue append */
  		k_queue_append(pqueue, (void *)&data[i]);
  	}
  
  	for (int i = LIST_LEN - 1; i >= 0; i--) {
  		/**TESTPOINT: queue prepend */
  		k_queue_prepend(pqueue, (void *)&data_p[i]);
  	}
  
  	/**TESTPOINT: queue append list*/
  	static qdata_t *head = &data_l[0], *tail = &data_l[LIST_LEN - 1];
  
  	head->snode.next = (sys_snode_t *)tail;
  	tail->snode.next = NULL;
  	k_queue_append_list(pqueue, (uint32_t *)head, (uint32_t *)tail);
  
  	/**TESTPOINT: queue merge slist*/
  	sys_slist_t slist;
  
  	sys_slist_init(&slist);
  	sys_slist_append(&slist, (sys_snode_t *)&(data_sl[0].snode));
  	sys_slist_append(&slist, (sys_snode_t *)&(data_sl[1].snode));
  	k_queue_merge_slist(pqueue, &slist);
  }
  
  static void tqueue_get(struct k_queue *pqueue)
  {
  	void *rx_data;
  
  	/*get queue data from "queue_prepend"*/
  	for (int i = 0; i < LIST_LEN; i++) {
  		/**TESTPOINT: queue get*/
  		rx_data = k_queue_get(pqueue, K_NO_WAIT);
  		zassert_equal(rx_data, (void *)&data_p[i], NULL);
  	}
  	/*get queue data from "queue_append"*/
  	for (int i = 0; i < LIST_LEN; i++) {
  		/**TESTPOINT: queue get*/
  		rx_data = k_queue_get(pqueue, K_NO_WAIT);
  		zassert_equal(rx_data, (void *)&data[i], NULL);
  	}
  	/*get queue data from "queue_append_list"*/
  	for (int i = 0; i < LIST_LEN; i++) {
  		rx_data = k_queue_get(pqueue, K_NO_WAIT);
  		zassert_equal(rx_data, (void *)&data_l[i], NULL);
  	}
  	/*get queue data from "queue_merge_slist"*/
  	for (int i = 0; i < LIST_LEN; i++) {
  		rx_data = k_queue_get(pqueue, K_NO_WAIT);
  		zassert_equal(rx_data, (void *)&data_sl[i], NULL);
  	}
  }
  
  /*entry of contexts*/
  static void tIsr_entry_append(const void *p)
  {
  	tqueue_append((struct k_queue *)p);
  }
  
  static void tIsr_entry_get(const void *p)
  {
  	tqueue_get((struct k_queue *)p);
  }
  
  static void tThread_entry(void *p1, void *p2, void *p3)
  {
  	tqueue_get((struct k_queue *)p1);
  	k_sem_give(&end_sema);
  }
  
  static void tqueue_thread_thread(struct k_queue *pqueue)
  {
  	k_sem_init(&end_sema, 0, 1);
  	/**TESTPOINT: thread-thread data passing via queue*/
  	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
  				      tThread_entry, pqueue, NULL, NULL,
  				      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
  	tqueue_append(pqueue);
  	k_sem_take(&end_sema, K_FOREVER);
  	k_thread_abort(tid);
  }
  
  static void tqueue_thread_isr(struct k_queue *pqueue)
  {
  	k_sem_init(&end_sema, 0, 1);
  	/**TESTPOINT: thread-isr data passing via queue*/
  	irq_offload(tIsr_entry_append, (const void *)pqueue);
  	tqueue_get(pqueue);
  }
  
  static void tqueue_isr_thread(struct k_queue *pqueue)
  {
  	k_sem_init(&end_sema, 0, 1);
  	/**TESTPOINT: isr-thread data passing via queue*/
  	tqueue_append(pqueue);
  	irq_offload(tIsr_entry_get, (const void *)pqueue);
  }
  
  /*test cases*/
  /**
   * @brief Verify data passing between threads using queue
   *
   * @details Static define and Dynamic define queues,
   * Then initialize them.
   * Create a new thread to wait for reading data.
   * Current thread will append item into queue.
   * Verify if rx_data is equal insert-data address.
   * Verify queue can be define at compile time.
   *
   * @ingroup kernel_queue_tests
   *
   * @see k_queue_init(), k_queue_insert(), k_queue_append()
   * K_THREAD_STACK_DEFINE()
   */
  void test_queue_thread2thread(void)
  {
  	/**TESTPOINT: init via k_queue_init*/
  	k_queue_init(&queue);
  	tqueue_thread_thread(&queue);
  
  	/**TESTPOINT: test K_QUEUE_DEFINEed queue*/
  	tqueue_thread_thread(&kqueue);
  }
  
  /**
   * @brief Verify data passing between thread and ISR
   *
   * @details Create a new ISR to insert data
   * And current thread is used for getting data
   * Verify if the rx_data is equal insert-data address.
   * If the received data address is the same as
   * the created array, prove that the queue data structures
   * are stored within the provided data items.
   *
   * @ingroup kernel_queue_tests
   *
   * @see k_queue_init(), k_queue_insert(), k_queue_append()
   */
  void test_queue_thread2isr(void)
  {
  	/**TESTPOINT: init via k_queue_init*/
  	k_queue_init(&queue);
  	tqueue_thread_isr(&queue);
  
  	/**TESTPOINT: test K_QUEUE_DEFINEed queue*/
  	tqueue_thread_isr(&kqueue);
  }
  
  /**
   * @brief Verify data passing between ISR and thread
   *
   * @details Create a new ISR and ready for getting data
   * And current thread is used for inserting data
   * Verify if the rx_data is equal insert-data address.
   *
   * @ingroup kernel_queue_tests
   *
   * @see k_queue_init(), k_queue_insert(), k_queue_get(),
   * k_queue_append(), k_queue_remove()
   */
  void test_queue_isr2thread(void)
  {
  	/**TESTPOINT: test k_queue_init queue*/
  	k_queue_init(&queue);
  	tqueue_isr_thread(&queue);
  
  	/**TESTPOINT: test K_QUEUE_DEFINE queue*/
  	tqueue_isr_thread(&kqueue);
  }
  
  static void tThread_get(void *p1, void *p2, void *p3)
  {
  	zassert_true(k_queue_get((struct k_queue *)p1, K_FOREVER) != NULL,
  		     NULL);
  	k_sem_give(&end_sema);
  }
  
  static void tqueue_get_2threads(struct k_queue *pqueue)
  {
  	k_sem_init(&end_sema, 0, 1);
  	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
  				      tThread_get, pqueue, NULL, NULL,
  				      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
  
  	k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
  				       tThread_get, pqueue, NULL, NULL,
  				       K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
  
  	/* Wait threads to initialize */
  	k_sleep(K_MSEC(10));
  
  	k_queue_append(pqueue, (void *)&data[0]);
  	k_queue_append(pqueue, (void *)&data[1]);
  	/* Wait threads to finalize */
  	k_sem_take(&end_sema, K_FOREVER);
  	k_sem_take(&end_sema, K_FOREVER);
  
  	k_thread_abort(tid);
  	k_thread_abort(tid1);
  }
  
  /**
   * @brief Verify k_queue_get()
   * @ingroup kernel_queue_tests
   * @see k_queue_init(), k_queue_get(),
   * k_queue_append(), k_queue_alloc_prepend()
   */
  void test_queue_get_2threads(void)
  {
  	/**TESTPOINT: test k_queue_init queue*/
  	k_queue_init(&queue);
  
  	tqueue_get_2threads(&queue);
  }
  
  static void tqueue_alloc(struct k_queue *pqueue)
  {
  	k_thread_heap_assign(k_current_get(), NULL);
  
  	/* Alloc append without resource pool */
  	k_queue_alloc_append(pqueue, (void *)&data_append);
  
  	/* Insertion fails and alloc returns NOMEM */
  	zassert_false(k_queue_remove(pqueue, &data_append), NULL);
  
  	/* Assign resource pool of lower size */
  	k_thread_heap_assign(k_current_get(), &mem_pool_fail);
  
  	/* Prepend to the queue, but fails because of
  	 * insufficient memory
  	 */
  	k_queue_alloc_prepend(pqueue, (void *)&data_prepend);
  
  	zassert_false(k_queue_remove(pqueue, &data_prepend), NULL);
  
  	/* No element must be present in the queue, as all
  	 * operations failed
  	 */
  	zassert_true(k_queue_is_empty(pqueue), NULL);
  
  	/* Assign resource pool of sufficient size */
  	k_thread_heap_assign(k_current_get(), &mem_pool_pass);
  
  	zassert_false(k_queue_alloc_prepend(pqueue, (void *)&data_prepend),
  		      NULL);
  
  	/* Now queue shouldn't be empty */
  	zassert_false(k_queue_is_empty(pqueue), NULL);
  
  	zassert_true(k_queue_get(pqueue, K_FOREVER) != NULL,
  		     NULL);
  }
  
  /**
   * @brief Test queue alloc append and prepend
   * @ingroup kernel_queue_tests
   * @see k_queue_alloc_append(), k_queue_alloc_prepend(),
   * z_thread_resource_pool_assign(), k_queue_is_empty(),
   * k_queue_get(), k_queue_remove()
   */
  void test_queue_alloc(void)
  {
  	/* The mem_pool_fail pool is supposed to be too small to
  	 * succeed any allocations, but in fact with the heap backend
  	 * there's some base minimal memory in there that can be used.
  	 * Make sure it's really truly full.
  	 */
  	while (k_heap_alloc(&mem_pool_fail, 1, K_NO_WAIT) != NULL) {
  	}
  
  	k_queue_init(&queue);
  
  	tqueue_alloc(&queue);
  }
  
  
  /* Does nothing but read items out of the queue and verify that they
   * are non-null.  Two such threads will be created.
   */
  static void queue_poll_race_consume(void *p1, void *p2, void *p3)
  {
  	struct k_queue *q = p1;
  	int *count = p2;
  
  	while (true) {
  		zassert_true(k_queue_get(q, K_FOREVER) != NULL, NULL);
  		*count += 1;
  	}
  }
  
  /* There was a historical race in the queue internals when CONFIG_POLL
   * was enabled -- it was possible to wake up a lower priority thread
   * with an insert but then steal it with a higher priority thread
   * before it got a chance to run, and the lower priority thread would
   * then return NULL before its timeout expired.
   */
  void test_queue_poll_race(void)
  {
  	int prio = k_thread_priority_get(k_current_get());
  	int mid_count = 0, low_count = 0;
  
  	k_queue_init(&queue);
  
  	k_thread_create(&tdata, tstack, STACK_SIZE,
  			queue_poll_race_consume,
  			&queue, &mid_count, NULL,
  			prio + 1, 0, K_NO_WAIT);
  
  	k_thread_create(&tdata1, tstack1, STACK_SIZE,
  			queue_poll_race_consume,
  			&queue, &low_count, NULL,
  			prio + 2, 0, K_NO_WAIT);
  
  	/* Let them initialize and block */
  	k_sleep(K_TICKS(2));
  
  	/* Insert two items.  This will wake up both threads, but the
  	 * higher priority thread (tdata1) might (if CONFIG_POLL)
  	 * consume both.  The lower priority thread should stay
  	 * asleep.
  	 */
  	k_queue_append(&queue, &data[0]);
  	k_queue_append(&queue, &data[1]);
  
  	zassert_true(low_count == 0, NULL);
  	zassert_true(mid_count == 0, NULL);
  
  	k_sleep(K_TICKS(2));
  
  	zassert_true(low_count + mid_count == 2, NULL);
  
  	k_thread_abort(&tdata);
  	k_thread_abort(&tdata1);
  }
  
  /**
   * @brief Verify that multiple queues can be defined
   * simultaneously
   *
   * @details define multiple queues to verify
   * they can work.
   *
   * @ingroup kernel_queue_tests
   *
   * @see k_queue_init()
   */
  #define QUEUE_NUM 10
  void test_multiple_queues(void)
  {
  	/*define multiple queues*/
  	static struct k_queue queues[QUEUE_NUM];
  
  	for (int i = 0; i < QUEUE_NUM; i++) {
  		k_queue_init(&queues[i]);
  
  		/*Indicating that they are working*/
  		tqueue_append(&queues[i]);
  		tqueue_get(&queues[i]);
  	}
  }
  
  void user_access_queue_private_data(void *p1, void *p2, void *p3)
  {
  	ztest_set_fault_valid(true);
  	/* try to access to private kernel data, will happen kernel oops */
  	k_queue_is_empty(&queue);
  }
  
  /**
   * @brief Test access kernel object with private data using system call
   *
   * @details
   * - When defining system calls, it is very important to ensure that
   *   access to the API’s private data is done exclusively through system call
   *   interfaces. Private kernel data should never be made available to user mode
   *   threads directly. For example, the k_queue APIs were intentionally not made
   *   available as they store bookkeeping information about the queue directly
   *   in the queue buffers which are visible from user mode.
   * - Current test makes user thread try to access private kernel data within
   *   their associated data structures. Kernel will track that system call
   *   access to these object with the kernel object permission system.
   *   Current user thread doesn't have permission on it, trying to access
   *   &pqueue kernel object will happen kernel oops, because current user
   *   thread doesn't have permission on k_queue object with private kernel data.
   *
   * @ingroup kernel_memprotect_tests
   */
  void test_access_kernel_obj_with_priv_data(void)
  {
  	k_queue_init(&queue);
  	k_queue_insert(&queue, k_queue_peek_tail(&queue), (void *)&data[0]);
  	k_thread_create(&tdata, tstack, STACK_SIZE, user_access_queue_private_data,
  					NULL, NULL, NULL, 0, K_USER, K_NO_WAIT);
  	k_thread_join(&tdata, K_FOREVER);
  }
  