* src/vm/finalizer.cpp, src/vm/finalizer.hpp: Generalize internal finalizer
[cacao.git] / src / vm / finalizer.cpp
1 /* src/vm/finalizer.cpp - finalizer linked list and thread
2
3    Copyright (C) 1996-2011
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdlib.h>
29
30 #include "vm/types.h"
31
32 #include "mm/memory.hpp"
33
34 #include "threads/condition.hpp"
35 #include "threads/mutex.hpp"
36 #include "threads/thread.hpp"
37 #include "threads/lock.hpp"
38
39 #include "vm/jit/builtin.hpp"
40 #include "vm/exceptions.hpp"
41 #include "vm/global.h"
42 #include "vm/options.h"
43 #include "vm/vm.hpp"
44
45 #include "vm/jit/asmpart.h"
46
47 #include "finalizer.hpp"
48
49 #include <map>
50
51 #if defined(ENABLE_GC_BOEHM)
52 # include "mm/boehm-gc/include/gc.h"
53 #endif
54
55 /* global variables ***********************************************************/
56
57 #if defined(ENABLE_THREADS)
58 static Mutex     *finalizer_thread_mutex;
59 static Condition *finalizer_thread_cond;
60 #endif
61
62 extern "C" {
63
64 /* finalizer_init **************************************************************
65
66    Initializes the finalizer global lock and the linked list.
67
68 *******************************************************************************/
69
70 bool finalizer_init(void)
71 {
72         TRACESUBSYSTEMINITIALIZATION("finalizer_init");
73
74 #if defined(ENABLE_THREADS)
75         finalizer_thread_mutex = new Mutex();
76         finalizer_thread_cond  = new Condition();
77 #endif
78
79         /* everything's ok */
80
81         return true;
82 }
83
84
85 /* finalizer_thread ************************************************************
86
87    This thread waits on an object for a notification and the runs the
88    finalizers (finalizer thread).  This is necessary because of a
89    possible deadlock in the GC.
90
91 *******************************************************************************/
92
93 #if defined(ENABLE_THREADS)
94 static void finalizer_thread(void)
95 {
96         while (true) {
97                 /* get the lock on the finalizer mutex, so we can call wait */
98
99                 finalizer_thread_mutex->lock();
100
101                 /* wait forever on that condition till we are signaled */
102         
103                 finalizer_thread_cond->wait(finalizer_thread_mutex);
104
105                 /* leave the lock */
106
107                 finalizer_thread_mutex->unlock();
108
109 #if !defined(NDEBUG)
110                 if (opt_DebugFinalizer)
111                         log_println("[finalizer thread    : status=awake]");
112 #endif
113
114                 /* and call the finalizers */
115
116                 gc_invoke_finalizers();
117
118 #if !defined(NDEBUG)
119                 if (opt_DebugFinalizer)
120                         log_println("[finalizer thread    : status=sleeping]");
121 #endif
122         }
123 }
124 #endif
125
126
127 /* finalizer_start_thread ******************************************************
128
129    Starts the finalizer thread.
130
131 *******************************************************************************/
132
133 #if defined(ENABLE_THREADS)
134 bool finalizer_start_thread(void)
135 {
136         utf *name;
137
138         name = utf_new_char("Finalizer");
139
140         if (!threads_thread_start_internal(name, finalizer_thread))
141                 return false;
142
143         /* everything's ok */
144
145         return true;
146 }
147 #endif
148
149
150 /* finalizer_notify ************************************************************
151
152    Notifies the finalizer thread that it should run the
153    gc_invoke_finalizers from the GC.
154
155 *******************************************************************************/
156
157 void finalizer_notify(void)
158 {
159 #if !defined(NDEBUG)
160         if (opt_DebugFinalizer)
161                 log_println("[finalizer notified]");
162 #endif
163
164 #if defined(ENABLE_THREADS)
165         /* get the lock on the finalizer lock object, so we can call wait */
166
167         finalizer_thread_mutex->lock();
168
169         /* signal the finalizer thread */
170
171         finalizer_thread_cond->signal();
172
173         /* leave the lock */
174
175         finalizer_thread_mutex->unlock();
176 #else
177         /* if we don't have threads, just run the finalizers */
178
179         gc_invoke_finalizers();
180 #endif
181 }
182
183
184 /* finalizer_run ***************************************************************
185
186    Actually run the finalizer functions.
187
188 *******************************************************************************/
189
190 void finalizer_run(void *o, void *p)
191 {
192         java_handle_t *h;
193         classinfo     *c;
194
195         h = (java_handle_t *) o;
196
197 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
198         /* XXX this is only a dirty hack to make Boehm work with handles */
199
200         h = LLNI_WRAP((java_object_t *) h);
201 #endif
202
203         LLNI_class_get(h, c);
204
205 #if !defined(NDEBUG)
206         if (opt_DebugFinalizer) {
207                 log_start();
208                 log_print("[finalizer running   : o=%p p=%p class=", o, p);
209                 class_print(c);
210                 log_print("]");
211                 log_finish();
212         }
213 #endif
214
215         /* call the finalizer function */
216
217         (void) vm_call_method(c->finalizer, h);
218
219 #if !defined(NDEBUG)
220         if (opt_DebugFinalizer && (exceptions_get_exception() != NULL)) {
221                 log_println("[finalizer exception]");
222                 exceptions_print_stacktrace();
223         }
224 #endif
225
226         /* if we had an exception in the finalizer, ignore it */
227
228         exceptions_clear_exception();
229
230 #if defined(ENABLE_GC_BOEHM)
231         Finalizer::reinstall_custom_finalizer(h);
232 #endif
233 }
234
235 }
236
237 #if defined(ENABLE_GC_BOEHM)
238
239 struct FinalizerData {
240         Finalizer::FinalizerFunc f;
241         void *data;
242         FinalizerData(Finalizer::FinalizerFunc f, void *data): f(f), data(data) { }
243 };
244
245 Mutex final_mutex;
246 // final_map contains registered custom finalizers for a given Java
247 // object. Must be accessed with held final_mutex.
248 std::multimap<java_handle_t *, FinalizerData> final_map;
249
250 static void custom_finalizer_handler(void *object, void *data)
251 {
252         typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
253         java_handle_t *hdl = (java_handle_t *) object;
254         MutexLocker l(final_mutex);
255         MI it_first = final_map.lower_bound(hdl), it = it_first;
256         assert(it->first == hdl);
257         for (; it->first == hdl; ++it) {
258                 final_mutex.unlock();
259                 it->second.f(hdl, it->second.data);
260                 final_mutex.lock();
261         }
262         final_map.erase(it_first, it);
263 }
264
265 /* attach_custom_finalizer *****************************************************
266
267    Register a custom handler that is run when the object becomes
268    unreachable. This is intended for internal cleanup actions. If the
269    handler already exists, it is not registered again, and its data
270    pointer is returned.
271
272 *******************************************************************************/
273
274 void *Finalizer::attach_custom_finalizer(java_handle_t *h, Finalizer::FinalizerFunc f, void *data)
275 {
276         MutexLocker l(final_mutex);
277
278         GC_finalization_proc ofinal = 0;
279         void *odata = 0;
280
281         GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, &ofinal, &odata);
282
283         /* There was a finalizer -- reinstall it. We do not want to
284            disrupt the normal finalizer operation. This is thread-safe
285            because the other finalizer is only installed at object
286            creation time. */
287         if (ofinal && ofinal != custom_finalizer_handler)
288                 GC_REGISTER_FINALIZER_NO_ORDER(LLNI_DIRECT(h), ofinal, odata, 0, 0);
289
290         typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
291         std::pair<MI, MI> r = final_map.equal_range(h);
292         for (MI it = r.first; it != r.second; ++it)
293                 if (it->second.f == f)
294                         return it->second.data;
295         final_map.insert(r.first, std::make_pair(h, FinalizerData(f, data)));
296         return data;
297 }
298
299 /* reinstall_custom_finalizer **************************************************
300
301    Arranges for the custom finalizers to be called after the Java
302    finalizer, possibly much later, because the object needs to become
303    unreachable.
304
305 *******************************************************************************/
306
307 void Finalizer::reinstall_custom_finalizer(java_handle_t *h)
308 {
309         MutexLocker l(final_mutex);
310         std::multimap<java_handle_t *, FinalizerData>::iterator it = final_map.find(h);
311         if (it == final_map.end())
312                 return;
313
314         GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, 0, 0);
315 }
316 #endif
317
318 /*
319  * These are local overrides for various environment variables in Emacs.
320  * Please do not remove this and leave it at the end of the file, where
321  * Emacs will automagically detect them.
322  * ---------------------------------------------------------------------
323  * Local variables:
324  * mode: c++
325  * indent-tabs-mode: t
326  * c-basic-offset: 4
327  * tab-width: 4
328  * End:
329  */