bar.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* Copyright (C) 2005-2022 Free Software Foundation, Inc.
  2. Contributed by Richard Henderson <rth@redhat.com>.
  3. This file is part of the GNU Offloading and Multi Processing Library
  4. (libgomp).
  5. Libgomp is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. /* This is the default implementation of a barrier synchronization mechanism
  21. for libgomp. This type is private to the library. Note that we rely on
  22. being able to adjust the barrier count while threads are blocked, so the
  23. POSIX pthread_barrier_t won't work. */
  24. #include "libgomp.h"
  25. void
  26. gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
  27. {
  28. gomp_mutex_init (&bar->mutex1);
  29. #ifndef HAVE_SYNC_BUILTINS
  30. gomp_mutex_init (&bar->mutex2);
  31. #endif
  32. gomp_sem_init (&bar->sem1, 0);
  33. gomp_sem_init (&bar->sem2, 0);
  34. bar->total = count;
  35. bar->arrived = 0;
  36. bar->generation = 0;
  37. bar->cancellable = false;
  38. }
  39. void
  40. gomp_barrier_destroy (gomp_barrier_t *bar)
  41. {
  42. /* Before destroying, make sure all threads have left the barrier. */
  43. gomp_mutex_lock (&bar->mutex1);
  44. gomp_mutex_unlock (&bar->mutex1);
  45. gomp_mutex_destroy (&bar->mutex1);
  46. #ifndef HAVE_SYNC_BUILTINS
  47. gomp_mutex_destroy (&bar->mutex2);
  48. #endif
  49. gomp_sem_destroy (&bar->sem1);
  50. gomp_sem_destroy (&bar->sem2);
  51. }
  52. void
  53. gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count)
  54. {
  55. gomp_mutex_lock (&bar->mutex1);
  56. bar->total = count;
  57. gomp_mutex_unlock (&bar->mutex1);
  58. }
  59. void
  60. gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
  61. {
  62. unsigned int n;
  63. if (state & BAR_WAS_LAST)
  64. {
  65. n = --bar->arrived;
  66. if (n > 0)
  67. {
  68. do
  69. gomp_sem_post (&bar->sem1);
  70. while (--n != 0);
  71. gomp_sem_wait (&bar->sem2);
  72. }
  73. gomp_mutex_unlock (&bar->mutex1);
  74. }
  75. else
  76. {
  77. gomp_mutex_unlock (&bar->mutex1);
  78. gomp_sem_wait (&bar->sem1);
  79. #ifdef HAVE_SYNC_BUILTINS
  80. n = __sync_add_and_fetch (&bar->arrived, -1);
  81. #else
  82. gomp_mutex_lock (&bar->mutex2);
  83. n = --bar->arrived;
  84. gomp_mutex_unlock (&bar->mutex2);
  85. #endif
  86. if (n == 0)
  87. gomp_sem_post (&bar->sem2);
  88. }
  89. }
  90. void
  91. gomp_barrier_wait (gomp_barrier_t *barrier)
  92. {
  93. gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
  94. }
  95. void
  96. gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
  97. {
  98. unsigned int n;
  99. state &= ~BAR_CANCELLED;
  100. if (state & BAR_WAS_LAST)
  101. {
  102. n = --bar->arrived;
  103. struct gomp_thread *thr = gomp_thread ();
  104. struct gomp_team *team = thr->ts.team;
  105. team->work_share_cancelled = 0;
  106. if (team->task_count)
  107. {
  108. gomp_barrier_handle_tasks (state);
  109. if (n > 0)
  110. gomp_sem_wait (&bar->sem2);
  111. gomp_mutex_unlock (&bar->mutex1);
  112. return;
  113. }
  114. bar->generation = state + BAR_INCR - BAR_WAS_LAST;
  115. if (n > 0)
  116. {
  117. do
  118. gomp_sem_post (&bar->sem1);
  119. while (--n != 0);
  120. gomp_sem_wait (&bar->sem2);
  121. }
  122. gomp_mutex_unlock (&bar->mutex1);
  123. }
  124. else
  125. {
  126. gomp_mutex_unlock (&bar->mutex1);
  127. int gen;
  128. do
  129. {
  130. gomp_sem_wait (&bar->sem1);
  131. gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
  132. if (gen & BAR_TASK_PENDING)
  133. {
  134. gomp_barrier_handle_tasks (state);
  135. gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
  136. }
  137. }
  138. while (gen != state + BAR_INCR);
  139. #ifdef HAVE_SYNC_BUILTINS
  140. n = __sync_add_and_fetch (&bar->arrived, -1);
  141. #else
  142. gomp_mutex_lock (&bar->mutex2);
  143. n = --bar->arrived;
  144. gomp_mutex_unlock (&bar->mutex2);
  145. #endif
  146. if (n == 0)
  147. gomp_sem_post (&bar->sem2);
  148. }
  149. }
  150. bool
  151. gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
  152. gomp_barrier_state_t state)
  153. {
  154. unsigned int n;
  155. if (state & BAR_WAS_LAST)
  156. {
  157. bar->cancellable = false;
  158. n = --bar->arrived;
  159. struct gomp_thread *thr = gomp_thread ();
  160. struct gomp_team *team = thr->ts.team;
  161. team->work_share_cancelled = 0;
  162. if (team->task_count)
  163. {
  164. gomp_barrier_handle_tasks (state);
  165. if (n > 0)
  166. gomp_sem_wait (&bar->sem2);
  167. gomp_mutex_unlock (&bar->mutex1);
  168. return false;
  169. }
  170. bar->generation = state + BAR_INCR - BAR_WAS_LAST;
  171. if (n > 0)
  172. {
  173. do
  174. gomp_sem_post (&bar->sem1);
  175. while (--n != 0);
  176. gomp_sem_wait (&bar->sem2);
  177. }
  178. gomp_mutex_unlock (&bar->mutex1);
  179. }
  180. else
  181. {
  182. if (state & BAR_CANCELLED)
  183. {
  184. gomp_mutex_unlock (&bar->mutex1);
  185. return true;
  186. }
  187. bar->cancellable = true;
  188. gomp_mutex_unlock (&bar->mutex1);
  189. int gen;
  190. do
  191. {
  192. gomp_sem_wait (&bar->sem1);
  193. gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
  194. if (gen & BAR_CANCELLED)
  195. break;
  196. if (gen & BAR_TASK_PENDING)
  197. {
  198. gomp_barrier_handle_tasks (state);
  199. gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
  200. if (gen & BAR_CANCELLED)
  201. break;
  202. }
  203. }
  204. while (gen != state + BAR_INCR);
  205. #ifdef HAVE_SYNC_BUILTINS
  206. n = __sync_add_and_fetch (&bar->arrived, -1);
  207. #else
  208. gomp_mutex_lock (&bar->mutex2);
  209. n = --bar->arrived;
  210. gomp_mutex_unlock (&bar->mutex2);
  211. #endif
  212. if (n == 0)
  213. gomp_sem_post (&bar->sem2);
  214. if (gen & BAR_CANCELLED)
  215. return true;
  216. }
  217. return false;
  218. }
  219. void
  220. gomp_team_barrier_wait (gomp_barrier_t *barrier)
  221. {
  222. gomp_team_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
  223. }
  224. void
  225. gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
  226. {
  227. if (count == 0)
  228. count = bar->total - 1;
  229. while (count-- > 0)
  230. gomp_sem_post (&bar->sem1);
  231. }
  232. bool
  233. gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
  234. {
  235. gomp_barrier_state_t state = gomp_barrier_wait_cancel_start (bar);
  236. return gomp_team_barrier_wait_cancel_end (bar, state);
  237. }
  238. void
  239. gomp_team_barrier_cancel (struct gomp_team *team)
  240. {
  241. if (team->barrier.generation & BAR_CANCELLED)
  242. return;
  243. gomp_mutex_lock (&team->barrier.mutex1);
  244. gomp_mutex_lock (&team->task_lock);
  245. if (team->barrier.generation & BAR_CANCELLED)
  246. {
  247. gomp_mutex_unlock (&team->task_lock);
  248. gomp_mutex_unlock (&team->barrier.mutex1);
  249. return;
  250. }
  251. team->barrier.generation |= BAR_CANCELLED;
  252. gomp_mutex_unlock (&team->task_lock);
  253. if (team->barrier.cancellable)
  254. {
  255. int n = team->barrier.arrived;
  256. if (n > 0)
  257. {
  258. do
  259. gomp_sem_post (&team->barrier.sem1);
  260. while (--n != 0);
  261. gomp_sem_wait (&team->barrier.sem2);
  262. }
  263. team->barrier.cancellable = false;
  264. }
  265. gomp_mutex_unlock (&team->barrier.mutex1);
  266. }