ARGOBOTS  66b1c39742507d8df30e8d28c54839b961a14814
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
abtd_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 static inline void ythread_terminate(ABTI_xstream *p_local_xstream,
9  ABTI_ythread *p_ythread);
10 
11 void ABTD_ythread_func_wrapper(void *p_arg)
12 {
13  ABTD_ythread_context *p_ctx = (ABTD_ythread_context *)p_arg;
14  ABTI_ythread *p_ythread = ABTI_ythread_context_get_ythread(p_ctx);
15  ABTI_xstream *p_local_xstream = p_ythread->thread.p_last_xstream;
16  ABTI_tool_event_thread_run(p_local_xstream, &p_ythread->thread,
17  p_local_xstream->p_thread,
18  p_ythread->thread.p_parent);
19  p_local_xstream->p_thread = &p_ythread->thread;
20 
21  p_ythread->thread.f_thread(p_ythread->thread.p_arg);
22 
23  /* This ABTI_local_get_xstream() is controversial since it is called after
24  * the context-switchable function (i.e., thread_func()). We assume that
25  * the compiler does not load TLS offset etc before thread_func(). */
26  p_local_xstream = ABTI_local_get_xstream(ABTI_local_get_local());
27  ythread_terminate(p_local_xstream, p_ythread);
28 }
29 
30 void ABTD_ythread_exit(ABTI_xstream *p_local_xstream, ABTI_ythread *p_ythread)
31 {
32  ythread_terminate(p_local_xstream, p_ythread);
33 }
34 
35 static inline void ythread_terminate(ABTI_xstream *p_local_xstream,
36  ABTI_ythread *p_ythread)
37 {
38  ABTD_ythread_context *p_ctx = &p_ythread->ctx;
39  ABTD_ythread_context *p_link =
40  ABTD_atomic_acquire_load_ythread_context_ptr(&p_ctx->p_link);
41  if (p_link) {
42  /* If p_link is set, it means that other ULT has called the join. */
43  ABTI_ythread *p_joiner = ABTI_ythread_context_get_ythread(p_link);
44  if (p_ythread->thread.p_last_xstream ==
45  p_joiner->thread.p_last_xstream &&
46  !(p_ythread->thread.type & ABTI_THREAD_TYPE_MAIN_SCHED)) {
47  /* Only when the current ULT is on the same ES as p_joiner's,
48  * we can jump to the joiner ULT. */
49  ABTD_atomic_release_store_int(&p_ythread->thread.state,
51  LOG_DEBUG("[U%" PRIu64 ":E%d] terminated\n",
52  ABTI_thread_get_id(&p_ythread->thread),
53  p_ythread->thread.p_last_xstream->rank);
54 
55  /* Note that a parent ULT cannot be a joiner. */
56  ABTI_tool_event_ythread_resume(ABTI_xstream_get_local(
57  p_local_xstream),
58  p_joiner, &p_ythread->thread);
59  ABTI_ythread_finish_context_to_sibling(p_local_xstream, p_ythread,
60  p_joiner);
61  return;
62  } else {
63  /* If the current ULT's associated ES is different from p_joiner's,
64  * we can't directly jump to p_joiner. Instead, we wake up
65  * p_joiner here so that p_joiner's scheduler can resume it.
66  * Note that the main scheduler needs to jump back to the root
67  * scheduler, so the main scheduler needs to take this path. */
68  ABTI_ythread_set_ready(ABTI_xstream_get_local(p_local_xstream),
69  p_joiner);
70 
71  /* We don't need to use the atomic OR operation here because the ULT
72  * will be terminated regardless of other requests. */
73  ABTD_atomic_release_store_uint32(&p_ythread->thread.request,
74  ABTI_THREAD_REQ_TERMINATE);
75  }
76  } else {
77  uint32_t req =
78  ABTD_atomic_fetch_or_uint32(&p_ythread->thread.request,
79  ABTI_THREAD_REQ_JOIN |
80  ABTI_THREAD_REQ_TERMINATE);
81  if (req & ABTI_THREAD_REQ_JOIN) {
82  /* This case means there has been a join request and the joiner has
83  * blocked. We have to wake up the joiner ULT. */
84  do {
85  p_link = ABTD_atomic_acquire_load_ythread_context_ptr(
86  &p_ctx->p_link);
87  } while (!p_link);
88  ABTI_ythread_set_ready(ABTI_xstream_get_local(p_local_xstream),
89  ABTI_ythread_context_get_ythread(p_link));
90  }
91  }
92 
93  /* No other ULT is waiting or blocked for this ULT. Since a context does not
94  * switch to another context when it finishes, we need to explicitly switch
95  * to the parent. */
96  ABTI_ythread_finish_context_to_parent(p_local_xstream, p_ythread);
97 }
98 
99 #if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION
100 void ABTD_ythread_terminate_no_arg()
101 {
102  ABTI_local *p_local = ABTI_local_get_local();
103  ABTI_xstream *p_local_xstream = ABTI_local_get_xstream(p_local);
104  /* This function is called by `return` in
105  * ABTD_ythread_context_make_and_call, so it cannot take the argument. We
106  * get the thread descriptor from TLS. */
107  ABTI_thread *p_thread = p_local_xstream->p_thread;
108  ABTI_ASSERT(p_thread->type & ABTI_THREAD_TYPE_YIELDABLE);
109  ythread_terminate(p_local_xstream, ABTI_thread_get_ythread(p_thread));
110 }
111 #endif
112 
113 void ABTD_ythread_cancel(ABTI_xstream *p_local_xstream, ABTI_ythread *p_ythread)
114 {
115  /* When we cancel a ULT, if other ULT is blocked to join the canceled ULT,
116  * we have to wake up the joiner ULT. However, unlike the case when the
117  * ULT has finished its execution and calls ythread_terminate/exit,
118  * this function is called by the scheduler. Therefore, we should not
119  * context switch to the joiner ULT and need to always wake it up. */
120  ABTD_ythread_context *p_ctx = &p_ythread->ctx;
121 
122  if (ABTD_atomic_acquire_load_ythread_context_ptr(&p_ctx->p_link)) {
123  /* If p_link is set, it means that other ULT has called the join. */
124  ABTI_ythread *p_joiner = ABTI_ythread_context_get_ythread(
125  ABTD_atomic_relaxed_load_ythread_context_ptr(&p_ctx->p_link));
126  ABTI_ythread_set_ready(ABTI_xstream_get_local(p_local_xstream),
127  p_joiner);
128  } else {
129  uint32_t req =
130  ABTD_atomic_fetch_or_uint32(&p_ythread->thread.request,
131  ABTI_THREAD_REQ_JOIN |
132  ABTI_THREAD_REQ_TERMINATE);
133  if (req & ABTI_THREAD_REQ_JOIN) {
134  /* This case means there has been a join request and the joiner has
135  * blocked. We have to wake up the joiner ULT. */
136  while (ABTD_atomic_acquire_load_ythread_context_ptr(
137  &p_ctx->p_link) == NULL)
138  ;
139  ABTI_ythread *p_joiner = ABTI_ythread_context_get_ythread(
140  ABTD_atomic_relaxed_load_ythread_context_ptr(&p_ctx->p_link));
141  ABTI_ythread_set_ready(ABTI_xstream_get_local(p_local_xstream),
142  p_joiner);
143  }
144  }
145  ABTI_tool_event_thread_cancel(p_local_xstream, &p_ythread->thread);
146 }
147 
148 void ABTD_ythread_print_context(ABTI_ythread *p_ythread, FILE *p_os, int indent)
149 {
150  ABTD_ythread_context *p_ctx = &p_ythread->ctx;
151  fprintf(p_os, "%*sp_ctx : %p\n", indent, "", p_ctx->p_ctx);
152  fprintf(p_os, "%*sp_link : %p\n", indent, "",
153  (void *)ABTD_atomic_acquire_load_ythread_context_ptr(
154  &p_ctx->p_link));
155  fflush(p_os);
156 }
static void ythread_terminate(ABTI_xstream *p_local_xstream, ABTI_ythread *p_ythread)
Definition: abtd_ythread.c:35
#define LOG_DEBUG(fmt,...)
Definition: abti_log.h:26