[tests] Reenable enum equals test on interpreter (#18673)
[mono-project.git] / mono / mini / mini-windows.c
blob6a02867da6de32f7084ed6577f90cae7caab57e9
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/coree.h>
21 #include <mono/metadata/assembly.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/tabledefs.h>
24 #include <mono/metadata/class.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/tabledefs.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/appdomain.h>
30 #include <mono/metadata/debug-helpers.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-runtime.h"
50 #include "mini-windows.h"
51 #include <string.h>
52 #include <ctype.h>
53 #include "trace.h"
54 #include "version.h"
56 #include "jit-icalls.h"
58 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
59 #include <mmsystem.h>
60 #endif
62 #define MONO_HANDLER_DELIMITER ','
63 #define MONO_HANDLER_DELIMITER_LEN G_N_ELEMENTS(MONO_HANDLER_DELIMITER)-1
65 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS "atexit-waitkeypress"
66 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN G_N_ELEMENTS(MONO_HANDLER_ATEXIT_WAIT_KEYPRESS)-1
68 // Typedefs used to setup handler table.
69 typedef void (*handler)(void);
71 typedef struct {
72 const char * cmd;
73 const int cmd_len;
74 handler handler;
75 } HandlerItem;
77 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
78 /**
79 * atexit_wait_keypress:
81 * 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.
82 * This can be handy in debug scenarios (running from within the debugger) since an exit of the process will close the console window
83 * without giving the end user a chance to look at the output before closed.
85 static void
86 atexit_wait_keypress (void)
89 fflush (stdin);
91 printf ("Press any key to continue . . . ");
92 fflush (stdout);
94 _getch ();
96 return;
99 /**
100 * install_atexit_wait_keypress:
102 * This function installs the wait keypress exit handler.
104 static void
105 install_atexit_wait_keypress (void)
107 atexit (atexit_wait_keypress);
108 return;
111 #else
114 * install_atexit_wait_keypress:
116 * Not supported on WINAPI family.
118 static void
119 install_atexit_wait_keypress (void)
121 return;
124 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
126 // 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.
127 const HandlerItem g_handler_items[] = { { MONO_HANDLER_ATEXIT_WAIT_KEYPRESS, MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN, install_atexit_wait_keypress },
128 { NULL, 0, NULL } };
131 * get_handler_arg_len:
132 * @handlers: Get length of next handler.
134 * This function calculates the length of next handler included in argument.
136 * Returns: The length of next handler, if available.
138 static size_t
139 get_next_handler_arg_len (const char *handlers)
141 assert (handlers != NULL);
143 size_t current_len = 0;
144 const char *handler = strchr (handlers, MONO_HANDLER_DELIMITER);
145 if (handler != NULL) {
146 // Get length of next handler arg.
147 current_len = (handler - handlers);
148 } else {
149 // Consume rest as length of next handler arg.
150 current_len = strlen (handlers);
153 return current_len;
157 * install_custom_handler:
158 * @handlers: Handlers included in --handler argument, example "atexit-waitkeypress,someothercmd,yetanothercmd".
159 * @handler_arg_len: Output, length of consumed handler.
161 * This function installs the next handler included in @handlers parameter.
163 * Returns: TRUE on successful install, FALSE on failure or unrecognized handler.
165 static gboolean
166 install_custom_handler (const char *handlers, size_t *handler_arg_len)
168 gboolean result = FALSE;
170 assert (handlers != NULL);
171 assert (handler_arg_len);
173 *handler_arg_len = get_next_handler_arg_len (handlers);
174 for (int current_item = 0; current_item < G_N_ELEMENTS (g_handler_items); ++current_item) {
175 const HandlerItem * handler_item = &g_handler_items [current_item];
177 if (handler_item->cmd == NULL)
178 continue;
180 if (*handler_arg_len == handler_item->cmd_len && strncmp (handlers, handler_item->cmd, *handler_arg_len) == 0) {
181 assert (handler_item->handler != NULL);
182 handler_item->handler ();
183 result = TRUE;
184 break;
187 return result;
190 void
191 mono_runtime_install_handlers (void)
193 #ifndef MONO_CROSS_COMPILE
194 win32_seh_init();
195 win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
196 win32_seh_set_handler(SIGILL, mono_sigill_signal_handler);
197 win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
198 if (mini_debug_options.handle_sigint)
199 win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
200 #endif
203 gboolean
204 mono_runtime_install_custom_handlers (const char *handlers)
206 gboolean result = FALSE;
208 assert (handlers != NULL);
209 while (*handlers != '\0') {
210 size_t handler_arg_len = 0;
212 result = install_custom_handler (handlers, &handler_arg_len);
213 handlers += handler_arg_len;
215 if (*handlers == MONO_HANDLER_DELIMITER)
216 handlers++;
217 if (!result)
218 break;
221 return result;
224 void
225 mono_runtime_install_custom_handlers_usage (void)
227 fprintf (stdout,
228 "Custom Handlers:\n"
229 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
230 " separated list of available handlers to install.\n"
231 "\n"
232 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
233 "HANDLERS is composed of:\n"
234 " atexit-waitkeypress Install an atexit handler waiting for a keypress\n"
235 " before exiting process.\n");
236 #else
237 "No handlers supported on current platform.\n");
238 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
241 void
242 mono_runtime_cleanup_handlers (void)
244 #ifndef MONO_CROSS_COMPILE
245 win32_seh_cleanup();
246 #endif
249 void
250 mono_init_native_crash_info (void)
252 return;
255 void
256 mono_cleanup_native_crash_info (void)
258 return;
261 #if G_HAVE_API_SUPPORT (HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
262 /* mono_chain_signal:
264 * Call the original signal handler for the signal given by the arguments, which
265 * should be the same as for a signal handler. Returns TRUE if the original handler
266 * was called, false otherwise.
268 gboolean
269 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
271 /* Set to FALSE to indicate that vectored exception handling should continue to look for handler */
272 MONO_SIG_HANDLER_GET_INFO ()->handled = FALSE;
273 return TRUE;
276 #ifndef MONO_CROSS_COMPILE
277 void
278 mono_dump_native_crash_info (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info)
280 //TBD
283 void
284 mono_post_native_crash_handler (const char *signal, MonoContext *mctx, MONO_SIG_HANDLER_INFO_TYPE *info, gboolean crash_chaining)
286 if (!crash_chaining)
287 abort ();
289 #endif /* !MONO_CROSS_COMPILE */
290 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
292 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
293 static MMRESULT g_timer_event = 0;
294 static HANDLE g_timer_main_thread = INVALID_HANDLE_VALUE;
296 static VOID
297 thread_timer_expired (HANDLE thread)
299 CONTEXT context;
301 context.ContextFlags = CONTEXT_CONTROL;
302 if (GetThreadContext (thread, &context)) {
303 guchar *ip;
305 #ifdef _WIN64
306 ip = (guchar *) context.Rip;
307 #else
308 ip = (guchar *) context.Eip;
309 #endif
311 MONO_PROFILER_RAISE (sample_hit, (ip, &context));
315 static VOID CALLBACK
316 timer_event_proc (UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
318 thread_timer_expired ((HANDLE)dwUser);
321 static VOID
322 stop_profiler_timer_event (void)
324 if (g_timer_event != 0) {
326 timeKillEvent (g_timer_event);
327 g_timer_event = 0;
330 if (g_timer_main_thread != INVALID_HANDLE_VALUE) {
332 CloseHandle (g_timer_main_thread);
333 g_timer_main_thread = INVALID_HANDLE_VALUE;
337 static VOID
338 start_profiler_timer_event (void)
340 g_return_if_fail (g_timer_main_thread == INVALID_HANDLE_VALUE && g_timer_event == 0);
342 TIMECAPS timecaps;
344 if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
345 return;
347 g_timer_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ());
348 if (g_timer_main_thread == NULL)
349 return;
351 if (timeBeginPeriod (1) != TIMERR_NOERROR)
352 return;
354 g_timer_event = timeSetEvent (1, 0, (LPTIMECALLBACK)timer_event_proc, (DWORD_PTR)g_timer_main_thread, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
355 if (g_timer_event == 0) {
356 timeEndPeriod (1);
357 return;
361 void
362 mono_runtime_setup_stat_profiler (void)
364 start_profiler_timer_event ();
365 return;
368 void
369 mono_runtime_shutdown_stat_profiler (void)
371 stop_profiler_timer_event ();
372 return;
375 gboolean
376 mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
378 HANDLE handle;
379 CONTEXT context;
381 g_assert (thread_id != GetCurrentThreadId ());
383 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
384 g_assert (handle);
386 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
388 if (!GetThreadContext (handle, &context)) {
389 CloseHandle (handle);
390 return FALSE;
393 g_assert (context.ContextFlags & CONTEXT_INTEGER);
394 g_assert (context.ContextFlags & CONTEXT_CONTROL);
396 memset (mono_context, 0, sizeof (MonoContext));
397 mono_sigctx_to_monoctx (&context, mono_context);
399 CloseHandle (handle);
400 return TRUE;
402 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
404 gboolean
405 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info, void *sigctx)
407 tctx->valid = FALSE;
408 tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
409 tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
410 tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
412 if (sigctx == NULL) {
413 DWORD id = mono_thread_info_get_tid (info);
414 mono_setup_thread_context (id, &tctx->ctx);
415 } else {
416 g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_INTEGER);
417 g_assert (((CONTEXT *)sigctx)->ContextFlags & CONTEXT_CONTROL);
418 mono_sigctx_to_monoctx (sigctx, &tctx->ctx);
421 /* mono_set_jit_tls () sets this */
422 void *jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
423 /* SET_APPDOMAIN () sets this */
424 void *domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
426 /*Thread already started to cleanup, can no longer capture unwind state*/
427 if (!jit_tls || !domain)
428 return FALSE;
431 * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
432 * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
433 * can be accessed through MonoThreadInfo.
435 /* mono_set_lmf_addr () sets this */
436 MonoLMF *lmf = NULL;
437 MonoLMF **addr = (MonoLMF**)mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
438 if (addr)
439 lmf = *addr;
441 tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
442 tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
443 tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
444 tctx->valid = TRUE;
446 return TRUE;
449 BOOL
450 mono_win32_runtime_tls_callback (HMODULE module_handle, DWORD reason, LPVOID reserved, MonoWin32TLSCallbackType callback_type)
452 if (!mono_win32_handle_tls_callback_type (callback_type))
453 return TRUE;
455 if (!mono_gc_dllmain (module_handle, reason, reserved))
456 return FALSE;
458 switch (reason)
460 case DLL_PROCESS_ATTACH:
461 mono_install_runtime_load (mini_init);
462 break;
463 case DLL_PROCESS_DETACH:
464 if (coree_module_handle)
465 FreeLibrary (coree_module_handle);
466 break;
467 case DLL_THREAD_DETACH:
468 mono_thread_info_detach ();
469 break;
472 return TRUE;