-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
ep-thread.h
349 lines (294 loc) · 10.6 KB
/
ep-thread.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#ifndef __EVENTPIPE_THREAD_H__
#define __EVENTPIPE_THREAD_H__
#include "ep-rt-config.h"
#ifdef ENABLE_PERFTRACING
#include "ep-types.h"
#undef EP_IMPL_GETTER_SETTER
#ifdef EP_IMPL_THREAD_GETTER_SETTER
#define EP_IMPL_GETTER_SETTER
#endif
#include "ep-getter-setter.h"
/*
* EventPipeThread.
*/
#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThread {
#else
struct _EventPipeThread_Internal {
#endif
// Per-session state.
// The pointers in this array are only read/written under rt_lock
// Some of the data within the ThreadSessionState object can be accessed
// without rt_lock however, see the fields of that type for details.
EventPipeThreadSessionState *session_state [EP_MAX_NUMBER_OF_SESSIONS];
#ifdef EP_THREAD_INCLUDE_ACTIVITY_ID
uint8_t activity_id [EP_ACTIVITY_ID_SIZE];
#endif
EventPipeSession *rundown_session;
// This lock is designed to have low contention. Normally it is only taken by this thread,
// but occasionally it may also be taken by another thread which is trying to collect and drain
// buffers from all threads.
ep_rt_spin_lock_handle_t rt_lock;
// This is initialized when the Thread object is first constructed and remains
// immutable afterwards.
uint64_t os_thread_id;
// The EventPipeThreadHolder maintains one count while the thread is alive
// and each session's EventPipeBufferList maintains one count while it
// exists.
int32_t ref_count;
// If this is set to a valid id before the corresponding entry of sessions is set to null,
// that pointer will be protected from deletion. See ep_disable () and
// ep_write () for more detail.
volatile uint32_t writing_event_in_progress;
// This is set to non-zero when the thread is unregistered from the global list of EventPipe threads.
// This should happen when a physical thread is ending.
// This is a convenience marker to prevent us from having to search the global list.
// defaults to false.
volatile uint32_t unregistered;
};
#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThread {
uint8_t _internal [sizeof (struct _EventPipeThread_Internal)];
};
#endif
#ifdef EP_THREAD_INCLUDE_ACTIVITY_ID
EP_DEFINE_GETTER_ARRAY_REF(EventPipeThread *, thread, uint8_t *, const uint8_t *, activity_id, activity_id[0]);
#else
static
inline
const uint8_t *
ep_thread_get_activity_id_cref (ep_rt_thread_activity_id_handle_t activity_id_handle)
{
return ep_rt_thread_get_activity_id_cref (activity_id_handle);
}
#endif
EP_DEFINE_GETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session);
EP_DEFINE_SETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session);
EP_DEFINE_GETTER_REF(EventPipeThread *, thread, ep_rt_spin_lock_handle_t *, rt_lock);
EP_DEFINE_GETTER(EventPipeThread *, thread, uint64_t, os_thread_id);
EP_DEFINE_GETTER_REF(EventPipeThread *, thread, int32_t *, ref_count);
EP_DEFINE_GETTER_REF(EventPipeThread *, thread, volatile uint32_t *, unregistered);
EventPipeThread *
ep_thread_alloc (void);
void
ep_thread_free (EventPipeThread *thread);
void
ep_thread_addref (EventPipeThread *thread);
void
ep_thread_release (EventPipeThread *thread);
void
ep_thread_init (void);
bool
ep_thread_register (EventPipeThread *thread);
bool
ep_thread_unregister (EventPipeThread *thread);
EventPipeThread *
ep_thread_get (void);
EventPipeThread *
ep_thread_get_or_create (void);
void
ep_thread_get_threads (dn_vector_ptr_t *threads);
static
inline
void
ep_thread_create_activity_id (
uint8_t *activity_id,
uint32_t activity_id_len)
{
ep_rt_create_activity_id (activity_id, activity_id_len);
}
static
inline
ep_rt_thread_activity_id_handle_t
ep_thread_get_activity_id_handle (void)
{
return ep_rt_thread_get_activity_id_handle ();
}
static
inline
void
ep_thread_get_activity_id (
ep_rt_thread_activity_id_handle_t activity_id_handle,
uint8_t *activity_id,
uint32_t activity_id_len)
{
ep_rt_thread_get_activity_id (activity_id_handle, activity_id, activity_id_len);
}
static
inline
void
ep_thread_set_activity_id (
ep_rt_thread_activity_id_handle_t activity_id_handle,
const uint8_t *activity_id,
uint32_t activity_id_len)
{
ep_rt_thread_set_activity_id (activity_id_handle, activity_id, activity_id_len);
}
static
inline
void
ep_thread_set_as_rundown_thread (
EventPipeThread *thread,
EventPipeSession *session)
{
EP_ASSERT (thread != NULL);
ep_thread_set_rundown_session (thread, session);
}
static
inline
bool
ep_thread_is_rundown_thread (const EventPipeThread *thread)
{
EP_ASSERT (thread != NULL);
return (ep_thread_get_rundown_session (thread) != NULL);
}
#ifdef EP_CHECKED_BUILD
void
ep_thread_requires_lock_held (const EventPipeThread *thread);
void
ep_thread_requires_lock_not_held (const EventPipeThread *thread);
#else
#define ep_thread_requires_lock_held(thread)
#define ep_thread_requires_lock_not_held(thread)
#endif
void
ep_thread_set_session_write_in_progress (
EventPipeThread *thread,
uint32_t session_index);
uint32_t
ep_thread_get_session_write_in_progress (const EventPipeThread *thread);
// _Requires_lock_held (thread)
EventPipeThreadSessionState *
ep_thread_get_or_create_session_state (
EventPipeThread *thread,
EventPipeSession *session);
// _Requires_lock_held (thread)
EventPipeThreadSessionState *
ep_thread_get_session_state (
const EventPipeThread *thread,
EventPipeSession *session);
// _Requires_lock_held (thread)
void
ep_thread_delete_session_state (
EventPipeThread *thread,
EventPipeSession *session);
/*
* EventPipeThreadHolder.
*/
#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThreadHolder {
#else
struct _EventPipeThreadHolder_Internal {
#endif
EventPipeThread *thread;
};
#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThreadHolder {
uint8_t _internal [sizeof (struct _EventPipeThreadHolder_Internal)];
};
#endif
EP_DEFINE_GETTER(EventPipeThreadHolder *, thread_holder, EventPipeThread *, thread)
EventPipeThreadHolder *
ep_thread_holder_alloc (EventPipeThread *thread);
EventPipeThreadHolder *
ep_thread_holder_init (
EventPipeThreadHolder *thread_holder,
EventPipeThread *thread);
void
ep_thread_holder_fini (EventPipeThreadHolder *thread_holder);
void
ep_thread_holder_free (EventPipeThreadHolder *thread_holder);
/*
* EventPipeThreadSessionState.
*/
#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThreadSessionState {
#else
struct _EventPipeThreadSessionState_Internal {
#endif
// immutable.
EventPipeThreadHolder thread_holder;
// immutable.
EventPipeSession *session;
// The buffer this thread is allowed to write to if non-null, it must
// match the tail of buffer_list
// protected by thread_holder->thread.rt_lock
EventPipeBuffer *write_buffer;
// The list of buffers that were written to by this thread. This
// is populated lazily the first time a thread tries to allocate
// a buffer for this session. It is set back to null when
// event writing is suspended during session disable.
// protected by the buffer manager lock.
// This field can be read outside the lock when
// the buffer allocation logic is estimating how many
// buffers a given thread has used (see: ep_thread_session_state_get_buffer_count_estimate and its uses).
EventPipeBufferList *buffer_list;
#ifdef EP_CHECKED_BUILD
// protected by the buffer manager lock.
EventPipeBufferManager *buffer_manager;
#endif
// The number of events that were attempted to be written by this
// thread. Each event was either successfully recorded in a buffer
// or it was dropped.
//
// Only updated by the current thread under thread_holder->thread.rt_lock. Other
// event writer threads are allowed to do unsynchronized reads when
// capturing a sequence point but this does not provide any consistency
// guarantee. In particular there is no promise that the other thread
// is observing the most recent sequence number, nor is there a promise
// that the observable number of events in the write buffer matches the
// sequence number. A writer thread will always update the sequence
// number in tandem with an event write or drop, but without a write
// barrier between those memory writes they might observed out-of-order
// by the thread capturing the sequence point. The only utility this
// unsynchronized read has is that if some other thread observes a sequence
// number X, it knows this thread must have attempted to write at least
// X events prior to the moment in time when the read occurred. If the event
// buffers are later read and there are fewer than X events timestamped
// prior to the sequence point we can be certain the others were dropped.
volatile uint32_t sequence_number;
};
#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_THREAD_GETTER_SETTER)
struct _EventPipeThreadSessionState {
uint8_t _internal [sizeof (struct _EventPipeThreadSessionState_Internal)];
};
#endif
EP_DEFINE_GETTER_REF(EventPipeThreadSessionState *, thread_session_state, EventPipeThreadHolder *, thread_holder)
EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, EventPipeSession *, session)
EventPipeThreadSessionState *
ep_thread_session_state_alloc (
EventPipeThread *thread,
EventPipeSession *session,
EventPipeBufferManager *buffer_manager);
void
ep_thread_session_state_free (EventPipeThreadSessionState *thread_session_state);
EventPipeThread *
ep_thread_session_state_get_thread (const EventPipeThreadSessionState *thread_session_state);
uint32_t
ep_thread_session_state_get_buffer_count_estimate(const EventPipeThreadSessionState *thread_session_state);
// _Requires_lock_held (thread)
EventPipeBuffer *
ep_thread_session_state_get_write_buffer (const EventPipeThreadSessionState *thread_session_state);
// _Requires_lock_held (thread)
void
ep_thread_session_state_set_write_buffer (
EventPipeThreadSessionState *thread_session_state,
EventPipeBuffer *new_buffer);
// _Requires_lock_held (buffer_manager)
EventPipeBufferList *
ep_thread_session_state_get_buffer_list (const EventPipeThreadSessionState *thread_session_state);
// _Requires_lock_held (buffer_manager)
void
ep_thread_session_state_set_buffer_list (
EventPipeThreadSessionState *thread_session_state,
EventPipeBufferList *new_buffer_list);
uint32_t
ep_thread_session_state_get_volatile_sequence_number (const EventPipeThreadSessionState *thread_session_state);
// _Requires_lock_held (thread)
uint32_t
ep_thread_session_state_get_sequence_number (const EventPipeThreadSessionState *thread_session_state);
// _Requires_lock_held (thread)
void
ep_thread_session_state_increment_sequence_number (EventPipeThreadSessionState *thread_session_state);
#endif /* ENABLE_PERFTRACING */
#endif /* __EVENTPIPE_THREAD_H__ */