1 /* src/vm/finalizer.cpp - finalizer linked list and thread
3 Copyright (C) 1996-2011
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
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.
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.
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
32 #include "mm/memory.hpp"
34 #include "threads/condition.hpp"
35 #include "threads/mutex.hpp"
36 #include "threads/thread.hpp"
37 #include "threads/lock.hpp"
39 #include "vm/jit/builtin.hpp"
40 #include "vm/exceptions.hpp"
41 #include "vm/global.h"
42 #include "vm/options.h"
45 #include "vm/jit/asmpart.h"
47 #include "finalizer.hpp"
51 #if defined(ENABLE_GC_BOEHM)
52 # include "mm/boehm-gc/include/gc.h"
55 /* global variables ***********************************************************/
57 #if defined(ENABLE_THREADS)
58 static Mutex *finalizer_thread_mutex;
59 static Condition *finalizer_thread_cond;
64 /* finalizer_init **************************************************************
66 Initializes the finalizer global lock and the linked list.
68 *******************************************************************************/
70 bool finalizer_init(void)
72 TRACESUBSYSTEMINITIALIZATION("finalizer_init");
74 #if defined(ENABLE_THREADS)
75 finalizer_thread_mutex = new Mutex();
76 finalizer_thread_cond = new Condition();
85 /* finalizer_thread ************************************************************
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.
91 *******************************************************************************/
93 #if defined(ENABLE_THREADS)
94 static void finalizer_thread(void)
97 /* get the lock on the finalizer mutex, so we can call wait */
99 finalizer_thread_mutex->lock();
101 /* wait forever on that condition till we are signaled */
103 finalizer_thread_cond->wait(finalizer_thread_mutex);
107 finalizer_thread_mutex->unlock();
110 if (opt_DebugFinalizer)
111 log_println("[finalizer thread : status=awake]");
114 /* and call the finalizers */
116 gc_invoke_finalizers();
119 if (opt_DebugFinalizer)
120 log_println("[finalizer thread : status=sleeping]");
127 /* finalizer_start_thread ******************************************************
129 Starts the finalizer thread.
131 *******************************************************************************/
133 #if defined(ENABLE_THREADS)
134 bool finalizer_start_thread(void)
138 name = utf_new_char("Finalizer");
140 if (!threads_thread_start_internal(name, finalizer_thread))
143 /* everything's ok */
150 /* finalizer_notify ************************************************************
152 Notifies the finalizer thread that it should run the
153 gc_invoke_finalizers from the GC.
155 *******************************************************************************/
157 void finalizer_notify(void)
160 if (opt_DebugFinalizer)
161 log_println("[finalizer notified]");
164 #if defined(ENABLE_THREADS)
165 /* get the lock on the finalizer lock object, so we can call wait */
167 finalizer_thread_mutex->lock();
169 /* signal the finalizer thread */
171 finalizer_thread_cond->signal();
175 finalizer_thread_mutex->unlock();
177 /* if we don't have threads, just run the finalizers */
179 gc_invoke_finalizers();
184 /* finalizer_run ***************************************************************
186 Actually run the finalizer functions.
188 *******************************************************************************/
190 void finalizer_run(void *o, void *p)
195 h = (java_handle_t *) o;
197 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
198 /* XXX this is only a dirty hack to make Boehm work with handles */
200 h = LLNI_WRAP((java_object_t *) h);
203 LLNI_class_get(h, c);
206 if (opt_DebugFinalizer) {
208 log_print("[finalizer running : o=%p p=%p class=", o, p);
215 /* call the finalizer function */
217 (void) vm_call_method(c->finalizer, h);
220 if (opt_DebugFinalizer && (exceptions_get_exception() != NULL)) {
221 log_println("[finalizer exception]");
222 exceptions_print_stacktrace();
226 /* if we had an exception in the finalizer, ignore it */
228 exceptions_clear_exception();
230 #if defined(ENABLE_GC_BOEHM)
231 Finalizer::reinstall_custom_finalizer(h);
237 #if defined(ENABLE_GC_BOEHM)
239 struct FinalizerData {
240 Finalizer::FinalizerFunc f;
242 FinalizerData(Finalizer::FinalizerFunc f, void *data): f(f), data(data) { }
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;
250 static void custom_finalizer_handler(void *object, void *data)
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);
262 final_map.erase(it_first, it);
265 /* attach_custom_finalizer *****************************************************
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
272 *******************************************************************************/
274 void *Finalizer::attach_custom_finalizer(java_handle_t *h, Finalizer::FinalizerFunc f, void *data)
276 MutexLocker l(final_mutex);
278 GC_finalization_proc ofinal = 0;
281 GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, &ofinal, &odata);
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
287 if (ofinal && ofinal != custom_finalizer_handler)
288 GC_REGISTER_FINALIZER_NO_ORDER(LLNI_DIRECT(h), ofinal, odata, 0, 0);
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)));
299 /* reinstall_custom_finalizer **************************************************
301 Arranges for the custom finalizers to be called after the Java
302 finalizer, possibly much later, because the object needs to become
305 *******************************************************************************/
307 void Finalizer::reinstall_custom_finalizer(java_handle_t *h)
309 MutexLocker l(final_mutex);
310 std::multimap<java_handle_t *, FinalizerData>::iterator it = final_map.find(h);
311 if (it == final_map.end())
314 GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, 0, 0);
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 * ---------------------------------------------------------------------
325 * indent-tabs-mode: t