-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
ds-server.c
299 lines (245 loc) · 8.1 KB
/
ds-server.c
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
#include "ds-rt-config.h"
#ifdef ENABLE_PERFTRACING
#if !defined(DS_INCLUDE_SOURCE_FILES) || defined(DS_FORCE_INCLUDE_SOURCE_FILES)
#define DS_IMPL_SERVER_GETTER_SETTER
#include "ds-server.h"
#include "ds-ipc.h"
#include "ds-protocol.h"
#include "ds-process-protocol.h"
#include "ds-eventpipe-protocol.h"
#include "ds-dump-protocol.h"
#include "ds-profiler-protocol.h"
#include "ds-rt.h"
/*
* Globals and volatile access functions.
*/
static volatile uint32_t _server_shutting_down_state = 0;
static ep_rt_wait_event_handle_t _server_resume_runtime_startup_event = { 0 };
static bool _server_disabled = false;
static volatile bool _is_paused_for_startup = false;
static
inline
bool
server_volatile_load_shutting_down_state (void)
{
return (ep_rt_volatile_load_uint32_t (&_server_shutting_down_state) != 0) ? true : false;
}
static
inline
void
server_volatile_store_shutting_down_state (bool state)
{
ep_rt_volatile_store_uint32_t (&_server_shutting_down_state, state ? 1 : 0);
}
/*
* Forward declares of all static functions.
*/
static
void
server_error_callback_create (
const ep_char8_t *message,
uint32_t code);
static
void
server_error_callback_close (
const ep_char8_t *message,
uint32_t code);
static
void
server_warning_callback (
const ep_char8_t *message,
uint32_t code);
static
bool
server_protocol_helper_unknown_command (
DiagnosticsIpcMessage *message,
DiagnosticsIpcStream *stream);
/*
* DiagnosticServer.
*/
static
void
server_error_callback_create (
const ep_char8_t *message,
uint32_t code)
{
EP_ASSERT (message != NULL);
DS_LOG_ERROR_2 ("Failed to create diagnostic IPC: error (%d): %s.", code, message);
}
static
void
server_error_callback_close (
const ep_char8_t *message,
uint32_t code)
{
EP_ASSERT (message != NULL);
DS_LOG_ERROR_2 ("Failed to close diagnostic IPC: error (%d): %s.", code, message);
}
static
bool
server_protocol_helper_unknown_command (
DiagnosticsIpcMessage *message,
DiagnosticsIpcStream *stream)
{
DS_LOG_WARNING_1 ("Received unknown request type (%d)", ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (message)));
ds_ipc_message_send_error (stream, DS_IPC_E_UNKNOWN_COMMAND);
ds_ipc_stream_free (stream);
return true;
}
static
void
server_warning_callback (
const ep_char8_t *message,
uint32_t code)
{
EP_ASSERT (message != NULL);
DS_LOG_WARNING_2 ("warning (%d): %s.", code, message);
}
EP_RT_DEFINE_THREAD_FUNC (server_thread)
{
EP_ASSERT (server_volatile_load_shutting_down_state () || ds_ipc_stream_factory_has_active_ports ());
ep_rt_set_server_name();
if (!ds_ipc_stream_factory_has_active_ports ()) {
#ifndef DS_IPC_DISABLE_LISTEN_PORTS
DS_LOG_ERROR_0 ("Diagnostics IPC listener was undefined");
#endif
return 1;
}
while (!server_volatile_load_shutting_down_state ()) {
DiagnosticsIpcStream *stream = ds_ipc_stream_factory_get_next_available_stream (server_warning_callback);
if (!stream)
continue;
ds_rt_auto_trace_signal ();
DiagnosticsIpcMessage message;
if (!ds_ipc_message_init (&message))
continue;
if (!ds_ipc_message_initialize_stream (&message, stream)) {
ds_ipc_message_send_error (stream, DS_IPC_E_BAD_ENCODING);
ds_ipc_stream_free (stream);
ds_ipc_message_fini (&message);
continue;
}
if (ep_rt_utf8_string_compare (
(const ep_char8_t *)ds_ipc_header_get_magic_ref (ds_ipc_message_get_header_ref (&message)),
(const ep_char8_t *)DOTNET_IPC_V1_MAGIC) != 0) {
ds_ipc_message_send_error (stream, DS_IPC_E_UNKNOWN_MAGIC);
ds_ipc_stream_free (stream);
ds_ipc_message_fini (&message);
continue;
}
DS_LOG_INFO_2 ("DiagnosticServer - received IPC message with command set (%d) and command id (%d)", ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message)), ds_ipc_header_get_commandid (ds_ipc_message_get_header_ref (&message)));
switch ((DiagnosticsServerCommandSet)ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message))) {
case DS_SERVER_COMMANDSET_EVENTPIPE:
ds_eventpipe_protocol_helper_handle_ipc_message (&message, stream);
break;
case DS_SERVER_COMMANDSET_DUMP:
ds_dump_protocol_helper_handle_ipc_message (&message, stream);
break;
case DS_SERVER_COMMANDSET_PROCESS:
ds_process_protocol_helper_handle_ipc_message (&message, stream);
break;
case DS_SERVER_COMMANDSET_PROFILER:
ds_profiler_protocol_helper_handle_ipc_message (&message, stream);
break;
default:
server_protocol_helper_unknown_command (&message, stream);
break;
}
ds_ipc_message_fini (&message);
}
return (ep_rt_thread_start_func_return_t)0;
}
void
ds_server_disable (void)
{
_server_disabled = true;
}
bool
ds_server_init (void)
{
if (!ds_ipc_stream_factory_init ())
return false;
if (_server_disabled || !ds_rt_config_value_get_enable ())
return true;
bool result = false;
// Initialize PAL layer.
if (!ds_ipc_pal_init ()) {
DS_LOG_ERROR_1 ("Failed to initialize PAL layer (%d).", ep_rt_get_last_error ());
ep_raise_error ();
}
// Initialize the RuntimeIdentifier before use
ds_ipc_advertise_cookie_v1_init ();
// Ports can fail to be configured
if (!ds_ipc_stream_factory_configure (server_error_callback_create))
DS_LOG_ERROR_0 ("At least one Diagnostic Port failed to be configured.");
if (ds_ipc_stream_factory_any_suspended_ports ()) {
ep_rt_wait_event_alloc (&_server_resume_runtime_startup_event, true, false);
ep_raise_error_if_nok (ep_rt_wait_event_is_valid (&_server_resume_runtime_startup_event));
}
if (ds_ipc_stream_factory_has_active_ports ()) {
ds_rt_auto_trace_init ();
ds_rt_auto_trace_launch ();
ep_rt_thread_id_t thread_id = ep_rt_uint64_t_to_thread_id_t (0);
if (!ep_rt_thread_create ((void *)server_thread, NULL, EP_THREAD_TYPE_SERVER, (void *)&thread_id)) {
// Failed to create IPC thread.
ds_ipc_stream_factory_close_ports (NULL);
DS_LOG_ERROR_1 ("Failed to create diagnostic server thread (%d).", ep_rt_get_last_error ());
ep_raise_error ();
} else {
ds_rt_auto_trace_wait ();
}
}
result = true;
ep_on_exit:
return result;
ep_on_error:
EP_ASSERT (!result);
ep_exit_error_handler ();
}
bool
ds_server_shutdown (void)
{
server_volatile_store_shutting_down_state (true);
if (ds_ipc_stream_factory_has_active_ports ())
ds_ipc_stream_factory_shutdown (server_error_callback_close);
ds_ipc_stream_factory_fini ();
ds_ipc_pal_shutdown ();
return true;
}
// This method will block runtime bring-up IFF DOTNET_DefaultDiagnosticPortSuspend != NULL and DOTNET_DiagnosticPorts != 0 (it's default state)
// The _ds_resume_runtime_startup_event event will be signaled when the Diagnostics Monitor uses the ResumeRuntime Diagnostics IPC Command
void
ds_server_pause_for_diagnostics_monitor (void)
{
_is_paused_for_startup = true;
if (ds_ipc_stream_factory_any_suspended_ports ()) {
EP_ASSERT (ep_rt_wait_event_is_valid (&_server_resume_runtime_startup_event));
DS_LOG_ALWAYS_0 ("The runtime has been configured to pause during startup and is awaiting a Diagnostics IPC ResumeStartup command.");
if (ep_rt_wait_event_wait (&_server_resume_runtime_startup_event, 5000, false) != 0) {
ds_rt_server_log_pause_message ();
DS_LOG_ALWAYS_0 ("The runtime has been configured to pause during startup and is awaiting a Diagnostics IPC ResumeStartup command and has waited 5 seconds.");
ep_rt_wait_event_wait (&_server_resume_runtime_startup_event, EP_INFINITE_WAIT, false);
}
}
// allow wait failures to fall through and the runtime to continue coming up
}
void
ds_server_resume_runtime_startup (void)
{
ds_ipc_stream_factory_resume_current_port ();
if (!ds_ipc_stream_factory_any_suspended_ports () && ep_rt_wait_event_is_valid (&_server_resume_runtime_startup_event)) {
ep_rt_wait_event_set (&_server_resume_runtime_startup_event);
_is_paused_for_startup = false;
}
}
bool
ds_server_is_paused_in_startup (void)
{
return _is_paused_for_startup;
}
#endif /* !defined(DS_INCLUDE_SOURCE_FILES) || defined(DS_FORCE_INCLUDE_SOURCE_FILES) */
#endif /* ENABLE_PERFTRACING */
#if !defined(ENABLE_PERFTRACING) || (defined(DS_INCLUDE_SOURCE_FILES) && !defined(DS_FORCE_INCLUDE_SOURCE_FILES))
extern const char quiet_linker_empty_file_warning_diagnostics_server;
const char quiet_linker_empty_file_warning_diagnostics_server = 0;
#endif