[threadpool] Let the runtime abort and wait for threads on shutdown (#4348)
[mono.git] / mono / metadata / runtime.c
1 /*
2  * runtime.c: Runtime functions
3  *
4  * Authors:
5  *  Jonathan Pryor 
6  *
7  * Copyright 2010 Novell, Inc (http://www.novell.com)
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include <config.h>
12
13 #include <glib.h>
14
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/class.h>
17 #include <mono/metadata/class-internals.h>
18 #include <mono/metadata/runtime.h>
19 #include <mono/metadata/monitor.h>
20 #include <mono/metadata/threads-types.h>
21 #include <mono/metadata/threadpool.h>
22 #include <mono/metadata/marshal.h>
23 #include <mono/utils/atomic.h>
24
25 static gboolean shutting_down_inited = FALSE;
26 static gboolean shutting_down = FALSE;
27
28 /** 
29  * mono_runtime_set_shutting_down:
30  *
31  * Invoked by System.Environment.Exit to flag that the runtime
32  * is shutting down.
33  *
34  * Deprecated. This function can break the shutdown sequence.
35  */
36 void
37 mono_runtime_set_shutting_down (void)
38 {
39         shutting_down = TRUE;
40 }
41
42 /**
43  * mono_runtime_is_shutting_down:
44  *
45  * Returns whether the runtime has been flagged for shutdown.
46  *
47  * This is consumed by the P:System.Environment.HasShutdownStarted
48  * property.
49  *
50  */
51 gboolean
52 mono_runtime_is_shutting_down (void)
53 {
54         return shutting_down;
55 }
56
57 static void
58 fire_process_exit_event (MonoDomain *domain, gpointer user_data)
59 {
60         MonoError error;
61         MonoClassField *field;
62         gpointer pa [2];
63         MonoObject *delegate, *exc;
64
65         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
66         g_assert (field);
67
68         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
69         if (delegate == NULL)
70                 return;
71
72         pa [0] = domain;
73         pa [1] = NULL;
74         mono_runtime_delegate_try_invoke (delegate, pa, &exc, &error);
75         mono_error_cleanup (&error);
76 }
77
78 static void
79 mono_runtime_fire_process_exit_event (void)
80 {
81 #ifndef MONO_CROSS_COMPILE
82         mono_domain_foreach (fire_process_exit_event, NULL);
83 #endif
84 }
85
86
87 /**
88  * mono_runtime_try_shutdown:
89  *
90  * Try to initialize runtime shutdown.
91  *
92  * After this call completes the thread pool will stop accepting new jobs and no further threads will be created.
93  *
94  * Returns: TRUE if shutdown was initiated by this call or false is other thread beat this one.
95  */
96 gboolean
97 mono_runtime_try_shutdown (void)
98 {
99         if (InterlockedCompareExchange (&shutting_down_inited, TRUE, FALSE))
100                 return FALSE;
101
102         mono_runtime_fire_process_exit_event ();
103
104         shutting_down = TRUE;
105
106         mono_threads_set_shutting_down ();
107
108         /* No new threads will be created after this point */
109
110         mono_runtime_set_shutting_down ();
111
112         /*TODO move the follow to here:
113         mono_thread_suspend_all_other_threads (); OR  mono_thread_wait_all_other_threads
114
115         mono_runtime_quit ();
116         */
117
118         return TRUE;
119 }
120
121
122 gboolean
123 mono_runtime_is_critical_method (MonoMethod *method)
124 {
125         return FALSE;
126 }
127
128 /*
129 Coordinate the creation of all remaining TLS slots in the runtime.
130 No further TLS slots should be created after this function finishes.
131 This restriction exists because AOT requires offsets to be constant
132 across runs.
133 */
134 void
135 mono_runtime_init_tls (void)
136 {
137         mono_marshal_init_tls ();
138 }
139
140 char*
141 mono_runtime_get_aotid (void)
142 {
143         int i;
144         guint8 aotid_sum = 0;
145         MonoDomain* domain = mono_domain_get ();
146
147         if (!domain->entry_assembly || !domain->entry_assembly->image)
148                 return NULL;
149
150         guint8 (*aotid)[16] = &domain->entry_assembly->image->aotid;
151
152         for (i = 0; i < 16; ++i)
153                 aotid_sum |= (*aotid)[i];
154
155         if (aotid_sum == 0)
156                 return NULL;
157
158         return mono_guid_to_string ((guint8*) aotid);
159 }