Line data Source code
1 : #ifndef AWS_COMMON_THREAD_H
2 : #define AWS_COMMON_THREAD_H
3 :
4 : /**
5 : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 : * SPDX-License-Identifier: Apache-2.0.
7 : */
8 : #include <aws/common/common.h>
9 :
10 : #ifndef _WIN32
11 : # include <pthread.h>
12 : #endif
13 :
14 : enum aws_thread_detach_state {
15 : AWS_THREAD_NOT_CREATED = 1,
16 : AWS_THREAD_JOINABLE,
17 : AWS_THREAD_JOIN_COMPLETED,
18 : AWS_THREAD_MANAGED,
19 : };
20 :
21 : /**
22 : * Specifies the join strategy used on an aws_thread, which in turn controls whether or not a thread participates
23 : * in the managed thread system. The managed thread system provides logic to guarantee a join on all participating
24 : * threads at the cost of laziness (the user cannot control when joins happen).
25 : *
26 : * Manual - thread does not particpate in the managed thread system; any joins must be done by the user. This
27 : * is the default.
28 : *
29 : * Managed - the managed thread system will automatically perform a join some time after the thread's run function
30 : * has completed. It is an error to call aws_thread_join on a thread configured with the managed join strategy.
31 : *
32 : * Additionally, an API exists, aws_thread_join_all_managed(), which blocks and returns when all outstanding threads
33 : * with the managed strategy have fully joined. This API is useful for tests (rather than waiting for many individual
34 : * signals) and program shutdown or DLL unload. This API is automatically invoked by the common library clean up
35 : * function. If the common library clean up is called from a managed thread, this will cause deadlock.
36 : *
37 : * Lazy thread joining is done only when threads finish their run function or when the user calls
38 : * aws_thread_join_all_managed(). This means it may be a long time between thread function completion and the join
39 : * being applied, but the queue of unjoined threads is always one or fewer so there is no critical resource
40 : * backlog.
41 : *
42 : * Currently, only event loop group async cleanup and host resolver threads participate in the managed thread system.
43 : * Additionally, event loop threads will increment and decrement the pending join count (they are manually joined
44 : * internally) in order to have an accurate view of internal thread usage and also to prevent failure to release
45 : * an event loop group fully from allowing aws_thread_join_all_managed() from running to completion when its
46 : * intent is such that it should block instead.
47 : */
48 : enum aws_thread_join_strategy {
49 : AWS_TJS_MANUAL = 0,
50 : AWS_TJS_MANAGED,
51 : };
52 :
53 : struct aws_thread_options {
54 : size_t stack_size;
55 : /* default is -1. If you set this to anything >= 0, and the platform supports it, the thread will be pinned to
56 : * that cpu. Also, we assume you're doing this for memory throughput purposes. On unix systems,
57 : * If libnuma.so is available, upon the thread launching, the memory policy for that thread will be set to
58 : * allocate on the numa node that cpu-core is on.
59 : *
60 : * On windows, this will cause the thread affinity to be set, but currently we don't do anything to tell the OS
61 : * how to allocate memory on a node.
62 : *
63 : * On Apple and Android platforms, this setting doesn't do anything at all.
64 : */
65 : int32_t cpu_id;
66 :
67 : enum aws_thread_join_strategy join_strategy;
68 : };
69 :
70 : #ifdef _WIN32
71 : typedef union {
72 : void *ptr;
73 : } aws_thread_once;
74 : # define AWS_THREAD_ONCE_STATIC_INIT \
75 : { NULL }
76 : typedef unsigned long aws_thread_id_t;
77 : #else
78 : typedef pthread_once_t aws_thread_once;
79 : # define AWS_THREAD_ONCE_STATIC_INIT PTHREAD_ONCE_INIT
80 : typedef pthread_t aws_thread_id_t;
81 : #endif
82 :
83 : /*
84 : * Buffer size needed to represent aws_thread_id_t as a string (2 hex chars per byte
85 : * plus '\0' terminator). Needed for portable printing because pthread_t is
86 : * opaque.
87 : */
88 0 : #define AWS_THREAD_ID_T_REPR_BUFSZ (sizeof(aws_thread_id_t) * 2 + 1)
89 :
90 : struct aws_thread {
91 : struct aws_allocator *allocator;
92 : enum aws_thread_detach_state detach_state;
93 : #ifdef _WIN32
94 : void *thread_handle;
95 : #endif
96 : aws_thread_id_t thread_id;
97 : };
98 :
99 : AWS_EXTERN_C_BEGIN
100 :
101 : /**
102 : * Returns an instance of system default thread options.
103 : */
104 : AWS_COMMON_API
105 : const struct aws_thread_options *aws_default_thread_options(void);
106 :
107 : AWS_COMMON_API void aws_thread_call_once(aws_thread_once *flag, void (*call_once)(void *), void *user_data);
108 :
109 : /**
110 : * Initializes a new platform specific thread object struct (not the os-level
111 : * thread itself).
112 : */
113 : AWS_COMMON_API
114 : int aws_thread_init(struct aws_thread *thread, struct aws_allocator *allocator);
115 :
116 : /**
117 : * Creates an OS level thread and associates it with func. context will be passed to func when it is executed.
118 : * options will be applied to the thread if they are applicable for the platform.
119 : * You must either call join or detach after creating the thread and before calling clean_up.
120 : */
121 : AWS_COMMON_API
122 : int aws_thread_launch(
123 : struct aws_thread *thread,
124 : void (*func)(void *arg),
125 : void *arg,
126 : const struct aws_thread_options *options);
127 :
128 : /**
129 : * Gets the id of thread
130 : */
131 : AWS_COMMON_API
132 : aws_thread_id_t aws_thread_get_id(struct aws_thread *thread);
133 :
134 : /**
135 : * Gets the detach state of the thread. For example, is it safe to call join on
136 : * this thread? Has it been detached()?
137 : */
138 : AWS_COMMON_API
139 : enum aws_thread_detach_state aws_thread_get_detach_state(struct aws_thread *thread);
140 :
141 : /**
142 : * Joins the calling thread to a thread instance. Returns when thread is
143 : * finished.
144 : */
145 : AWS_COMMON_API
146 : int aws_thread_join(struct aws_thread *thread);
147 :
148 : /**
149 : * Blocking call that waits for all managed threads to complete their join call. This can only be called
150 : * from the main thread or a non-managed thread.
151 : *
152 : * This gets called automatically from library cleanup.
153 : *
154 : * By default the wait is unbounded, but that default can be overridden via aws_thread_set_managed_join_timeout_ns()
155 : */
156 : AWS_COMMON_API
157 : int aws_thread_join_all_managed(void);
158 :
159 : /**
160 : * Overrides how long, in nanoseconds, that aws_thread_join_all_managed will wait for threads to complete.
161 : * A value of zero will result in an unbounded wait.
162 : */
163 : AWS_COMMON_API
164 : void aws_thread_set_managed_join_timeout_ns(uint64_t timeout_in_ns);
165 :
166 : /**
167 : * Cleans up the thread handle. Either detach or join must be called
168 : * before calling this function.
169 : */
170 : AWS_COMMON_API
171 : void aws_thread_clean_up(struct aws_thread *thread);
172 :
173 : /**
174 : * Returns the thread id of the calling thread.
175 : */
176 : AWS_COMMON_API
177 : aws_thread_id_t aws_thread_current_thread_id(void);
178 :
179 : /**
180 : * Compare thread ids.
181 : */
182 : AWS_COMMON_API
183 : bool aws_thread_thread_id_equal(aws_thread_id_t t1, aws_thread_id_t t2);
184 :
185 : /**
186 : * Sleeps the current thread by nanos.
187 : */
188 : AWS_COMMON_API
189 : void aws_thread_current_sleep(uint64_t nanos);
190 :
191 : typedef void(aws_thread_atexit_fn)(void *user_data);
192 :
193 : /**
194 : * Adds a callback to the chain to be called when the current thread joins.
195 : * Callbacks are called from the current thread, in the reverse order they
196 : * were added, after the thread function returns.
197 : * If not called from within an aws_thread, has no effect.
198 : */
199 : AWS_COMMON_API
200 : int aws_thread_current_at_exit(aws_thread_atexit_fn *callback, void *user_data);
201 :
202 : /**
203 : * Increments the count of unjoined threads in the managed thread system. Used by managed threads and
204 : * event loop threads. Additional usage requires the user to join corresponding threads themselves and
205 : * correctly increment/decrement even in the face of launch/join errors.
206 : *
207 : * aws_thread_join_all_managed() will not return until this count has gone to zero.
208 : */
209 : AWS_COMMON_API void aws_thread_increment_unjoined_count(void);
210 :
211 : /**
212 : * Decrements the count of unjoined threads in the managed thread system. Used by managed threads and
213 : * event loop threads. Additional usage requires the user to join corresponding threads themselves and
214 : * correctly increment/decrement even in the face of launch/join errors.
215 : *
216 : * aws_thread_join_all_managed() will not return until this count has gone to zero.
217 : */
218 : AWS_COMMON_API void aws_thread_decrement_unjoined_count(void);
219 :
220 : AWS_EXTERN_C_END
221 :
222 : #endif /* AWS_COMMON_THREAD_H */
|