[mini] set MONO_ARCH_HAVE_INIT_LMF_EXT on architectures that implement mono_arch_init...
[mono-project.git] / mono / mini / mini-windows.c
blob2d3c64f22e62ba0014bf63ff7dcb4f40619c4f84
1 /**
2 * \file
3 * POSIX signal handling support for Mono.
5 * Authors:
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Ximian, Inc.
11 * See LICENSE for licensing information.
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <config.h>
15 #include <signal.h>
16 #include <math.h>
17 #include <conio.h>
18 #include <assert.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/class.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/tabledefs.h>
27 #include <mono/metadata/threads.h>
28 #include <mono/metadata/appdomain.h>
29 #include <mono/metadata/debug-helpers.h>
30 #include "mono/metadata/profiler.h"
31 #include <mono/metadata/profiler-private.h>
32 #include <mono/metadata/mono-config.h>
33 #include <mono/metadata/environment.h>
34 #include <mono/metadata/mono-debug.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/verify.h>
38 #include <mono/metadata/verify-internals.h>
39 #include <mono/metadata/mempool-internals.h>
40 #include <mono/metadata/attach.h>
41 #include <mono/utils/mono-math.h>
42 #include <mono/utils/mono-compiler.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-logger-internals.h>
45 #include <mono/utils/mono-mmap.h>
46 #include <mono/utils/dtrace.h>
48 #include "mini.h"
49 #include "mini-windows.h"
50 #include <string.h>
51 #include <ctype.h>
52 #include "trace.h"
53 #include "version.h"
55 #include "jit-icalls.h"
57 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
58 #include <mmsystem.h>
59 #endif
61 #define MONO_HANDLER_DELIMITER ','
62 #define MONO_HANDLER_DELIMITER_LEN G_N_ELEMENTS(MONO_HANDLER_DELIMITER)-1
64 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS "atexit-waitkeypress"
65 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN G_N_ELEMENTS(MONO_HANDLER_ATEXIT_WAIT_KEYPRESS)-1
67 // Typedefs used to setup handler table.
68 typedef void (*handler)(void);
70 typedef struct {
71 const char * cmd;
72 const int cmd_len;
73 handler handler;
74 } HandlerItem;
76 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
77 /**
78 * atexit_wait_keypress:
80 * This function is installed as an atexit function making sure that the console is not terminated before the end user has a chance to read the result.
81 * This can be handy in debug scenarios (running from within the debugger) since an exit of the process will close the console window
82 * without giving the end user a chance to look at the output before closed.
84 static void
85 atexit_wait_keypress (void)
88 fflush (stdin);
90 printf ("Press any key to continue . . . ");
91 fflush (stdout);
93 _getch ();
95 return;
98 /**
99 * install_atexit_wait_keypress:
101 * This function installs the wait keypress exit handler.
103 static void
104 install_atexit_wait_keypress (void)
106 atexit (atexit_wait_keypress);
107 return;
110 #else
113 * install_atexit_wait_keypress:
115 * Not supported on WINAPI family.
117 static void
118 install_atexit_wait_keypress (void)
120 return;
123 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
125 // Table describing handlers that can be installed at process startup. Adding a new handler can be done by adding a new item to the table together with an install handler function.
126 const HandlerItem g_handler_items[] = { { MONO_HANDLER_ATEXIT_WAIT_KEYPRESS, MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN, install_atexit_wait_keypress },
127 { NULL, 0, NULL } };
130 * get_handler_arg_len:
131 * @handlers: Get length of next handler.
133 * This function calculates the length of next handler included in argument.
135 * Returns: The length of next handler, if available.
137 static size_t
138 get_next_handler_arg_len (const char *handlers)
140 assert (handlers != NULL);
142 size_t current_len = 0;
143 const char *handler = strchr (handlers, MONO_HANDLER_DELIMITER);
144 if (handler != NULL) {
145 // Get length of next handler arg.
146 current_len = (handler - handlers);
147 } else {
148 // Consume rest as length of next handler arg.
149 current_len = strlen (handlers);
152 return current_len;
156 * install_custom_handler:
157 * @handlers: Handlers included in --handler argument, example "atexit-waitkeypress,someothercmd,yetanothercmd".
158 * @handler_arg_len: Output, length of consumed handler.
160 * This function installs the next handler included in @handlers parameter.
162 * Returns: TRUE on successful install, FALSE on failure or unrecognized handler.
164 static gboolean
165 install_custom_handler (const char *handlers, size_t *handler_arg_len)
167 gboolean result = FALSE;
169 assert (handlers != NULL);
170 assert (handler_arg_len);
172 *handler_arg_len = get_next_handler_arg_len (handlers);
173 for (int current_item = 0; current_item < G_N_ELEMENTS (g_handler_items); ++current_item) {
174 const HandlerItem * handler_item = &g_handler_items [current_item];
176 if (handler_item->cmd == NULL)
177 continue;
179 if (*handler_arg_len == handler_item->cmd_len && strncmp (handlers, handler_item->cmd, *handler_arg_len) == 0) {
180 assert (handler_item->handler != NULL);
181 handler_item->handler ();
182 result = TRUE;
183 break;
186 return result;
189 void
190 mono_runtime_install_handlers (void)
192 #ifndef MONO_CROSS_COMPILE
193 win32_seh_init();
194 win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
195 win32_seh_set_handler(SIGILL, mono_sigill_signal_handler);
196 win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
197 if (mini_get_debug_options ()->handle_sigint)
198 win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
199 #endif
202 gboolean
203 mono_runtime_install_custom_handlers (const char *handlers)
205 gboolean result = FALSE;
207 assert (handlers != NULL);
208 while (*handlers != '\0') {
209 size_t handler_arg_len = 0;
211 result = install_custom_handler (handlers, &handler_arg_len);
212 handlers += handler_arg_len;
214 if (*handlers == MONO_HANDLER_DELIMITER)
215 handlers++;
216 if (!result)
217 break;
220 return result;
223 void
224 mono_runtime_install_custom_handlers_usage (void)
226 fprintf (stdout,
227 "Custom Handlers:\n"
228 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
229 " separated list of available handlers to install.\n"
230 "\n"
231 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
232 "HANDLERS is composed of:\n"
233 " atexit-waitkeypress Install an atexit handler waiting for a keypress\n"
234 " before exiting process.\n");
235 #else
236 "No handlers supported on current platform.\n");
237 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
240 void
241 mono_runtime_cleanup_handlers (void)
243 #ifndef MONO_CROSS_COMPILE
244 win32_seh_cleanup();
245 #endif
249 /* mono_chain_signal:
251 * Call the original signal handler for the signal given by the arguments, which
252 * should be the same as for a signal handler. Returns TRUE if the original handler
253 * was called, false otherwise.
255 gboolean
256 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
258 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
259 jit_tls->mono_win_chained_exception_needs_run = TRUE;
260 return TRUE;
263 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
264 static MMRESULT g_timer_event = 0;
265 static HANDLE g_timer_main_thread = INVALID_HANDLE_VALUE;
267 static VOID
268 thread_timer_expired (HANDLE thread)
270 CONTEXT context;
272 context.ContextFlags = CONTEXT_CONTROL;
273 if (GetThreadContext (thread, &context)) {
274 #ifdef _WIN64
275 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
276 #else
277 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
278 #endif
282 static VOID CALLBACK
283 timer_event_proc (UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
285 thread_timer_expired ((HANDLE)dwUser);
288 static VOID
289 stop_profiler_timer_event (void)
291 if (g_timer_event != 0) {
293 timeKillEvent (g_timer_event);
294 g_timer_event = 0;
297 if (g_timer_main_thread != INVALID_HANDLE_VALUE) {
299 CloseHandle (g_timer_main_thread);
300 g_timer_main_thread = INVALID_HANDLE_VALUE;
304 static VOID
305 start_profiler_timer_event (void)
307 g_return_if_fail (g_timer_main_thread == INVALID_HANDLE_VALUE && g_timer_event == 0);
309 TIMECAPS timecaps;
311 if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
312 return;
314 g_timer_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ());
315 if (g_timer_main_thread == NULL)
316 return;
318 if (timeBeginPeriod (1) != TIMERR_NOERROR)
319 return;
321 g_timer_event = timeSetEvent (1, 0, (LPTIMECALLBACK)timer_event_proc, (DWORD_PTR)g_timer_main_thread, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
322 if (g_timer_event == 0) {
323 timeEndPeriod (1);
324 return;
328 void
329 mono_runtime_setup_stat_profiler (void)
331 start_profiler_timer_event ();
332 return;
335 void
336 mono_runtime_shutdown_stat_profiler (void)
338 stop_profiler_timer_event ();
339 return;
342 gboolean
343 mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
345 HANDLE handle;
346 CONTEXT context;
348 g_assert (thread_id != GetCurrentThreadId ());
350 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
351 g_assert (handle);
353 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
355 if (!GetThreadContext (handle, &context)) {
356 CloseHandle (handle);
357 return FALSE;
360 g_assert (context.ContextFlags & CONTEXT_INTEGER);
361 g_assert (context.ContextFlags & CONTEXT_CONTROL);
363 memset (mono_context, 0, sizeof (MonoContext));
364 mono_sigctx_to_monoctx (&context, mono_context);
366 CloseHandle (handle);
367 return TRUE;
369 #endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
371 gboolean
372 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info)
374 DWORD id = mono_thread_info_get_tid (info);
375 MonoJitTlsData *jit_tls;
376 void *domain;
377 MonoLMF *lmf = NULL;
378 gpointer *addr;
380 tctx->valid = FALSE;
381 tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
382 tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
383 tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
385 mono_setup_thread_context(id, &tctx->ctx);
387 /* mono_set_jit_tls () sets this */
388 jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
389 /* SET_APPDOMAIN () sets this */
390 domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
392 /*Thread already started to cleanup, can no longer capture unwind state*/
393 if (!jit_tls || !domain)
394 return FALSE;
397 * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
398 * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
399 * can be accessed through MonoThreadInfo.
401 /* mono_set_lmf_addr () sets this */
402 addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
403 if (addr)
404 lmf = *addr;
406 tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
407 tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
408 tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
409 tctx->valid = TRUE;
411 return TRUE;