ARGOBOTS  4dc37e16e1b227a480715ab67dae1dcfb4d2d4e0
abtd_ucontext.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 ABTD_UCONTEXT_H_INCLUDED
7 #define ABTD_UCONTEXT_H_INCLUDED
8 
9 struct ABTD_ythread_context {
10  void *p_ctx; /* actual context of fcontext, or a
11  * pointer to uctx */
12  ABTD_ythread_context_atomic_ptr p_link; /* pointer to scheduler context */
13  ucontext_t uctx; /* ucontext pointed by p_ctx */
14  void *p_stacktop; /* Stack pointer (top). */
15  size_t stacksize; /* Stack size. */
16  /* Call-back functions. */
17  void (*f_cb)(void *);
18  void *cb_arg;
19  /* Peek functions. */
20  void (*peek_func)(void *);
21  void *peek_arg;
22  ucontext_t *p_peek_uctx;
23  ABT_bool is_peeked;
24 };
25 
26 static inline void ABTDI_ucontext_check_peeked(ABTD_ythread_context *p_self)
27 {
28  /* Check if this thread is called only for peeked */
29  while (ABTU_unlikely(p_self->is_peeked)) {
30  p_self->peek_func(p_self->peek_arg);
31  /* Reset the flag. */
32  p_self->is_peeked = ABT_FALSE;
33  int ret = swapcontext(&p_self->uctx, p_self->p_peek_uctx);
34  ABTI_ASSERT(ret == 0); /* Fatal. */
35  if (p_self->f_cb) {
36  p_self->f_cb(p_self->cb_arg);
37  p_self->f_cb = NULL;
38  }
39  }
40 }
41 
42 static void ABTD_ucontext_wrapper(int arg1, int arg2)
43 {
44  ABTD_ythread_context *p_self;
45 #if SIZEOF_VOID_P == 8
46  p_self = (ABTD_ythread_context *)(((uintptr_t)((uint32_t)arg1) << 32) |
47  ((uintptr_t)((uint32_t)arg2)));
48 #elif SIZEOF_VOID_P == 4
49  p_self = (ABTD_ythread_context *)((uintptr_t)arg1);
50 #else
51 #error "Unknown pointer size."
52 #endif
53 
54  if (p_self->f_cb) {
55  p_self->f_cb(p_self->cb_arg);
56  p_self->f_cb = NULL;
57  }
59  ABTD_ythread_func_wrapper(p_self);
61 }
62 
63 static inline void ABTD_ythread_context_init(ABTD_ythread_context *p_ctx,
64  void *p_stacktop, size_t stacksize)
65 {
66  p_ctx->p_ctx = NULL;
67  p_ctx->p_stacktop = p_stacktop;
68  p_ctx->stacksize = stacksize;
69  int ret = getcontext(&p_ctx->uctx);
70  ABTI_ASSERT(ret == 0); /* getcontext() should not return an error. */
71  ABTD_atomic_relaxed_store_ythread_context_ptr(&p_ctx->p_link, NULL);
72 }
73 
74 static inline void ABTD_ythread_context_init_lazy(ABTD_ythread_context *p_ctx,
75  size_t stacksize)
76 {
77  ABTD_ythread_context_init(p_ctx, NULL, stacksize);
78 }
79 
80 static inline void
81 ABTD_ythread_context_lazy_set_stack(ABTD_ythread_context *p_ctx,
82  void *p_stacktop)
83 {
84  p_ctx->p_stacktop = p_stacktop;
85 }
86 
87 static inline void
88 ABTD_ythread_context_lazy_unset_stack(ABTD_ythread_context *p_ctx)
89 {
90  p_ctx->p_stacktop = NULL;
91 }
92 
93 static inline void ABTD_ythread_context_reinit(ABTD_ythread_context *p_ctx)
94 {
95  p_ctx->p_ctx = NULL;
96  int ret = getcontext(&p_ctx->uctx);
97  ABTI_ASSERT(ret == 0); /* getcontext() should not return an error. */
98  ABTD_atomic_relaxed_store_ythread_context_ptr(&p_ctx->p_link, NULL);
99 }
100 
101 static inline void *
102 ABTD_ythread_context_get_stacktop(ABTD_ythread_context *p_ctx)
103 {
104  return p_ctx->p_stacktop;
105 }
106 
107 static inline ABT_bool
108 ABTD_ythread_context_has_stack(const ABTD_ythread_context *p_ctx)
109 {
110  return p_ctx->p_stacktop ? ABT_TRUE : ABT_FALSE;
111 }
112 
113 static inline size_t
114 ABTD_ythread_context_get_stacksize(ABTD_ythread_context *p_ctx)
115 {
116  return p_ctx->stacksize;
117 }
118 
119 static inline void ABTDI_ythread_context_make(ABTD_ythread_context *p_ctx)
120 {
121  p_ctx->p_ctx = &p_ctx->uctx;
122  /* uc_link is not used. */
123  p_ctx->uctx.uc_link = NULL;
124  void *p_stack = (void *)(((char *)p_ctx->p_stacktop) - p_ctx->stacksize);
125  p_ctx->uctx.uc_stack.ss_sp = p_stack;
126  p_ctx->uctx.uc_stack.ss_size = p_ctx->stacksize;
127 
128 #if SIZEOF_VOID_P == 8
129  int arg_upper = (int)(((uintptr_t)p_ctx) >> 32);
130  int arg_lower = (int)(((uintptr_t)p_ctx) >> 0);
131  makecontext(&p_ctx->uctx, (void (*)())ABTD_ucontext_wrapper, 2, arg_upper,
132  arg_lower);
133 #elif SIZEOF_VOID_P == 4
134  int arg = (int)((uintptr_t)p_ctx);
135  makecontext(&p_ctx->uctx, (void (*)())ABTD_ucontext_wrapper, 1, arg);
136 #else
137 #error "Unknown pointer size."
138 #endif
139  p_ctx->is_peeked = ABT_FALSE;
140 }
141 
142 static inline ABT_bool
143 ABTD_ythread_context_is_started(const ABTD_ythread_context *p_ctx)
144 {
145  return p_ctx->p_ctx ? ABT_TRUE : ABT_FALSE;
146 }
147 
148 static inline void ABTD_ythread_context_switch(ABTD_ythread_context *p_old,
149  ABTD_ythread_context *p_new)
150 {
151  ABTI_UB_ASSERT(ABTD_ythread_context_is_started(p_new));
152  p_old->is_peeked = ABT_FALSE;
153  p_old->p_ctx = &p_old->uctx;
154  p_new->f_cb = NULL;
155  int ret = swapcontext(&p_old->uctx, &p_new->uctx);
156  /* Fatal. This out-of-stack error is not recoverable. */
157  ABTI_ASSERT(ret == 0);
158  if (p_old->f_cb) {
159  p_old->f_cb(p_old->cb_arg);
160  p_old->f_cb = NULL;
161  }
163 }
164 
165 static inline void
166 ABTD_ythread_context_start_and_switch(ABTD_ythread_context *p_old,
167  ABTD_ythread_context *p_new)
168 {
169  ABTI_UB_ASSERT(!ABTD_ythread_context_is_started(p_new));
171  ABTD_ythread_context_switch(p_old, p_new);
172 }
173 
174 ABTU_noreturn static inline void
175 ABTD_ythread_context_jump(ABTD_ythread_context *p_new)
176 {
177  ABTI_UB_ASSERT(ABTD_ythread_context_is_started(p_new));
178  int ret = setcontext(&p_new->uctx);
179  ABTI_ASSERT(ret == 0); /* setcontext() should not return an error. */
181 }
182 
183 ABTU_noreturn static inline void
184 ABTD_ythread_context_start_and_jump(ABTD_ythread_context *p_new)
185 {
186  ABTI_UB_ASSERT(!ABTD_ythread_context_is_started(p_new));
188  ABTD_ythread_context_jump(p_new);
190 }
191 
192 static inline void
193 ABTD_ythread_context_switch_with_call(ABTD_ythread_context *p_old,
194  ABTD_ythread_context *p_new,
195  void (*f_cb)(void *), void *cb_arg)
196 {
197  ABTI_UB_ASSERT(ABTD_ythread_context_is_started(p_new));
198  p_old->is_peeked = ABT_FALSE;
199  p_old->p_ctx = &p_old->uctx;
200  p_new->f_cb = f_cb;
201  p_new->cb_arg = cb_arg;
202  int ret = swapcontext(&p_old->uctx, &p_new->uctx);
203  /* Fatal. This out-of-stack error is not recoverable. */
204  ABTI_ASSERT(ret == 0);
205  if (p_old->f_cb) {
206  p_old->f_cb(p_old->cb_arg);
207  p_old->f_cb = NULL;
208  }
210 }
211 
212 static inline void ABTD_ythread_context_start_and_switch_with_call(
213  ABTD_ythread_context *p_old, ABTD_ythread_context *p_new,
214  void (*f_cb)(void *), void *cb_arg)
215 {
216  ABTI_UB_ASSERT(!ABTD_ythread_context_is_started(p_new));
218  ABTD_ythread_context_switch_with_call(p_old, p_new, f_cb, cb_arg);
219 }
220 
221 ABTU_noreturn static inline void
222 ABTD_ythread_context_jump_with_call(ABTD_ythread_context *p_new,
223  void (*f_cb)(void *), void *cb_arg)
224 {
225  ABTI_UB_ASSERT(ABTD_ythread_context_is_started(p_new));
226  p_new->f_cb = f_cb;
227  p_new->cb_arg = cb_arg;
228  int ret = setcontext(&p_new->uctx);
229  ABTI_ASSERT(ret == 0); /* setcontext() should not return an error. */
231 }
232 
233 ABTU_noreturn static inline void ABTD_ythread_context_start_and_jump_with_call(
234  ABTD_ythread_context *p_new, void (*f_cb)(void *), void *cb_arg)
235 {
236  ABTI_UB_ASSERT(!ABTD_ythread_context_is_started(p_new));
238  ABTD_ythread_context_jump_with_call(p_new, f_cb, cb_arg);
240 }
241 
242 static inline ABT_bool ABTD_ythread_context_peek(ABTD_ythread_context *p_ctx,
243  void (*peek_func)(void *),
244  void *arg)
245 {
246  if (p_ctx->p_ctx) {
247  ucontext_t self_uctx;
248  p_ctx->peek_arg = arg;
249  p_ctx->peek_func = peek_func;
250  p_ctx->p_peek_uctx = &self_uctx;
251  p_ctx->is_peeked = ABT_TRUE;
252  int ret = swapcontext(&self_uctx, &p_ctx->uctx);
253  if (p_ctx->f_cb) {
254  p_ctx->f_cb(p_ctx->cb_arg);
255  p_ctx->f_cb = NULL;
256  }
257  ABTI_ASSERT(ret == 0);
258  return ABT_TRUE;
259  } else {
260  return ABT_FALSE;
261  }
262 }
263 
264 #endif /* ABTD_UCONTEXT_H_INCLUDED */
ABT_bool
int ABT_bool
Boolean type.
Definition: abt.h:1043
ABTU_noreturn
#define ABTU_noreturn
Definition: abtu.h:127
ABTU_unreachable
#define ABTU_unreachable()
Definition: abtu.h:133
ABTDI_ythread_context_make
static void ABTDI_ythread_context_make(ABTD_ythread_context *p_ctx)
Definition: abtd_ucontext.h:119
ABTU_unlikely
#define ABTU_unlikely(cond)
Definition: abtu.h:120
ABT_TRUE
#define ABT_TRUE
True constant for ABT_bool.
Definition: abt.h:784
ABT_FALSE
#define ABT_FALSE
False constant for ABT_bool.
Definition: abt.h:786
ABTDI_ucontext_check_peeked
static void ABTDI_ucontext_check_peeked(ABTD_ythread_context *p_self)
Definition: abtd_ucontext.h:26