ARGOBOTS
barrier.c
Go to the documentation of this file.
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  * See COPYRIGHT in top-level directory.
4  */
5 
6 #include "abti.h"
7 
26 int ABT_barrier_create(uint32_t num_waiters, ABT_barrier *newbarrier)
27 {
28  int abt_errno = ABT_SUCCESS;
29  ABTI_barrier *p_newbarrier;
30 
31  p_newbarrier = (ABTI_barrier *)ABTU_malloc(sizeof(ABTI_barrier));
32 
33  ABTI_spinlock_clear(&p_newbarrier->lock);
34  p_newbarrier->num_waiters = num_waiters;
35  p_newbarrier->counter = 0;
36  p_newbarrier->waiters =
37  (ABTI_thread **)ABTU_malloc(num_waiters * sizeof(ABTI_thread *));
38  p_newbarrier->waiter_type =
39  (ABT_unit_type *)ABTU_malloc(num_waiters * sizeof(ABT_unit_type));
40 
41  /* Return value */
42  *newbarrier = ABTI_barrier_get_handle(p_newbarrier);
43 
44  return abt_errno;
45 }
46 
60 int ABT_barrier_reinit(ABT_barrier barrier, uint32_t num_waiters)
61 {
62  int abt_errno = ABT_SUCCESS;
63  ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(barrier);
64  ABTI_CHECK_NULL_BARRIER_PTR(p_barrier);
65 
66  ABTI_ASSERT(p_barrier->counter == 0);
67 
68  /* Only when num_waiters is different from p_barrier->num_waiters, we
69  * change p_barrier. */
70  if (num_waiters < p_barrier->num_waiters) {
71  /* We can reuse waiters and waiter_type arrays */
72  p_barrier->num_waiters = num_waiters;
73  } else if (num_waiters > p_barrier->num_waiters) {
74  /* Free existing arrays and reallocate them */
75  p_barrier->num_waiters = num_waiters;
76  ABTU_free(p_barrier->waiters);
77  ABTU_free(p_barrier->waiter_type);
78  p_barrier->waiters =
79  (ABTI_thread **)ABTU_malloc(num_waiters * sizeof(ABTI_thread *));
80  p_barrier->waiter_type =
81  (ABT_unit_type *)ABTU_malloc(num_waiters * sizeof(ABT_unit_type));
82  }
83 
84 fn_exit:
85  return abt_errno;
86 
87 fn_fail:
88  HANDLE_ERROR_WITH_CODE("ABT_barrier_reinit", abt_errno);
89  goto fn_exit;
90 }
91 
105 {
106  int abt_errno = ABT_SUCCESS;
107  ABT_barrier h_barrier = *barrier;
108  ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(h_barrier);
109  ABTI_CHECK_NULL_BARRIER_PTR(p_barrier);
110 
111  ABTI_ASSERT(p_barrier->counter == 0);
112 
113  /* The lock needs to be acquired to safely free the barrier structure.
114  * However, we do not have to unlock it because the entire structure is
115  * freed here. */
116  ABTI_spinlock_acquire(&p_barrier->lock);
117 
118  ABTU_free(p_barrier->waiters);
119  ABTU_free(p_barrier->waiter_type);
120  ABTU_free(p_barrier);
121 
122  /* Return value */
123  *barrier = ABT_BARRIER_NULL;
124 
125 fn_exit:
126  return abt_errno;
127 
128 fn_fail:
129  HANDLE_ERROR_WITH_CODE("ABT_barrier_free", abt_errno);
130  goto fn_exit;
131 }
132 
145 {
146  int abt_errno = ABT_SUCCESS;
147  ABTI_local *p_local = ABTI_local_get_local();
148  ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(barrier);
149  ABTI_CHECK_NULL_BARRIER_PTR(p_barrier);
150  uint32_t pos;
151 
152  ABTI_spinlock_acquire(&p_barrier->lock);
153 
154  ABTI_ASSERT(p_barrier->counter < p_barrier->num_waiters);
155  pos = p_barrier->counter++;
156 
157  /* If we do not have all the waiters yet */
158  if (p_barrier->counter < p_barrier->num_waiters) {
159  ABTI_thread *p_thread;
160  ABT_unit_type type;
161  ABTD_atomic_int32 ext_signal = ABTD_ATOMIC_INT32_STATIC_INITIALIZER(0);
162 
163  if (p_local != NULL) {
164  p_thread = p_local->p_thread;
165  if (p_thread == NULL) {
166  abt_errno = ABT_ERR_BARRIER;
167  goto fn_fail;
168  }
169  type = ABT_UNIT_TYPE_THREAD;
170  } else {
171  /* external thread */
172  /* Check size if ext_signal can be stored in p_thread. */
173  ABTI_STATIC_ASSERT(sizeof(ext_signal) <= sizeof(p_thread));
174  p_thread = (ABTI_thread *)&ext_signal;
175  type = ABT_UNIT_TYPE_EXT;
176  }
177 
178  /* Keep the waiter's information */
179  p_barrier->waiters[pos] = p_thread;
180  p_barrier->waiter_type[pos] = type;
181 
182  if (type == ABT_UNIT_TYPE_THREAD) {
183  /* Change the ULT's state to BLOCKED */
184  ABTI_thread_set_blocked(p_thread);
185  }
186 
187  ABTI_spinlock_release(&p_barrier->lock);
188 
189  if (type == ABT_UNIT_TYPE_THREAD) {
190  /* Suspend the current ULT */
191  ABTI_thread_suspend(&p_local, p_thread);
192  } else {
193  /* External thread is waiting here polling ext_signal. */
194  /* FIXME: need a better implementation */
195  while (!ABTD_atomic_acquire_load_int32(&ext_signal))
196  ;
197  }
198  } else {
199  /* Signal all the waiting ULTs */
200  int i;
201  for (i = 0; i < p_barrier->num_waiters - 1; i++) {
202  ABTI_thread *p_thread = p_barrier->waiters[i];
203  if (p_barrier->waiter_type[i] == ABT_UNIT_TYPE_THREAD) {
204  ABTI_thread_set_ready(p_local, p_thread);
205  } else {
206  /* When p_cur is an external thread */
207  ABTD_atomic_int32 *p_ext_signal = (ABTD_atomic_int32 *)p_thread;
208  ABTD_atomic_release_store_int32(p_ext_signal, 1);
209  }
210 
211  p_barrier->waiters[i] = NULL;
212  }
213 
214  /* Reset counter */
215  p_barrier->counter = 0;
216 
217  ABTI_spinlock_release(&p_barrier->lock);
218  }
219 
220 fn_exit:
221  return abt_errno;
222 
223 fn_fail:
224  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
225  goto fn_exit;
226 }
227 
241 int ABT_barrier_get_num_waiters(ABT_barrier barrier, uint32_t *num_waiters)
242 {
243  int abt_errno = ABT_SUCCESS;
244  ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(barrier);
245  ABTI_CHECK_NULL_BARRIER_PTR(p_barrier);
246 
247  *num_waiters = p_barrier->num_waiters;
248 
249 fn_exit:
250  return abt_errno;
251 
252 fn_fail:
253  HANDLE_ERROR_WITH_CODE("ABT_barrier_get_num_waiters", abt_errno);
254  goto fn_exit;
255 }
struct ABT_barrier_opaque * ABT_barrier
Definition: abt.h:305
int ABT_barrier_free(ABT_barrier *barrier)
Free the barrier.
Definition: barrier.c:104
#define ABT_ERR_BARRIER
Definition: abt.h:110
int ABT_barrier_create(uint32_t num_waiters, ABT_barrier *newbarrier)
Create a new barrier.
Definition: barrier.c:26
static void * ABTU_malloc(size_t size)
Definition: abtu.h:39
#define HANDLE_ERROR_WITH_CODE(msg, n)
Definition: abti_error.h:234
#define HANDLE_ERROR_FUNC_WITH_CODE(n)
Definition: abti_error.h:241
int ABT_barrier_reinit(ABT_barrier barrier, uint32_t num_waiters)
Reinitialize the barrier.
Definition: barrier.c:60
#define ABT_SUCCESS
Definition: abt.h:64
ABT_unit_type
Definition: abt.h:170
int ABT_barrier_wait(ABT_barrier barrier)
Wait on the barrier.
Definition: barrier.c:144
int ABT_barrier_get_num_waiters(ABT_barrier barrier, uint32_t *num_waiters)
Get the number of waiters for the barrier.
Definition: barrier.c:241
static void ABTU_free(void *ptr)
Definition: abtu.h:32
#define ABT_BARRIER_NULL
Definition: abt.h:354