completion.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2012-09-30 Bernard first version.
  9. * 2021-08-18 chenyingchun add comments
  10. */
  11. #include <rthw.h>
  12. #include <rtdevice.h>
  13. #define RT_COMPLETED 1
  14. #define RT_UNCOMPLETED 0
  15. /**
  16. * @brief This function will initialize a completion object.
  17. *
  18. * @param completion is a pointer to a completion object.
  19. */
  20. void rt_completion_init(struct rt_completion *completion)
  21. {
  22. rt_base_t level;
  23. RT_ASSERT(completion != RT_NULL);
  24. level = rt_hw_interrupt_disable();
  25. completion->flag = RT_UNCOMPLETED;
  26. rt_list_init(&completion->suspended_list);
  27. rt_hw_interrupt_enable(level);
  28. }
  29. RTM_EXPORT(rt_completion_init);
  30. /**
  31. * @brief This function will wait for a completion, if the completion is unavailable, the thread shall wait for
  32. * the completion up to a specified time.
  33. *
  34. * @param completion is a pointer to a completion object.
  35. *
  36. * @param timeout is a timeout period (unit: OS ticks). If the completion is unavailable, the thread will wait for
  37. * the completion done up to the amount of time specified by the argument.
  38. * NOTE: Generally, we use the macro RT_WAITING_FOREVER to set this parameter, which means that when the
  39. * completion is unavailable, the thread will be waitting forever.
  40. *
  41. * @return Return the operation status. ONLY when the return value is RT_EOK, the operation is successful.
  42. * If the return value is any other values, it means that the completion wait failed.
  43. *
  44. * @warning This function can ONLY be called in the thread context. It MUST NOT be called in interrupt context.
  45. */
  46. rt_err_t rt_completion_wait(struct rt_completion *completion,
  47. rt_int32_t timeout)
  48. {
  49. rt_err_t result;
  50. rt_base_t level;
  51. rt_thread_t thread;
  52. RT_ASSERT(completion != RT_NULL);
  53. /* current context checking */
  54. RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
  55. result = RT_EOK;
  56. thread = rt_thread_self();
  57. level = rt_hw_interrupt_disable();
  58. if (completion->flag != RT_COMPLETED)
  59. {
  60. /* only one thread can suspend on complete */
  61. RT_ASSERT(rt_list_isempty(&(completion->suspended_list)));
  62. if (timeout == 0)
  63. {
  64. result = -RT_ETIMEOUT;
  65. goto __exit;
  66. }
  67. else
  68. {
  69. /* reset thread error number */
  70. thread->error = RT_EOK;
  71. /* suspend thread */
  72. rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
  73. /* add to suspended list */
  74. rt_list_insert_before(&(completion->suspended_list),
  75. &(thread->tlist));
  76. /* current context checking */
  77. RT_DEBUG_NOT_IN_INTERRUPT;
  78. /* start timer */
  79. if (timeout > 0)
  80. {
  81. /* reset the timeout of thread timer and start it */
  82. rt_timer_control(&(thread->thread_timer),
  83. RT_TIMER_CTRL_SET_TIME,
  84. &timeout);
  85. rt_timer_start(&(thread->thread_timer));
  86. }
  87. /* enable interrupt */
  88. rt_hw_interrupt_enable(level);
  89. /* do schedule */
  90. rt_schedule();
  91. /* thread is waked up */
  92. result = thread->error;
  93. level = rt_hw_interrupt_disable();
  94. }
  95. }
  96. /* clean completed flag */
  97. completion->flag = RT_UNCOMPLETED;
  98. __exit:
  99. rt_hw_interrupt_enable(level);
  100. return result;
  101. }
  102. RTM_EXPORT(rt_completion_wait);
  103. /**
  104. * @brief This function indicates a completion has done.
  105. *
  106. * @param completion is a pointer to a completion object.
  107. */
  108. void rt_completion_done(struct rt_completion *completion)
  109. {
  110. rt_base_t level;
  111. RT_ASSERT(completion != RT_NULL);
  112. if (completion->flag == RT_COMPLETED)
  113. return;
  114. level = rt_hw_interrupt_disable();
  115. completion->flag = RT_COMPLETED;
  116. if (!rt_list_isempty(&(completion->suspended_list)))
  117. {
  118. /* there is one thread in suspended list */
  119. struct rt_thread *thread;
  120. /* get thread entry */
  121. thread = rt_list_entry(completion->suspended_list.next,
  122. struct rt_thread,
  123. tlist);
  124. /* resume it */
  125. rt_thread_resume(thread);
  126. rt_hw_interrupt_enable(level);
  127. /* perform a schedule */
  128. rt_schedule();
  129. }
  130. else
  131. {
  132. rt_hw_interrupt_enable(level);
  133. }
  134. }
  135. RTM_EXPORT(rt_completion_done);