Merge pull request #2022 from esdrubal/fixes-GetDaylightChanges
[mono.git] / mono / mini / tasklets.c
1
2 #include "config.h"
3 #include "tasklets.h"
4 #include "mono/metadata/exception.h"
5 #include "mono/metadata/gc-internal.h"
6 #include "mini.h"
7
8 #if defined(MONO_SUPPORT_TASKLETS)
9
10 static mono_mutex_t tasklets_mutex;
11 #define tasklets_lock() mono_mutex_lock(&tasklets_mutex)
12 #define tasklets_unlock() mono_mutex_unlock(&tasklets_mutex)
13
14 /* LOCKING: tasklets_mutex is assumed to e taken */
15 static void
16 internal_init (void)
17 {
18         if (!mono_gc_is_moving ())
19                 /* Boehm requires the keepalive stacks to be kept in a hash since mono_gc_alloc_fixed () returns GC memory */
20                 g_assert_not_reached ();
21 }
22
23 static void*
24 continuation_alloc (void)
25 {
26         MonoContinuation *cont = g_new0 (MonoContinuation, 1);
27         return cont;
28 }
29
30 static void
31 continuation_free (MonoContinuation *cont)
32 {
33         if (cont->saved_stack)
34                 mono_gc_free_fixed (cont->saved_stack);
35         g_free (cont);
36 }
37
38 static MonoException*
39 continuation_mark_frame (MonoContinuation *cont)
40 {
41         MonoJitTlsData *jit_tls;
42         MonoLMF *lmf;
43         MonoContext ctx, new_ctx;
44         MonoJitInfo *ji, rji;
45         int endloop = FALSE;
46
47         if (cont->domain)
48                 return mono_get_exception_argument ("cont", "Already marked");
49
50         jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
51         lmf = mono_get_lmf();
52         cont->domain = mono_domain_get ();
53         cont->thread_id = GetCurrentThreadId ();
54
55         /* get to the frame that called Mark () */
56         memset (&rji, 0, sizeof (rji));
57         do {
58                 ji = mono_find_jit_info (cont->domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
59                 if (!ji || ji == (gpointer)-1) {
60                         return mono_get_exception_not_supported ("Invalid stack frame");
61                 }
62                 ctx = new_ctx;
63                 if (endloop)
64                         break;
65                 if (!ji->is_trampoline && strcmp (jinfo_get_method (ji)->name, "Mark") == 0)
66                         endloop = TRUE;
67         } while (1);
68
69         cont->top_sp = MONO_CONTEXT_GET_SP (&ctx);
70         /*g_print ("method: %s, sp: %p\n", jinfo_get_method (ji)->name, cont->top_sp);*/
71
72         return NULL;
73 }
74
75 static int
76 continuation_store (MonoContinuation *cont, int state, MonoException **e)
77 {
78         MonoLMF *lmf = mono_get_lmf ();
79         gsize num_bytes;
80
81         if (!cont->domain) {
82                 *e =  mono_get_exception_argument ("cont", "Continuation not initialized");
83                 return 0;
84         }
85         if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ()) {
86                 *e = mono_get_exception_argument ("cont", "Continuation from another thread or domain");
87                 return 0;
88         }
89
90         cont->lmf = lmf;
91         cont->return_ip = __builtin_extract_return_addr (__builtin_return_address (0));
92         cont->return_sp = __builtin_frame_address (0);
93
94         num_bytes = (char*)cont->top_sp - (char*)cont->return_sp;
95
96         /*g_print ("store: %d bytes, sp: %p, ip: %p, lmf: %p\n", num_bytes, cont->return_sp, cont->return_ip, lmf);*/
97
98         if (cont->saved_stack && num_bytes <= cont->stack_alloc_size) {
99                 /* clear to avoid GC retention */
100                 if (num_bytes < cont->stack_used_size) {
101                         memset ((char*)cont->saved_stack + num_bytes, 0, cont->stack_used_size - num_bytes);
102                 }
103                 cont->stack_used_size = num_bytes;
104         } else {
105                 tasklets_lock ();
106                 internal_init ();
107                 if (cont->saved_stack)
108                         mono_gc_free_fixed (cont->saved_stack);
109                 cont->stack_used_size = num_bytes;
110                 cont->stack_alloc_size = num_bytes * 1.1;
111                 cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL, MONO_ROOT_SOURCE_THREADING, "saved tasklet stack");
112                 tasklets_unlock ();
113         }
114         memcpy (cont->saved_stack, cont->return_sp, num_bytes);
115
116         return state;
117 }
118
119 static MonoException*
120 continuation_restore (MonoContinuation *cont, int state)
121 {
122         MonoLMF **lmf_addr = mono_get_lmf_addr ();
123         MonoContinuationRestore restore_state = mono_tasklets_arch_restore ();
124
125         if (!cont->domain || !cont->return_sp)
126                 return mono_get_exception_argument ("cont", "Continuation not initialized");
127         if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ())
128                 return mono_get_exception_argument ("cont", "Continuation from another thread or domain");
129
130         /*g_print ("restore: %p, state: %d\n", cont, state);*/
131         *lmf_addr = cont->lmf;
132         restore_state (cont, state, lmf_addr);
133         g_assert_not_reached ();
134 }
135
136 void
137 mono_tasklets_init (void)
138 {
139         mono_mutex_init_recursive (&tasklets_mutex);
140
141         mono_add_internal_call ("Mono.Tasklets.Continuation::alloc", continuation_alloc);
142         mono_add_internal_call ("Mono.Tasklets.Continuation::free", continuation_free);
143         mono_add_internal_call ("Mono.Tasklets.Continuation::mark", continuation_mark_frame);
144         mono_add_internal_call ("Mono.Tasklets.Continuation::store", continuation_store);
145         mono_add_internal_call ("Mono.Tasklets.Continuation::restore", continuation_restore);
146 }
147
148 void
149 mono_tasklets_cleanup (void)
150 {
151 }
152
153 #endif
154