stack.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (c) 2010-2016 Wind River Systems, Inc.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @brief fixed-size stack object
  8. */
  9. #include <kernel.h>
  10. #include <kernel_structs.h>
  11. #include <toolchain.h>
  12. #include <ksched.h>
  13. #include <wait_q.h>
  14. #include <sys/check.h>
  15. #include <init.h>
  16. #include <syscall_handler.h>
  17. #include <kernel_internal.h>
  18. void k_stack_init(struct k_stack *stack, stack_data_t *buffer,
  19. uint32_t num_entries)
  20. {
  21. z_waitq_init(&stack->wait_q);
  22. stack->lock = (struct k_spinlock) {};
  23. stack->next = stack->base = buffer;
  24. stack->top = stack->base + num_entries;
  25. SYS_PORT_TRACING_OBJ_INIT(k_stack, stack);
  26. z_object_init(stack);
  27. }
  28. int32_t z_impl_k_stack_alloc_init(struct k_stack *stack, uint32_t num_entries)
  29. {
  30. void *buffer;
  31. int32_t ret;
  32. SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_stack, alloc_init, stack);
  33. buffer = z_thread_malloc(num_entries * sizeof(stack_data_t));
  34. if (buffer != NULL) {
  35. k_stack_init(stack, buffer, num_entries);
  36. stack->flags = K_STACK_FLAG_ALLOC;
  37. ret = (int32_t)0;
  38. } else {
  39. ret = -ENOMEM;
  40. }
  41. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, alloc_init, stack, ret);
  42. return ret;
  43. }
  44. #ifdef CONFIG_USERSPACE
  45. static inline int32_t z_vrfy_k_stack_alloc_init(struct k_stack *stack,
  46. uint32_t num_entries)
  47. {
  48. Z_OOPS(Z_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_STACK));
  49. Z_OOPS(Z_SYSCALL_VERIFY(num_entries > 0));
  50. return z_impl_k_stack_alloc_init(stack, num_entries);
  51. }
  52. #include <syscalls/k_stack_alloc_init_mrsh.c>
  53. #endif
  54. int k_stack_cleanup(struct k_stack *stack)
  55. {
  56. SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_stack, cleanup, stack);
  57. CHECKIF(z_waitq_head(&stack->wait_q) != NULL) {
  58. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, cleanup, stack, -EAGAIN);
  59. return -EAGAIN;
  60. }
  61. if ((stack->flags & K_STACK_FLAG_ALLOC) != (uint8_t)0) {
  62. k_free(stack->base);
  63. stack->base = NULL;
  64. stack->flags &= ~K_STACK_FLAG_ALLOC;
  65. }
  66. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, cleanup, stack, 0);
  67. return 0;
  68. }
  69. int z_impl_k_stack_push(struct k_stack *stack, stack_data_t data)
  70. {
  71. struct k_thread *first_pending_thread;
  72. int ret = 0;
  73. k_spinlock_key_t key = k_spin_lock(&stack->lock);
  74. SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_stack, push, stack);
  75. CHECKIF(stack->next == stack->top) {
  76. ret = -ENOMEM;
  77. goto out;
  78. }
  79. first_pending_thread = z_unpend_first_thread(&stack->wait_q);
  80. if (first_pending_thread != NULL) {
  81. z_thread_return_value_set_with_data(first_pending_thread,
  82. 0, (void *)data);
  83. z_ready_thread(first_pending_thread);
  84. z_reschedule(&stack->lock, key);
  85. goto end;
  86. } else {
  87. *(stack->next) = data;
  88. stack->next++;
  89. goto out;
  90. }
  91. out:
  92. k_spin_unlock(&stack->lock, key);
  93. end:
  94. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, push, stack, ret);
  95. return ret;
  96. }
  97. #ifdef CONFIG_USERSPACE
  98. static inline int z_vrfy_k_stack_push(struct k_stack *stack, stack_data_t data)
  99. {
  100. Z_OOPS(Z_SYSCALL_OBJ(stack, K_OBJ_STACK));
  101. return z_impl_k_stack_push(stack, data);
  102. }
  103. #include <syscalls/k_stack_push_mrsh.c>
  104. #endif
  105. int z_impl_k_stack_pop(struct k_stack *stack, stack_data_t *data,
  106. k_timeout_t timeout)
  107. {
  108. k_spinlock_key_t key;
  109. int result;
  110. key = k_spin_lock(&stack->lock);
  111. SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_stack, pop, stack, timeout);
  112. if (likely(stack->next > stack->base)) {
  113. stack->next--;
  114. *data = *(stack->next);
  115. k_spin_unlock(&stack->lock, key);
  116. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, pop, stack, timeout, 0);
  117. return 0;
  118. }
  119. SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_stack, pop, stack, timeout);
  120. if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
  121. k_spin_unlock(&stack->lock, key);
  122. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, pop, stack, timeout, -EBUSY);
  123. return -EBUSY;
  124. }
  125. result = z_pend_curr(&stack->lock, key, &stack->wait_q, timeout);
  126. if (result == -EAGAIN) {
  127. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, pop, stack, timeout, -EAGAIN);
  128. return -EAGAIN;
  129. }
  130. *data = (stack_data_t)_current->base.swap_data;
  131. SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_stack, pop, stack, timeout, 0);
  132. return 0;
  133. }
  134. #ifdef CONFIG_USERSPACE
  135. static inline int z_vrfy_k_stack_pop(struct k_stack *stack,
  136. stack_data_t *data, k_timeout_t timeout)
  137. {
  138. Z_OOPS(Z_SYSCALL_OBJ(stack, K_OBJ_STACK));
  139. Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, sizeof(stack_data_t)));
  140. return z_impl_k_stack_pop(stack, data, timeout);
  141. }
  142. #include <syscalls/k_stack_pop_mrsh.c>
  143. #endif