ARGOBOTS  140a356fc09a44696eb3487150e459266f9b5405
abti_waitlist.h
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 #ifndef ABTI_WAITLIST_H_INCLUDED
7 #define ABTI_WAITLIST_H_INCLUDED
8 
9 #include "abt_config.h"
10 
11 static inline void ABTI_waitlist_init(ABTI_waitlist *p_waitlist)
12 {
13  p_waitlist->p_head = NULL;
14  p_waitlist->p_tail = NULL;
15 }
16 
17 static inline void
18 ABTI_waitlist_wait_and_unlock(ABTI_local **pp_local, ABTI_waitlist *p_waitlist,
19  ABTI_spinlock *p_lock, ABT_bool blocking,
20  ABT_sync_event_type sync_event_type, void *p_sync)
21 {
22  ABTI_ASSERT(ABTI_spinlock_is_locked(p_lock) == ABT_TRUE);
23  ABTI_ythread *p_ythread = NULL;
24  ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local);
25  if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) {
26  p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread);
27  }
28  if (!p_ythread || blocking) {
29  /* External thread, non-yieldable thread, or asked to block */
30  ABTI_thread thread;
31  thread.type = ABTI_THREAD_TYPE_EXT;
32  /* use state for synchronization */
33  ABTD_atomic_relaxed_store_int(&thread.state, ABT_THREAD_STATE_BLOCKED);
34  /* Add thread to the list. */
35  thread.p_next = NULL;
36  if (p_waitlist->p_head == NULL) {
37  p_waitlist->p_head = &thread;
38  } else {
39  p_waitlist->p_tail->p_next = &thread;
40  }
41  p_waitlist->p_tail = &thread;
42 
43  /* Non-yieldable thread is waiting here. */
44  ABTI_spinlock_release(p_lock);
45  while (ABTD_atomic_acquire_load_int(&thread.state) !=
47  ;
48  } else {
49  /* Add p_thread to the list. */
50  p_ythread->thread.p_next = NULL;
51  if (p_waitlist->p_head == NULL) {
52  p_waitlist->p_head = &p_ythread->thread;
53  } else {
54  p_waitlist->p_tail->p_next = &p_ythread->thread;
55  }
56  p_waitlist->p_tail = &p_ythread->thread;
57 
58  /* Suspend the current ULT */
59  ABTI_ythread_set_blocked(p_ythread);
60  ABTI_spinlock_release(p_lock);
61  ABTI_ythread_suspend(&p_local_xstream, p_ythread,
63  /* Resumed. */
64  *pp_local = ABTI_xstream_get_local(p_local_xstream);
65  }
66 }
67 
68 /* Return ABT_TRUE if timed out. */
69 static inline ABT_bool ABTI_waitlist_wait_timedout_and_unlock(
70  ABTI_local **pp_local, ABTI_waitlist *p_waitlist, ABTI_spinlock *p_lock,
71  ABT_bool blocking, double target_time, ABT_sync_event_type sync_event_type,
72  void *p_sync)
73 {
74  ABTI_ASSERT(ABTI_spinlock_is_locked(p_lock) == ABT_TRUE);
75  ABTI_ythread *p_ythread = NULL;
76  ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local);
77  if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream)
78  p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread);
79 
80  /* Always use a dummy thread. */
81  ABTI_thread thread;
82  thread.type = ABTI_THREAD_TYPE_EXT;
83  /* use state for synchronization */
84  ABTD_atomic_relaxed_store_int(&thread.state, ABT_THREAD_STATE_BLOCKED);
85 
86  /* Add p_thread to the list. This implementation is tricky since this
87  * updates p_prev as well for removal on timeout while the other functions
88  * (e.g., wait, broadcast, signal) do not update it. */
89  thread.p_next = NULL;
90  if (p_waitlist->p_head == NULL) {
91  p_waitlist->p_head = &thread;
92  thread.p_prev = NULL;
93  } else {
94  p_waitlist->p_tail->p_next = &thread;
95  thread.p_prev = p_waitlist->p_tail;
96  }
97  p_waitlist->p_tail = &thread;
98 
99  /* Waiting here. */
100  ABTI_spinlock_release(p_lock);
101  while (ABTD_atomic_acquire_load_int(&thread.state) !=
103  double cur_time = ABTI_get_wtime();
104  if (cur_time >= target_time) {
105  /* Timeout. Remove this thread if not signaled even after taking
106  * a lock. */
107  ABTI_spinlock_acquire(p_lock);
108  ABT_bool is_timedout =
109  (ABTD_atomic_acquire_load_int(&thread.state) !=
111  ? ABT_TRUE
112  : ABT_FALSE;
113  if (is_timedout) {
114  /* This thread is still in the list. */
115  if (p_waitlist->p_head == &thread) {
116  /* thread is a head. */
117  /* Note that thread->p_prev cannot be used to check whether
118  * thread is a head or not because signal and broadcast do
119  * not modify thread->p_prev. */
120  p_waitlist->p_head = thread.p_next;
121  if (!thread.p_next) {
122  /* This thread is p_tail */
123  ABTI_ASSERT(p_waitlist->p_tail == &thread);
124  p_waitlist->p_tail = NULL;
125  }
126  } else {
127  /* thread is not a head and thus p_prev exists. */
128  ABTI_ASSERT(thread.p_prev);
129  thread.p_prev->p_next = thread.p_next;
130  if (thread.p_next && thread.type == ABTI_THREAD_TYPE_EXT) {
131  /* Only an external thread (created by this function)
132  * checks p_prev. Note that an external thread is
133  * dummy, so updating p_prev is allowed. */
134  thread.p_next->p_prev = thread.p_prev;
135  } else {
136  /* This thread is p_tail */
137  ABTI_ASSERT(p_waitlist->p_tail == &thread);
138  p_waitlist->p_tail = thread.p_prev;
139  }
140  }
141  /* We do not need to modify thread->p_prev and p_next since this
142  * dummy thread is no longer used. */
143  }
144  ABTI_spinlock_release(p_lock);
145  return is_timedout;
146  }
147  if (p_ythread && !blocking) {
148  ABTI_ythread_yield(&p_local_xstream, p_ythread, sync_event_type,
149  p_sync);
150  *pp_local = ABTI_xstream_get_local(p_local_xstream);
151  } else {
152  ABTD_atomic_pause();
153  }
154  }
155  /* Singled */
156  return ABT_FALSE;
157 }
158 
159 static inline void ABTI_waitlist_signal(ABTI_local *p_local,
160  ABTI_waitlist *p_waitlist)
161 {
162  ABTI_thread *p_thread = p_waitlist->p_head;
163  if (p_thread) {
164  ABTI_thread *p_next = p_thread->p_next;
165  p_thread->p_next = NULL;
166 
167  ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
168  if (p_ythread) {
169  ABTI_ythread_set_ready(p_local, p_ythread);
170  } else {
171  /* When p_thread is an external thread or a tasklet */
172  ABTD_atomic_release_store_int(&p_thread->state,
174  }
175  /* After updating p_thread->state, p_thread can be updated and
176  * freed. */
177  p_waitlist->p_head = p_next;
178  if (!p_next)
179  p_waitlist->p_tail = NULL;
180  }
181 }
182 
183 static inline void ABTI_waitlist_broadcast(ABTI_local *p_local,
184  ABTI_waitlist *p_waitlist)
185 {
186  ABTI_thread *p_thread = p_waitlist->p_head;
187  if (p_thread) {
188  do {
189  ABTI_thread *p_next = p_thread->p_next;
190  p_thread->p_next = NULL;
191 
192  ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
193  if (p_ythread) {
194  ABTI_ythread_set_ready(p_local, p_ythread);
195  } else {
196  /* When p_thread is an external thread or a tasklet */
197  ABTD_atomic_release_store_int(&p_thread->state,
199  }
200  /* After updating p_thread->state, p_thread can be updated and
201  * freed. */
202  p_thread = p_next;
203  } while (p_thread);
204  p_waitlist->p_head = NULL;
205  p_waitlist->p_tail = NULL;
206  }
207 }
208 
209 static inline ABT_bool ABTI_waitlist_is_empty(ABTI_waitlist *p_waitlist)
210 {
211  return p_waitlist->p_head ? ABT_TRUE : ABT_FALSE;
212 }
213 
214 #endif /* ABTI_WAITLIST_H_INCLUDED */
ABT_bool
int ABT_bool
Boolean type.
Definition: abt.h:988
ABT_THREAD_STATE_READY
@ ABT_THREAD_STATE_READY
Definition: abt.h:409
ABT_sync_event_type
ABT_sync_event_type
Type of synchronization event.
Definition: abt.h:647
ABT_THREAD_STATE_BLOCKED
@ ABT_THREAD_STATE_BLOCKED
Definition: abt.h:413
abt_config.h
ABT_SYNC_EVENT_TYPE_EVENTUAL
@ ABT_SYNC_EVENT_TYPE_EVENTUAL
Definition: abt.h:665
ABT_TRUE
#define ABT_TRUE
True constant for ABT_bool.
Definition: abt.h:735
ABT_FALSE
#define ABT_FALSE
False constant for ABT_bool.
Definition: abt.h:737