ARGOBOTS  4dc37e16e1b227a480715ab67dae1dcfb4d2d4e0
ythread.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 
8 #ifdef ABT_CONFIG_ENABLE_STACK_UNWIND
9 #define UNW_LOCAL_ONLY
10 #include <libunwind.h>
11 struct unwind_stack_t {
12  FILE *fp;
13 };
14 static void ythread_unwind_stack(void *arg);
15 #endif
16 
17 /*****************************************************************************/
18 /* Private APIs */
19 /*****************************************************************************/
20 
21 static inline void ythread_callback_yield_impl(void *arg,
22  ABT_pool_context context)
23 {
24  ABTI_ythread *p_prev = (ABTI_ythread *)arg;
27  /* p_prev is terminated. */
28  } else {
29  /* Push p_prev back to the pool. */
30  ABTI_pool_add_thread(&p_prev->thread, context);
31  }
32 }
33 
35 {
37 }
38 
40 {
42 }
43 
45 {
47 }
48 
50 {
52 }
53 
55 {
57 }
58 
59 /* Before yield_to, p_prev->thread.p_pool's num_blocked must be incremented to
60  * avoid making a pool empty. */
62 {
63  ABTI_ythread *p_prev = (ABTI_ythread *)arg;
64  /* p_prev->thread.p_pool is loaded before ABTI_pool_add_thread() to keep
65  * num_blocked consistent. Otherwise, other threads might pop p_prev
66  * that has been pushed by ABTI_pool_add_thread() and change
67  * p_prev->thread.p_pool by ABT_unit_set_associated_pool(). */
68  ABTI_pool *p_pool = p_prev->thread.p_pool;
71  /* p_prev is terminated. */
72  } else {
73  /* Push p_prev back to the pool. */
76  }
77  /* Decrease the number of blocked threads of the original pool (i.e., before
78  * migration), which has been increased by p_prev to avoid making a pool
79  * size 0. */
81 }
82 
84 {
87  /* p_arg might point to the stack of the original ULT, so do not
88  * access it after that ULT becomes resumable. */
89  ABTI_ythread *p_prev = p_arg->p_prev;
90  ABTI_ythread *p_next = p_arg->p_next;
93  /* p_prev is terminated. */
94  } else {
95  /* Push this thread back to the pool. */
98  }
99  /* Decrease the number of blocked threads of p_next's pool. */
101 }
102 
104 {
105  ABTI_ythread *p_prev = (ABTI_ythread *)arg;
106  /* Increase the number of blocked threads of the original pool (i.e., before
107  * migration) */
109  /* Request handling. p_prev->thread.p_pool might be changed. */
111  /* Set this thread's state to BLOCKED. */
114 }
115 
117 {
120  /* p_arg might point to the stack of the original ULT, so do not
121  * access it after that ULT becomes resumable. */
122  ABTI_ythread *p_prev = p_arg->p_prev;
123  ABTI_ythread *p_next = p_arg->p_next;
124  ABTI_pool *p_prev_pool = p_prev->thread.p_pool;
125  ABTI_pool *p_next_pool = p_next->thread.p_pool;
126  if (p_prev_pool != p_next_pool) {
127  /* Increase the number of blocked threads of p_prev's pool */
128  ABTI_pool_inc_num_blocked(p_prev_pool);
129  /* Decrease the number of blocked threads of p_next's pool */
130  ABTI_pool_dec_num_blocked(p_next_pool);
131  }
132  /* Request handling. p_prev->thread.p_pool might be changed. */
134  /* Set this thread's state to BLOCKED. */
137 }
138 
140 {
141  /* Terminate this thread. */
142  ABTI_ythread *p_prev = (ABTI_ythread *)arg;
144  p_prev->thread.p_last_xstream, &p_prev->thread);
145 }
146 
148 {
151  /* p_arg might point to the stack of the original ULT, so do not
152  * access it after that ULT becomes resumable. */
153  ABTI_ythread *p_prev = p_arg->p_prev;
154  ABTI_ythread *p_next = p_arg->p_next;
155  /* Terminate this thread. */
157  p_prev->thread.p_last_xstream, &p_prev->thread);
158  /* Decrease the number of blocked threads. */
160 }
161 
163 {
166  /* p_arg might point to the stack of the original ULT, so do not
167  * access it after that ULT becomes resumable. */
168  ABTI_ythread *p_prev = p_arg->p_prev;
169  ABTD_spinlock *p_lock = p_arg->p_lock;
170  /* Increase the number of blocked threads */
172  /* Request handling. p_prev->thread.p_pool might be changed. */
174  /* Set this thread's state to BLOCKED. */
177  /* Release the lock. */
178  ABTD_spinlock_release(p_lock);
179 }
180 
182 {
185  /* p_arg might point to the stack of the original ULT, so do not
186  * access it after that ULT becomes resumable. */
187  ABTI_ythread *p_prev = p_arg->p_prev;
188  ABTI_ythread *p_target = p_arg->p_target;
189  /* Increase the number of blocked threads */
191  /* Request handling. p_prev->thread.p_pool might be changed. */
193  /* Set this thread's state to BLOCKED. */
196  /* Set the link in the context of the target ULT. This p_link might be
197  * read by p_target running on another ES in parallel, so release-store
198  * is needed here. */
200  &p_prev->ctx);
201 }
202 
204 {
207  /* p_arg might point to the stack of the original ULT, so do not
208  * access it after that ULT becomes resumable. */
209  ABTI_ythread *p_prev = p_arg->p_prev;
210  ABTI_sched *p_main_sched = p_arg->p_main_sched;
211  /* Increase the number of blocked threads */
213  /* Request handling. p_prev->thread.p_pool might be changed. */
215  /* Set this thread's state to BLOCKED. */
218  /* Ask the current main scheduler to replace its scheduler */
220 }
221 
223 {
224  /* It's a special operation, so request handling is unnecessary. */
225  ABTI_ythread *p_prev = (ABTI_ythread *)arg;
227  &p_prev->thread);
228 }
229 
231  ABTI_ythread *p_ythread,
232  FILE *p_os)
233 {
234  ABTD_ythread_print_context(p_ythread, p_os, 0);
235  fprintf(p_os,
236  "stacktop : %p\n"
237  "stacksize : %" PRIu64 "\n",
239  (uint64_t)ABTD_ythread_context_get_stacksize(&p_ythread->ctx));
240 
241 #ifdef ABT_CONFIG_ENABLE_STACK_UNWIND
242  {
243  /* Peeking a running context is specially forbidden. Though it is
244  * incomplete, let's quickly check if a thread is running. */
246  &p_ythread->thread.state);
247  if (state == ABT_THREAD_STATE_READY ||
248  state == ABT_THREAD_STATE_BLOCKED) {
249  struct unwind_stack_t arg;
250  arg.fp = p_os;
251  ABT_bool succeeded =
252  ABTI_ythread_context_peek(p_ythread, ythread_unwind_stack,
253  &arg);
254  if (!succeeded) {
255  fprintf(p_os, "not executed yet.\n");
256  }
257  } else {
258  fprintf(p_os, "failed to unwind a stack.\n");
259  }
260  }
261 #endif
262 
263  void *p_stacktop = ABTD_ythread_context_get_stacktop(&p_ythread->ctx);
264  size_t i, j,
265  stacksize = ABTD_ythread_context_get_stacksize(&p_ythread->ctx);
266  if (stacksize == 0 || p_stacktop == NULL) {
267  /* Some threads do not have p_stack (e.g., the main thread) */
268  fprintf(p_os, "no stack\n");
269  fflush(0);
270  return;
271  }
272  if (p_global->print_raw_stack) {
273  void *p_stack = (void *)(((char *)p_stacktop) - stacksize);
274  char buffer[32];
275  const size_t value_width = 8;
276  const int num_bytes = sizeof(buffer);
277 
278  for (i = 0; i < stacksize; i += num_bytes) {
279  if (stacksize >= i + num_bytes) {
280  memcpy(buffer, &((uint8_t *)p_stack)[i], num_bytes);
281  } else {
282  memset(buffer, 0, num_bytes);
283  memcpy(buffer, &((uint8_t *)p_stack)[i], stacksize - i);
284  }
285  /* Print the stack address */
286 #if SIZEOF_VOID_P == 8
287  fprintf(p_os, "%016" PRIxPTR ":",
288  (uintptr_t)(&((uint8_t *)p_stack)[i]));
289 #elif SIZEOF_VOID_P == 4
290  fprintf(p_os, "%08" PRIxPTR ":",
291  (uintptr_t)(&((uint8_t *)p_stack)[i]));
292 #else
293 #error "unknown pointer size"
294 #endif
295  /* Print the raw stack data */
296  for (j = 0; j < num_bytes / value_width; j++) {
297  if (value_width == 8) {
298  uint64_t val = ((uint64_t *)buffer)[j];
299  fprintf(p_os, " %016" PRIx64, val);
300  } else if (value_width == 4) {
301  uint32_t val = ((uint32_t *)buffer)[j];
302  fprintf(p_os, " %08" PRIx32, val);
303  } else if (value_width == 2) {
304  uint16_t val = ((uint16_t *)buffer)[j];
305  fprintf(p_os, " %04" PRIx16, val);
306  } else {
307  uint8_t val = ((uint8_t *)buffer)[j];
308  fprintf(p_os, " %02" PRIx8, val);
309  }
310  if (j == (num_bytes / value_width) - 1)
311  fprintf(p_os, "\n");
312  }
313  }
314  }
315  fflush(p_os);
316 }
317 
318 /*****************************************************************************/
319 /* Internal static functions */
320 /*****************************************************************************/
321 
322 #ifdef ABT_CONFIG_ENABLE_STACK_UNWIND
323 ABTU_no_sanitize_address static int ythread_unwind_stack_impl(FILE *fp)
324 {
325  unw_cursor_t cursor;
326  unw_context_t uc;
327  unw_word_t ip, sp;
328  int ret, level = -1;
329 
330  ret = unw_getcontext(&uc);
331  if (ret != 0)
332  return ABT_ERR_OTHER;
333 
334  ret = unw_init_local(&cursor, &uc);
335  if (ret != 0)
336  return ABT_ERR_OTHER;
337 
338  while (unw_step(&cursor) > 0 && level < 50) {
339  level++;
340 
341  ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);
342  if (ret != 0)
343  return ABT_ERR_OTHER;
344 
345  ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
346  if (ret != 0)
347  return ABT_ERR_OTHER;
348 
349  char proc_name[256];
350  unw_word_t offset;
351  ret = unw_get_proc_name(&cursor, proc_name, 256, &offset);
352  if (ret != 0)
353  return ABT_ERR_OTHER;
354 
355  /* Print function stack. */
356  fprintf(fp, "#%d %p in %s () <+%d> (%s = %p)\n", level,
357  (void *)((uintptr_t)ip), proc_name, (int)offset,
358  unw_regname(UNW_REG_SP), (void *)((uintptr_t)sp));
359  }
360  return ABT_SUCCESS;
361 }
362 
363 static void ythread_unwind_stack(void *arg)
364 {
365  struct unwind_stack_t *p_arg = (struct unwind_stack_t *)arg;
366  if (ythread_unwind_stack_impl(p_arg->fp) != ABT_SUCCESS) {
367  fprintf(p_arg->fp, "libunwind error\n");
368  }
369 }
370 
371 #endif /* ABT_CONFIG_ENABLE_STACK_UNWIND */
ABTI_ythread_callback_suspend_join
void ABTI_ythread_callback_suspend_join(void *arg)
Definition: ythread.c:181
ABTI_ythread_callback_suspend_unlock
void ABTI_ythread_callback_suspend_unlock(void *arg)
Definition: ythread.c:162
ABTI_ythread_callback_suspend_join_arg
Definition: abti_ythread.h:595
ABT_bool
int ABT_bool
Boolean type.
Definition: abt.h:1043
ABTD_atomic_release_store_ythread_context_ptr
static void ABTD_atomic_release_store_ythread_context_ptr(ABTD_ythread_context_atomic_ptr *ptr, ABTD_ythread_context *p_ctx)
Definition: abtd_context.h:44
ABT_POOL_CONTEXT_OP_THREAD_CREATE_TO
#define ABT_POOL_CONTEXT_OP_THREAD_CREATE_TO
A flag that hints a push operation in a thread creation routine with a yield operation.
Definition: abt.h:1686
ABTI_global::print_raw_stack
ABT_bool print_raw_stack
Definition: abti.h:235
ABT_pool_context
uint64_t ABT_pool_context
A pool context value.
Definition: abt.h:1566
ABTD_ythread_context_get_stacktop
static void * ABTD_ythread_context_get_stacktop(ABTD_ythread_context *p_ctx)
Definition: abtd_fcontext.h:118
ABT_THREAD_STATE_READY
@ ABT_THREAD_STATE_READY
Definition: abt.h:427
ABTI_ythread_callback_suspend_unlock_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:575
ABTI_global_get_global
static ABTI_global * ABTI_global_get_global(void)
Definition: abti_global.h:9
ABTI_ythread_callback_suspend
void ABTI_ythread_callback_suspend(void *arg)
Definition: ythread.c:103
ABTI_ythread_callback_yield_user_yield
void ABTI_ythread_callback_yield_user_yield(void *arg)
Definition: ythread.c:34
ABTI_ythread_print_stack
ABTU_no_sanitize_address void ABTI_ythread_print_stack(ABTI_global *p_global, ABTI_ythread *p_ythread, FILE *p_os)
Definition: ythread.c:230
ABTI_ythread_callback_suspend_join_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:596
ABTI_ythread_callback_resume_exit_to
void ABTI_ythread_callback_resume_exit_to(void *arg)
Definition: ythread.c:147
ABTD_ythread_context::p_link
ABTD_ythread_context_atomic_ptr p_link
Definition: abtd_fcontext.h:61
ABTD_spinlock
Definition: abtd_spinlock.h:9
ABTI_ythread_callback_resume_yield_to
void ABTI_ythread_callback_resume_yield_to(void *arg)
Definition: ythread.c:83
ABT_thread_state
ABT_thread_state
State of a work unit.
Definition: abt.h:425
ABTI_ythread_callback_suspend_unlock_arg
Definition: abti_ythread.h:574
ABTI_ythread_callback_suspend_replace_sched_arg::p_main_sched
ABTI_sched * p_main_sched
Definition: abti_ythread.h:618
ABTI_pool
Definition: abti.h:389
ABTI_ythread_callback_resume_exit_to_arg::p_next
ABTI_ythread * p_next
Definition: abti_ythread.h:546
ABTI_ythread_callback_resume_suspend_to_arg
Definition: abti_ythread.h:380
ABT_THREAD_STATE_BLOCKED
@ ABT_THREAD_STATE_BLOCKED
Definition: abt.h:431
abti.h
ABTI_ythread_callback_suspend_replace_sched
void ABTI_ythread_callback_suspend_replace_sched(void *arg)
Definition: ythread.c:203
ABTI_ythread_callback_resume_yield_to_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:318
ABTI_SCHED_REQ_REPLACE
#define ABTI_SCHED_REQ_REPLACE
Definition: abti.h:46
ABTI_ythread_context_peek
static ABT_bool ABTI_ythread_context_peek(ABTI_ythread *p_ythread, void(*f_peek)(void *), void *arg)
Definition: abti_ythread.h:221
ABTI_ythread_callback_resume_exit_to_arg
Definition: abti_ythread.h:544
ABTI_thread::state
ABTD_atomic_int state
Definition: abti.h:432
ABT_POOL_CONTEXT_OP_THREAD_REVIVE_TO
#define ABT_POOL_CONTEXT_OP_THREAD_REVIVE_TO
A flag that hints a push operation in a thread revival routine with a yield operation.
Definition: abt.h:1711
ABTI_THREAD_HANDLE_REQUEST_CANCELLED
#define ABTI_THREAD_HANDLE_REQUEST_CANCELLED
Definition: abti_thread.h:80
ABTI_ythread_callback_suspend_unlock_arg::p_lock
ABTD_spinlock * p_lock
Definition: abti_ythread.h:576
ABTI_ythread_callback_yield_loop
void ABTI_ythread_callback_yield_loop(void *arg)
Definition: ythread.c:39
ABT_POOL_CONTEXT_OP_THREAD_YIELD_TO
#define ABT_POOL_CONTEXT_OP_THREAD_YIELD_TO
A flag that hints a push operation in a thread yield-to routine.
Definition: abt.h:1733
ABTI_ythread_callback_suspend_replace_sched_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:617
ABTI_ythread::ctx
ABTD_ythread_context ctx
Definition: abti.h:458
ABTI_sched_set_request
static void ABTI_sched_set_request(ABTI_sched *p_sched, uint32_t req)
Definition: abti_sched.h:60
ABTI_ythread_callback_resume_yield_to_arg::p_next
ABTI_ythread * p_next
Definition: abti_ythread.h:319
ABTI_ythread_callback_suspend_join_arg::p_target
ABTI_ythread * p_target
Definition: abti_ythread.h:597
ABTI_ythread_callback_yield_revive_to
void ABTI_ythread_callback_yield_revive_to(void *arg)
Definition: ythread.c:54
ABT_SUCCESS
#define ABT_SUCCESS
Error code: the routine returns successfully.
Definition: abt.h:92
ABTD_atomic_acquire_load_int
static int ABTD_atomic_acquire_load_int(const ABTD_atomic_int *ptr)
Definition: abtd_atomic.h:878
ythread_callback_yield_impl
static void ythread_callback_yield_impl(void *arg, ABT_pool_context context)
Definition: ythread.c:21
ABT_TRUE
#define ABT_TRUE
True constant for ABT_bool.
Definition: abt.h:784
ABTI_pool_add_thread
static void ABTI_pool_add_thread(ABTI_thread *p_thread, ABT_pool_context context)
Definition: abti_pool.h:61
ABTI_ythread_callback_thread_yield_to
void ABTI_ythread_callback_thread_yield_to(void *arg)
Definition: ythread.c:61
ABTI_ythread_callback_resume_exit_to_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:545
ABTI_sched
Definition: abti.h:319
ABT_FALSE
#define ABT_FALSE
False constant for ABT_bool.
Definition: abt.h:786
ABTI_ythread
Definition: abti.h:456
ABTI_ythread_callback_yield_user_yield_to
void ABTI_ythread_callback_yield_user_yield_to(void *arg)
Definition: ythread.c:44
ABTI_ythread_callback_resume_suspend_to_arg::p_next
ABTI_ythread * p_next
Definition: abti_ythread.h:382
ABTD_spinlock_release
static void ABTD_spinlock_release(ABTD_spinlock *p_lock)
Definition: abtd_spinlock.h:42
ABTI_ythread_callback_resume_yield_to_arg
Definition: abti_ythread.h:317
ABTI_thread::p_last_xstream
ABTI_xstream * p_last_xstream
Definition: abti.h:428
ABTI_ythread_callback_exit
void ABTI_ythread_callback_exit(void *arg)
Definition: ythread.c:139
ABTU_no_sanitize_address
#define ABTU_no_sanitize_address
Definition: abtu.h:211
ABT_ERR_OTHER
#define ABT_ERR_OTHER
Error code: other error.
Definition: abt.h:109
ABTI_ythread::thread
ABTI_thread thread
Definition: abti.h:457
ABTI_pool_inc_num_blocked
static void ABTI_pool_inc_num_blocked(ABTI_pool *p_pool)
Definition: abti_pool.h:42
ABTI_thread_unset_associated_pool
static void ABTI_thread_unset_associated_pool(ABTI_global *p_global, ABTI_thread *p_thread)
Definition: abti_unit.h:214
ABTI_ythread_callback_resume_suspend_to
void ABTI_ythread_callback_resume_suspend_to(void *arg)
Definition: ythread.c:116
ABTI_ythread_callback_suspend_replace_sched_arg
Definition: abti_ythread.h:616
ABTI_ythread_callback_orphan
void ABTI_ythread_callback_orphan(void *arg)
Definition: ythread.c:222
ABTI_thread_handle_request
static int ABTI_thread_handle_request(ABTI_thread *p_thread, ABT_bool allow_termination)
Definition: abti_thread.h:83
ABTI_global
Definition: abti.h:223
ABTI_ythread_callback_resume_suspend_to_arg::p_prev
ABTI_ythread * p_prev
Definition: abti_ythread.h:381
ABTI_ythread_callback_yield_create_to
void ABTI_ythread_callback_yield_create_to(void *arg)
Definition: ythread.c:49
ABT_POOL_CONTEXT_OP_THREAD_YIELD_LOOP
#define ABT_POOL_CONTEXT_OP_THREAD_YIELD_LOOP
A flag that hints a push operation in a yield operation in a synchronization loop.
Definition: abt.h:1757
ABT_POOL_CONTEXT_OP_THREAD_YIELD
#define ABT_POOL_CONTEXT_OP_THREAD_YIELD
A flag that hints a push operation in a thread yield routine.
Definition: abt.h:1722
ABTI_thread::p_pool
ABTI_pool * p_pool
Definition: abti.h:434
ABTD_ythread_context_get_stacksize
static size_t ABTD_ythread_context_get_stacksize(ABTD_ythread_context *p_ctx)
Definition: abtd_fcontext.h:130
ABT_POOL_CONTEXT_OP_THREAD_RESUME_YIELD_TO
#define ABT_POOL_CONTEXT_OP_THREAD_RESUME_YIELD_TO
A flag that hints a push operation in a thread resume-yield-to routine.
Definition: abt.h:1745
ABTD_atomic_release_store_int
static void ABTD_atomic_release_store_int(ABTD_atomic_int *ptr, int val)
Definition: abtd_atomic.h:1065
ABTI_thread_terminate
static void ABTI_thread_terminate(ABTI_global *p_global, ABTI_xstream *p_local_xstream, ABTI_thread *p_thread)
Definition: abti_thread.h:130
ABTI_pool_dec_num_blocked
static void ABTI_pool_dec_num_blocked(ABTI_pool *p_pool)
Definition: abti_pool.h:48
ABTD_ythread_print_context
void ABTD_ythread_print_context(ABTI_ythread *p_ythread, FILE *p_os, int indent)
Definition: abtd_ythread.c:18