ARGOBOTS  23067fa015f4b179569e2d52278c1072e674eb1e
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
abtd_thread.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 ABTD_thread_terminate(ABTI_xstream *p_local_xstream,
9  ABTI_thread *p_thread);
10 
11 void ABTD_thread_func_wrapper(void *p_arg)
12 {
13  ABTD_thread_context *p_ctx = (ABTD_thread_context *)p_arg;
14  ABTI_thread *p_thread = ABTI_thread_context_get_thread(p_ctx);
15  ABTI_xstream *p_local_xstream = p_thread->unit_def.p_last_xstream;
16  ABTI_tool_event_thread_run(p_local_xstream, p_thread,
17  p_local_xstream->p_unit,
18  p_thread->unit_def.p_parent);
19  p_local_xstream->p_unit = &p_thread->unit_def;
20 
21  p_thread->unit_def.f_unit(p_thread->unit_def.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();
27  ABTD_thread_terminate(p_local_xstream, p_thread);
28 }
29 
30 void ABTD_thread_exit(ABTI_xstream *p_local_xstream, ABTI_thread *p_thread)
31 {
32  ABTD_thread_terminate(p_local_xstream, p_thread);
33 }
34 
35 static inline void ABTD_thread_terminate(ABTI_xstream *p_local_xstream,
36  ABTI_thread *p_thread)
37 {
38  ABTD_thread_context *p_ctx = &p_thread->ctx;
39  ABTD_thread_context *p_link =
40  ABTD_atomic_acquire_load_thread_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_thread *p_joiner = ABTI_thread_context_get_thread(p_link);
44  if (p_thread->unit_def.p_last_xstream ==
45  p_joiner->unit_def.p_last_xstream) {
46  /* Only when the current ULT is on the same ES as p_joiner's,
47  * we can jump to the joiner ULT. */
48  ABTD_atomic_release_store_int(&p_thread->unit_def.state,
49  ABTI_UNIT_STATE_TERMINATED);
50  LOG_DEBUG("[U%" PRIu64 ":E%d] terminated\n",
51  ABTI_thread_get_id(p_thread),
52  p_thread->unit_def.p_last_xstream->rank);
53 
54  /* Note that a parent ULT cannot be a joiner. */
55  ABTI_tool_event_thread_resume(p_local_xstream, p_joiner,
56  &p_thread->unit_def);
57  ABTI_thread_finish_context_to_sibling(p_local_xstream, p_thread,
58  p_joiner);
59  return;
60  } else {
61  /* If the current ULT's associated ES is different from p_joiner's,
62  * we can't directly jump to p_joiner. Instead, we wake up
63  * p_joiner here so that p_joiner's scheduler can resume it. */
64  ABTI_thread_set_ready(p_local_xstream, p_joiner);
65 
66  /* We don't need to use the atomic OR operation here because the ULT
67  * will be terminated regardless of other requests. */
68  ABTD_atomic_release_store_uint32(&p_thread->unit_def.request,
69  ABTI_UNIT_REQ_TERMINATE);
70  }
71  } else {
72  uint32_t req = ABTD_atomic_fetch_or_uint32(&p_thread->unit_def.request,
73  ABTI_UNIT_REQ_JOIN |
74  ABTI_UNIT_REQ_TERMINATE);
75  if (req & ABTI_UNIT_REQ_JOIN) {
76  /* This case means there has been a join request and the joiner has
77  * blocked. We have to wake up the joiner ULT. */
78  do {
79  p_link =
80  ABTD_atomic_acquire_load_thread_context_ptr(&p_ctx->p_link);
81  } while (!p_link);
82  ABTI_thread_set_ready(p_local_xstream,
83  ABTI_thread_context_get_thread(p_link));
84  }
85  }
86 
87  /* No other ULT is waiting or blocked for this ULT. Since a context does not
88  * switch to another context when it finishes, we need to explicitly switch
89  * to the parent. */
90  ABTI_thread_finish_context_to_parent(p_local_xstream, p_thread);
91 }
92 
93 #if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION
94 void ABTD_thread_terminate_no_arg()
95 {
96  ABTI_xstream *p_local_xstream = ABTI_local_get_xstream();
97  /* This function is called by `return` in ABTD_thread_context_make_and_call,
98  * so it cannot take the argument. We get the thread descriptor from TLS. */
99  ABTI_unit *p_unit = p_local_xstream->p_unit;
100  ABTI_ASSERT(ABTI_unit_type_is_thread(p_unit->type));
101  ABTD_thread_terminate(p_local_xstream, ABTI_unit_get_thread(p_unit));
102 }
103 #endif
104 
105 void ABTD_thread_cancel(ABTI_xstream *p_local_xstream, ABTI_thread *p_thread)
106 {
107  /* When we cancel a ULT, if other ULT is blocked to join the canceled ULT,
108  * we have to wake up the joiner ULT. However, unlike the case when the
109  * ULT has finished its execution and calls ABTD_thread_terminate/exit,
110  * this function is called by the scheduler. Therefore, we should not
111  * context switch to the joiner ULT and need to always wake it up. */
112  ABTD_thread_context *p_ctx = &p_thread->ctx;
113 
114  if (ABTD_atomic_acquire_load_thread_context_ptr(&p_ctx->p_link)) {
115  /* If p_link is set, it means that other ULT has called the join. */
116  ABTI_thread *p_joiner = ABTI_thread_context_get_thread(
117  ABTD_atomic_relaxed_load_thread_context_ptr(&p_ctx->p_link));
118  ABTI_thread_set_ready(p_local_xstream, p_joiner);
119  } else {
120  uint32_t req = ABTD_atomic_fetch_or_uint32(&p_thread->unit_def.request,
121  ABTI_UNIT_REQ_JOIN |
122  ABTI_UNIT_REQ_TERMINATE);
123  if (req & ABTI_UNIT_REQ_JOIN) {
124  /* This case means there has been a join request and the joiner has
125  * blocked. We have to wake up the joiner ULT. */
126  while (ABTD_atomic_acquire_load_thread_context_ptr(
127  &p_ctx->p_link) == NULL)
128  ;
129  ABTI_thread *p_joiner = ABTI_thread_context_get_thread(
130  ABTD_atomic_relaxed_load_thread_context_ptr(&p_ctx->p_link));
131  ABTI_thread_set_ready(p_local_xstream, p_joiner);
132  }
133  }
134  ABTI_tool_event_thread_cancel(p_local_xstream, p_thread);
135 }
136 
137 void ABTD_thread_print_context(ABTI_thread *p_thread, FILE *p_os, int indent)
138 {
139  char *prefix = ABTU_get_indent_str(indent);
140  ABTD_thread_context *p_ctx = &p_thread->ctx;
141  fprintf(p_os, "%sp_ctx : %p\n", prefix, p_ctx->p_ctx);
142  fprintf(p_os, "%sp_link : %p\n", prefix,
143  (void *)ABTD_atomic_acquire_load_thread_context_ptr(
144  &p_ctx->p_link));
145  fflush(p_os);
146  ABTU_free(prefix);
147 }
char * ABTU_get_indent_str(int indent)
Definition: util.c:12
#define LOG_DEBUG(fmt,...)
Definition: abti_log.h:30
static void ABTU_free(void *ptr)
Definition: abtu.h:111