watermark_queue.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Thread queue with water mark
  3. *
  4. * COPYRIGHT (C) 2014-2015, Shanghai Real-Thread Technology Co., Ltd
  5. * http://www.rt-thread.com
  6. *
  7. * This file is part of RT-Thread (http://www.rt-thread.org)
  8. *
  9. * All rights reserved.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  24. *
  25. * Change Logs:
  26. * Date Author Notes
  27. * 2014-04-16 Grissiom first version
  28. */
  29. struct rt_watermark_queue
  30. {
  31. /* Current water level. */
  32. unsigned int level;
  33. unsigned int high_mark;
  34. unsigned int low_mark;
  35. rt_list_t suspended_threads;
  36. };
  37. /** Init the struct rt_watermark_queue.
  38. */
  39. void rt_wm_que_init(struct rt_watermark_queue *wg,
  40. unsigned int low, unsigned int high);
  41. void rt_wm_que_set_mark(struct rt_watermark_queue *wg,
  42. unsigned int low, unsigned int high);
  43. void rt_wm_que_dump(struct rt_watermark_queue *wg);
  44. /* Water marks are often used in performance critical places. Benchmark shows
  45. * inlining functions will have 10% performance gain in some situation(for
  46. * example, VBus). So keep the inc/dec compact and inline. */
  47. /** Increase the water level.
  48. *
  49. * It should be called in the thread that want to raise the water level. If the
  50. * current level is above the high mark, the thread will be suspended up to
  51. * @timeout ticks.
  52. *
  53. * @return RT_EOK if water level increased successfully. -RT_EFULL on @timeout
  54. * is zero and the level is above water mark. -RT_ETIMEOUT if timeout occurred.
  55. */
  56. rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg,
  57. int timeout)
  58. {
  59. rt_base_t ilvl;
  60. /* Assert as early as possible. */
  61. if (timeout != 0)
  62. {
  63. RT_DEBUG_IN_THREAD_CONTEXT;
  64. }
  65. ilvl = rt_hw_interrupt_disable();
  66. while (wg->level > wg->high_mark)
  67. {
  68. rt_thread_t thread;
  69. if (timeout == 0)
  70. {
  71. rt_hw_interrupt_enable(ilvl);
  72. return -RT_EFULL;
  73. }
  74. thread = rt_thread_self();
  75. thread->error = RT_EOK;
  76. rt_thread_suspend(thread);
  77. rt_list_insert_after(&wg->suspended_threads, &thread->tlist);
  78. if (timeout > 0)
  79. {
  80. rt_timer_control(&(thread->thread_timer),
  81. RT_TIMER_CTRL_SET_TIME,
  82. &timeout);
  83. rt_timer_start(&(thread->thread_timer));
  84. }
  85. rt_hw_interrupt_enable(ilvl);
  86. rt_schedule();
  87. if (thread->error != RT_EOK)
  88. return thread->error;
  89. ilvl = rt_hw_interrupt_disable();
  90. }
  91. wg->level++;
  92. if (wg->level == 0)
  93. {
  94. wg->level = ~0;
  95. }
  96. rt_hw_interrupt_enable(ilvl);
  97. return RT_EOK;
  98. }
  99. /** Decrease the water level.
  100. *
  101. * It should be called by the consumer that drain the water out. If the water
  102. * level reached low mark, all the thread suspended in this queue will be waken
  103. * up. It's safe to call this function in interrupt context.
  104. */
  105. rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg)
  106. {
  107. int need_sched = 0;
  108. rt_base_t ilvl;
  109. if (wg->level == 0)
  110. return;
  111. ilvl = rt_hw_interrupt_disable();
  112. wg->level--;
  113. if (wg->level == wg->low_mark)
  114. {
  115. /* There should be spaces between the low mark and high mark, so it's
  116. * safe to resume all the threads. */
  117. while (!rt_list_isempty(&wg->suspended_threads))
  118. {
  119. rt_thread_t thread;
  120. thread = rt_list_entry(wg->suspended_threads.next,
  121. struct rt_thread,
  122. tlist);
  123. rt_thread_resume(thread);
  124. need_sched = 1;
  125. }
  126. }
  127. rt_hw_interrupt_enable(ilvl);
  128. if (need_sched)
  129. rt_schedule();
  130. }