ARGOBOTS
eventual.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 
32 int ABT_eventual_create(int nbytes, ABT_eventual *neweventual)
33 {
34  int abt_errno = ABT_SUCCESS;
35  ABTI_eventual *p_eventual;
36 
37  p_eventual = (ABTI_eventual *)ABTU_malloc(sizeof(ABTI_eventual));
38  ABTI_spinlock_clear(&p_eventual->lock);
39  p_eventual->ready = ABT_FALSE;
40  p_eventual->nbytes = nbytes;
41  p_eventual->value = (nbytes == 0) ? NULL : ABTU_malloc(nbytes);
42  p_eventual->p_head = NULL;
43  p_eventual->p_tail = NULL;
44 
45  *neweventual = ABTI_eventual_get_handle(p_eventual);
46 
47  return abt_errno;
48 }
49 
63 {
64  int abt_errno = ABT_SUCCESS;
65  ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(*eventual);
66  ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);
67 
68  /* The lock needs to be acquired to safely free the eventual structure.
69  * However, we do not have to unlock it because the entire structure is
70  * freed here. */
71  ABTI_spinlock_acquire(&p_eventual->lock);
72 
73  if (p_eventual->value)
74  ABTU_free(p_eventual->value);
75  ABTU_free(p_eventual);
76 
77  *eventual = ABT_EVENTUAL_NULL;
78 
79 fn_exit:
80  return abt_errno;
81 
82 fn_fail:
83  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
84  goto fn_exit;
85 }
86 
104 int ABT_eventual_wait(ABT_eventual eventual, void **value)
105 {
106  int abt_errno = ABT_SUCCESS;
107  ABTI_local *p_local = ABTI_local_get_local();
108  ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual);
109  ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);
110 
111  ABTI_spinlock_acquire(&p_eventual->lock);
112  if (p_eventual->ready == ABT_FALSE) {
113  ABTI_thread *p_current;
114  ABTI_unit *p_unit;
115  ABT_unit_type type;
116  ABTD_atomic_int32 ext_signal = ABTD_ATOMIC_INT32_STATIC_INITIALIZER(0);
117 
118  if (p_local != NULL) {
119  p_current = p_local->p_thread;
120  ABTI_CHECK_TRUE(p_current != NULL, ABT_ERR_EVENTUAL);
121 
122  type = ABT_UNIT_TYPE_THREAD;
123  p_unit = &p_current->unit_def;
124  p_unit->handle.thread = ABTI_thread_get_handle(p_current);
125  p_unit->type = type;
126  } else {
127  /* external thread */
128  type = ABT_UNIT_TYPE_EXT;
129  p_unit = (ABTI_unit *)ABTU_calloc(1, sizeof(ABTI_unit));
130  /* Check size if ext_signal can be stored in p_unit->handle.thread.
131  */
132  ABTI_STATIC_ASSERT(sizeof(ext_signal) <=
133  sizeof(p_unit->handle.thread));
134  p_unit->handle.thread = (ABT_thread)&ext_signal;
135  p_unit->type = type;
136  }
137 
138  p_unit->p_next = NULL;
139  if (p_eventual->p_head == NULL) {
140  p_eventual->p_head = p_unit;
141  p_eventual->p_tail = p_unit;
142  } else {
143  p_eventual->p_tail->p_next = p_unit;
144  p_eventual->p_tail = p_unit;
145  }
146 
147  if (type == ABT_UNIT_TYPE_THREAD) {
148  ABTI_thread_set_blocked(p_current);
149 
150  ABTI_spinlock_release(&p_eventual->lock);
151 
152  /* Suspend the current ULT */
153  ABTI_thread_suspend(&p_local, p_current);
154 
155  } else {
156  ABTI_spinlock_release(&p_eventual->lock);
157 
158  /* External thread is waiting here polling ext_signal. */
159  /* FIXME: need a better implementation */
160  while (!ABTD_atomic_acquire_load_int32(&ext_signal))
161  ;
162  ABTU_free(p_unit);
163  }
164  } else {
165  ABTI_spinlock_release(&p_eventual->lock);
166  }
167  if (value)
168  *value = p_eventual->value;
169 
170 fn_exit:
171  return abt_errno;
172 
173 fn_fail:
174  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
175  goto fn_exit;
176 }
177 
193 int ABT_eventual_test(ABT_eventual eventual, void **value, int *is_ready)
194 {
195  int abt_errno = ABT_SUCCESS;
196  ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual);
197  ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);
198  int flag = ABT_FALSE;
199 
200  ABTI_spinlock_acquire(&p_eventual->lock);
201  if (p_eventual->ready != ABT_FALSE) {
202  if (value)
203  *value = p_eventual->value;
204  flag = ABT_TRUE;
205  }
206  ABTI_spinlock_release(&p_eventual->lock);
207 
208  *is_ready = flag;
209 
210 fn_exit:
211  return abt_errno;
212 
213 fn_fail:
214  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
215  goto fn_exit;
216 }
217 
235 int ABT_eventual_set(ABT_eventual eventual, void *value, int nbytes)
236 {
237  int abt_errno = ABT_SUCCESS;
238  ABTI_local *p_local = ABTI_local_get_local();
239  ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual);
240  ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);
241  ABTI_CHECK_TRUE(nbytes <= p_eventual->nbytes, ABT_ERR_INV_EVENTUAL);
242 
243  ABTI_spinlock_acquire(&p_eventual->lock);
244 
245  p_eventual->ready = ABT_TRUE;
246  if (p_eventual->value)
247  memcpy(p_eventual->value, value, nbytes);
248 
249  if (p_eventual->p_head == NULL) {
250  ABTI_spinlock_release(&p_eventual->lock);
251  goto fn_exit;
252  }
253 
254  /* Wake up all waiting ULTs */
255  ABTI_unit *p_head = p_eventual->p_head;
256  ABTI_unit *p_unit = p_head;
257  while (1) {
258  ABTI_unit *p_next = p_unit->p_next;
259  ABT_unit_type type = p_unit->type;
260 
261  p_unit->p_next = NULL;
262 
263  if (type == ABT_UNIT_TYPE_THREAD) {
264  ABTI_thread *p_thread = ABTI_thread_get_ptr(p_unit->handle.thread);
265  ABTI_thread_set_ready(p_local, p_thread);
266  } else {
267  /* When the head is an external thread */
268  ABTD_atomic_int32 *p_ext_signal =
269  (ABTD_atomic_int32 *)p_unit->handle.thread;
270  ABTD_atomic_release_store_int32(p_ext_signal, 1);
271  }
272 
273  /* Next ULT */
274  if (p_next != NULL) {
275  p_unit = p_next;
276  } else {
277  break;
278  }
279  }
280 
281  p_eventual->p_head = NULL;
282  p_eventual->p_tail = NULL;
283 
284  ABTI_spinlock_release(&p_eventual->lock);
285 
286 fn_exit:
287  return abt_errno;
288 
289 fn_fail:
290  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
291  goto fn_exit;
292 }
293 
307 {
308  int abt_errno = ABT_SUCCESS;
309  ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual);
310  ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual);
311 
312  ABTI_spinlock_acquire(&p_eventual->lock);
313  p_eventual->ready = ABT_FALSE;
314  ABTI_spinlock_release(&p_eventual->lock);
315 
316 fn_exit:
317  return abt_errno;
318 
319 fn_fail:
320  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
321  goto fn_exit;
322 }
int ABT_eventual_reset(ABT_eventual eventual)
Reset the readiness of the target eventual.
Definition: eventual.c:306
static void * ABTU_malloc(size_t size)
Definition: abtu.h:39
#define ABT_ERR_INV_EVENTUAL
Definition: abt.h:88
#define ABT_FALSE
Definition: abt.h:224
struct ABT_thread_opaque * ABT_thread
Definition: abt.h:279
#define ABT_EVENTUAL_NULL
Definition: abt.h:352
#define HANDLE_ERROR_FUNC_WITH_CODE(n)
Definition: abti_error.h:241
#define ABT_SUCCESS
Definition: abt.h:64
#define ABT_ERR_EVENTUAL
Definition: abt.h:108
int ABT_eventual_free(ABT_eventual *eventual)
Free the eventual object.
Definition: eventual.c:62
#define ABT_TRUE
Definition: abt.h:223
ABT_unit_type
Definition: abt.h:170
struct ABT_eventual_opaque * ABT_eventual
Definition: abt.h:301
int ABT_eventual_wait(ABT_eventual eventual, void **value)
Wait on the eventual.
Definition: eventual.c:104
int ABT_eventual_test(ABT_eventual eventual, void **value, int *is_ready)
Test the readiness of an eventual.
Definition: eventual.c:193
static void ABTU_free(void *ptr)
Definition: abtu.h:32
int ABT_eventual_create(int nbytes, ABT_eventual *neweventual)
Create an eventual.
Definition: eventual.c:32
int ABT_eventual_set(ABT_eventual eventual, void *value, int nbytes)
Signal the eventual.
Definition: eventual.c:235
static void * ABTU_calloc(size_t num, size_t size)
Definition: abtu.h:49