condvar.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-04-27 flybreak the first version.
  9. */
  10. #include <arm-tpl.h>
  11. #include "tpl.h"
  12. #include <new>
  13. #include <cstdint>
  14. #include <stdatomic.h>
  15. arm_tpl_cv::arm_tpl_cv()
  16. {
  17. s = rt_sem_create("semxs", 0, RT_IPC_FLAG_PRIO);
  18. if (s == nullptr)
  19. RT_ASSERT(0);
  20. h = rt_sem_create("semxh", 0, RT_IPC_FLAG_PRIO);
  21. if (h == nullptr)
  22. {
  23. rt_sem_delete(s);
  24. RT_ASSERT(0);
  25. }
  26. x = rt_mutex_create("mutx", RT_IPC_FLAG_PRIO);
  27. if (x == nullptr)
  28. {
  29. rt_sem_delete(s);
  30. rt_sem_delete(h);
  31. RT_ASSERT(0);
  32. }
  33. }
  34. arm_tpl_cv::~arm_tpl_cv()
  35. {
  36. rt_mutex_delete(x);
  37. rt_sem_delete(h);
  38. rt_sem_delete(s);
  39. }
  40. void arm_tpl_cv::wait(rt_mutex_t lock, bool recursive)
  41. {
  42. while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
  43. rt_sem_release(s);
  44. rt_mutex_release(x);
  45. if (recursive)
  46. rt_mutex_release(lock);
  47. else
  48. rt_mutex_release(lock);
  49. while (rt_sem_take(h, ARM_TPL_MAX_DELAY) != 0);
  50. if (recursive)
  51. while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
  52. else
  53. while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
  54. }
  55. int arm_tpl_cv::timedwait(rt_mutex_t lock, bool recursive, unsigned int timeout_ms)
  56. {
  57. int result = 0;
  58. while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
  59. rt_sem_release(s);
  60. rt_mutex_release(x);
  61. if (recursive)
  62. rt_mutex_release(lock);
  63. else
  64. rt_mutex_release(lock);
  65. if (rt_sem_take(h, rt_tick_from_millisecond(timeout_ms)) != 0)
  66. {
  67. while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
  68. if (rt_sem_take(h, 0) != 0)
  69. {
  70. if (rt_sem_take(s, 0) != 0)
  71. result = -1;
  72. else
  73. result = 1;
  74. }
  75. rt_mutex_release(x);
  76. }
  77. if (recursive)
  78. while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
  79. else
  80. while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0);
  81. return result;
  82. }
  83. void arm_tpl_cv::signal()
  84. {
  85. while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
  86. if (rt_sem_take(s, 0) == 0)
  87. rt_sem_release(h);
  88. rt_mutex_release(x);
  89. }
  90. void arm_tpl_cv::broadcast()
  91. {
  92. while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0);
  93. auto count = s->value;
  94. for (auto i = 0; i < count; i++)
  95. {
  96. while (rt_sem_take(s, ARM_TPL_MAX_DELAY) != 0);
  97. rt_sem_release(h);
  98. }
  99. rt_mutex_release(x);
  100. }
  101. static int check_create(volatile __ARM_TPL_condvar_t *__vcv)
  102. {
  103. if (__vcv->data == 0)
  104. {
  105. uintptr_t cv_new;
  106. cv_new = reinterpret_cast<uintptr_t>(new arm_tpl_cv());
  107. if (cv_new == 0)
  108. {
  109. return -1;
  110. }
  111. uintptr_t cv_null = 0;
  112. if (!atomic_compare_exchange_strong(&__vcv->data, &cv_null, cv_new))
  113. delete reinterpret_cast<arm_tpl_cv *>(cv_new);
  114. }
  115. return 0;
  116. }
  117. extern "C" int __ARM_TPL_condvar_wait(__ARM_TPL_condvar_t *__cv, __ARM_TPL_mutex_t *__m)
  118. {
  119. volatile __ARM_TPL_condvar_t *__vcv = __cv;
  120. if (check_create(__vcv) != 0)
  121. return -1;
  122. struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data);
  123. ((arm_tpl_cv *) __vcv->data)->wait(tmutex->mutex, tmutex->type == RECURSIVE);
  124. return 0;
  125. }
  126. extern "C" int __ARM_TPL_condvar_timedwait(__ARM_TPL_condvar_t *__cv,
  127. __ARM_TPL_mutex_t *__m,
  128. __ARM_TPL_timespec_t *__ts)
  129. {
  130. volatile __ARM_TPL_condvar_t *__vcv = __cv;
  131. if (check_create(__vcv) != 0)
  132. return -1;
  133. __ARM_TPL_timespec_t now;
  134. if (__ARM_TPL_clock_realtime(&now) != 0)
  135. return -1;
  136. struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data);
  137. unsigned int timeout_ms = (__ts->tv_sec - now.tv_sec) * 1000 + (__ts->tv_nsec - now.tv_nsec) / 1000000;
  138. if (((arm_tpl_cv *) __vcv->data)->timedwait(tmutex->mutex, tmutex->type == RECURSIVE, timeout_ms) < 0)
  139. return -1;
  140. return 0;
  141. }
  142. extern "C" int __ARM_TPL_condvar_signal(__ARM_TPL_condvar_t *__cv)
  143. {
  144. volatile __ARM_TPL_condvar_t *__vcv = __cv;
  145. if (__vcv->data != 0)
  146. ((arm_tpl_cv *) __vcv->data)->signal();
  147. return 0;
  148. }
  149. extern "C" int __ARM_TPL_condvar_broadcast(__ARM_TPL_condvar_t *__cv)
  150. {
  151. volatile __ARM_TPL_condvar_t *__vcv = __cv;
  152. if (__vcv->data != 0)
  153. ((arm_tpl_cv *) __vcv->data)->broadcast();
  154. return 0;
  155. }
  156. extern "C" int __ARM_TPL_condvar_destroy(__ARM_TPL_condvar_t *__cv)
  157. {
  158. volatile __ARM_TPL_condvar_t *__vcv = __cv;
  159. if (__vcv->data != 0)
  160. {
  161. delete (arm_tpl_cv *) __vcv->data;
  162. __vcv->data = 0;
  163. }
  164. return 0;
  165. }