ARGOBOTS  1227c643f7a7f974f1f1778a9ffebd29d7dafecf
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
abti_cond.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_COND_H_INCLUDED
7 #define ABTI_COND_H_INCLUDED
8 
9 #include "abti_mutex.h"
10 
11 /* Inlined functions for Condition Variable */
12 
13 static inline void ABTI_cond_init(ABTI_cond *p_cond)
14 {
15  ABTI_spinlock_clear(&p_cond->lock);
16  p_cond->p_waiter_mutex = NULL;
17  p_cond->num_waiters = 0;
18  p_cond->p_head = NULL;
19  p_cond->p_tail = NULL;
20 }
21 
22 static inline void ABTI_cond_fini(ABTI_cond *p_cond)
23 {
24  /* The lock needs to be acquired to safely free the condition structure.
25  * However, we do not have to unlock it because the entire structure is
26  * freed here. */
27  ABTI_spinlock_acquire(&p_cond->lock);
28 }
29 
30 static inline ABTI_cond *ABTI_cond_get_ptr(ABT_cond cond)
31 {
32 #ifndef ABT_CONFIG_DISABLE_ERROR_CHECK
33  ABTI_cond *p_cond;
34  if (cond == ABT_COND_NULL) {
35  p_cond = NULL;
36  } else {
37  p_cond = (ABTI_cond *)cond;
38  }
39  return p_cond;
40 #else
41  return (ABTI_cond *)cond;
42 #endif
43 }
44 
45 static inline ABT_cond ABTI_cond_get_handle(ABTI_cond *p_cond)
46 {
47 #ifndef ABT_CONFIG_DISABLE_ERROR_CHECK
48  ABT_cond h_cond;
49  if (p_cond == NULL) {
50  h_cond = ABT_COND_NULL;
51  } else {
52  h_cond = (ABT_cond)p_cond;
53  }
54  return h_cond;
55 #else
56  return (ABT_cond)p_cond;
57 #endif
58 }
59 
60 ABTU_ret_err static inline int
61 ABTI_cond_wait(ABTI_local **pp_local, ABTI_cond *p_cond, ABTI_mutex *p_mutex)
62 {
63  ABTI_ythread *p_ythread = NULL;
64  ABTI_thread *p_thread;
65 
66  ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local);
67  if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) {
68  p_thread = p_local_xstream->p_thread;
69  p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
70  }
71  if (!p_ythread) {
72  /* external thread or non-yieldable thread */
73  int abt_errno = ABTU_calloc(1, sizeof(ABTI_thread), (void **)&p_thread);
74  ABTI_CHECK_ERROR_RET(abt_errno);
75  p_thread->type = ABTI_THREAD_TYPE_EXT;
76  /* use state for synchronization */
77  ABTD_atomic_relaxed_store_int(&p_thread->state,
79  }
80 
81  ABTI_spinlock_acquire(&p_cond->lock);
82 
83  if (p_cond->p_waiter_mutex == NULL) {
84  p_cond->p_waiter_mutex = p_mutex;
85  } else {
86  if (p_cond->p_waiter_mutex != p_mutex) {
87  ABTI_spinlock_release(&p_cond->lock);
88  if (!p_ythread)
89  ABTU_free(p_thread);
90  return ABT_ERR_INV_MUTEX;
91  }
92  }
93 
94  if (p_cond->num_waiters == 0) {
95  p_thread->p_prev = p_thread;
96  p_thread->p_next = p_thread;
97  p_cond->p_head = p_thread;
98  p_cond->p_tail = p_thread;
99  } else {
100  p_cond->p_tail->p_next = p_thread;
101  p_cond->p_head->p_prev = p_thread;
102  p_thread->p_prev = p_cond->p_tail;
103  p_thread->p_next = p_cond->p_head;
104  p_cond->p_tail = p_thread;
105  }
106 
107  p_cond->num_waiters++;
108 
109  if (p_ythread) {
110  /* Change the ULT's state to BLOCKED */
111  ABTI_ythread_set_blocked(p_ythread);
112 
113  ABTI_spinlock_release(&p_cond->lock);
114 
115  /* Unlock the mutex that the calling ULT is holding */
116  /* FIXME: should check if mutex was locked by the calling ULT */
117  ABTI_mutex_unlock(ABTI_xstream_get_local(p_local_xstream), p_mutex);
118 
119  /* Suspend the current ULT */
120  ABTI_ythread_suspend(&p_local_xstream, p_ythread,
121  ABT_SYNC_EVENT_TYPE_COND, (void *)p_cond);
122  *pp_local = ABTI_xstream_get_local(p_local_xstream);
123  } else {
124  ABTI_spinlock_release(&p_cond->lock);
125  ABTI_mutex_unlock(ABTI_xstream_get_local(p_local_xstream), p_mutex);
126 
127  /* External thread is waiting here. */
128  while (ABTD_atomic_acquire_load_int(&p_thread->state) !=
130  ;
131  ABTU_free(p_thread);
132  }
133 
134  /* Lock the mutex again */
135  ABTI_mutex_lock(pp_local, p_mutex);
136  return ABT_SUCCESS;
137 }
138 
139 static inline void ABTI_cond_broadcast(ABTI_local *p_local, ABTI_cond *p_cond)
140 {
141  ABTI_spinlock_acquire(&p_cond->lock);
142 
143  if (p_cond->num_waiters == 0) {
144  ABTI_spinlock_release(&p_cond->lock);
145  return;
146  }
147 
148  /* Wake up all waiting ULTs */
149  ABTI_thread *p_head = p_cond->p_head;
150  ABTI_thread *p_thread = p_head;
151  while (1) {
152  ABTI_thread *p_next = p_thread->p_next;
153 
154  p_thread->p_prev = NULL;
155  p_thread->p_next = NULL;
156 
157  ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread);
158  if (p_ythread) {
159  ABTI_ythread_set_ready(p_local, p_ythread);
160  } else {
161  /* When the head is an external thread */
162  ABTD_atomic_release_store_int(&p_thread->state,
164  }
165 
166  /* Next ULT */
167  if (p_next != p_head) {
168  p_thread = p_next;
169  } else {
170  break;
171  }
172  }
173 
174  p_cond->p_waiter_mutex = NULL;
175  p_cond->num_waiters = 0;
176  p_cond->p_head = NULL;
177  p_cond->p_tail = NULL;
178 
179  ABTI_spinlock_release(&p_cond->lock);
180 }
181 
182 #endif /* ABTI_COND_H_INCLUDED */
#define ABT_ERR_INV_MUTEX
Definition: abt.h:84
#define ABT_SUCCESS
Definition: abt.h:64
#define ABT_COND_NULL
Definition: abt.h:421
static ABTU_ret_err int ABTU_calloc(size_t num, size_t size, void **p_ptr)
Definition: abtu.h:152
static void ABTU_free(void *ptr)
Definition: abtu.h:135
#define ABTU_ret_err
Definition: abtu.h:49
struct ABT_cond_opaque * ABT_cond
Definition: abt.h:361