Line data Source code
1 : /* src/vm/finalizer.cpp - finalizer linked list and thread
2 :
3 : Copyright (C) 1996-2014
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 : #include "finalizer.hpp"
26 : #include "config.h" // for ENABLE_THREADS, etc
27 : #include <assert.h> // for assert
28 : #include <stdlib.h> // for NULL
29 : #include <map> // for multimap, _Rb_tree_iterator, etc
30 : #include <utility> // for pair, make_pair
31 : #include "mm/gc.hpp" // for gc_invoke_finalizers
32 : #include "native/llni.hpp" // for LLNI_DIRECT, LLNI_class_get
33 : #include "threads/condition.hpp" // for Condition
34 : #include "threads/mutex.hpp" // for Mutex, MutexLocker
35 : #include "threads/thread.hpp"
36 : #include "toolbox/OStream.hpp" // for OStream, nl
37 : #include "toolbox/logging.hpp" // for LOG
38 : #include "utf8.hpp" // for Utf8String
39 : #include "vm/class.hpp" // for operator<<, classinfo
40 : #include "vm/exceptions.hpp" // for exceptions_clear_exception, etc
41 : #include "vm/global.hpp" // for java_handle_t
42 : #include "vm/options.hpp"
43 : #include "vm/vm.hpp" // for vm_call_method
44 :
45 : #if defined(ENABLE_GC_BOEHM)
46 : # include "mm/boehm-gc/include/gc.h"
47 : #endif
48 :
49 : #define DEBUG_NAME "finalizer"
50 :
51 : /* global variables ***********************************************************/
52 :
53 : /***
54 : * Simple synchronization helper for coordinating sets of finalizer runs and
55 : * requests from concurrent threads. It assumes that there is only a single
56 : * finalizer thread.
57 : */
58 : class FinalizerThreadCoordinator {
59 : Mutex mutex;
60 : Condition cond; // finalizer thread blocks on this cv
61 : Condition *shutdown; // thread requesting shutdown blocks on this one
62 : bool running; // thread requested to run finalizers
63 : bool pending; // thread should continue running finalizers
64 : bool disabled; // thread has been requested to stop
65 :
66 : public:
67 163 : FinalizerThreadCoordinator(): shutdown(0), running(false), pending(false), disabled(false) { }
68 :
69 : // Called by finalizer thread
70 : bool accept();
71 : void done();
72 : void shutdown_ack();
73 :
74 : // Called by requestor threads
75 : void request();
76 : void join();
77 : };
78 : static FinalizerThreadCoordinator *finalizer_thread_coord;
79 :
80 48 : void FinalizerThreadCoordinator::request()
81 : {
82 48 : MutexLocker lock(mutex);
83 48 : if (running)
84 2 : pending = true;
85 : else {
86 46 : running = true;
87 46 : cond.signal();
88 0 : }
89 48 : }
90 :
91 211 : bool FinalizerThreadCoordinator::accept()
92 : {
93 211 : MutexLocker lock(mutex);
94 609 : while (!running)
95 209 : cond.wait(&mutex);
96 189 : return !shutdown;
97 : }
98 :
99 48 : void FinalizerThreadCoordinator::done()
100 : {
101 48 : MutexLocker lock(mutex);
102 48 : running = pending;
103 48 : pending = false;
104 48 : }
105 :
106 141 : void FinalizerThreadCoordinator::shutdown_ack()
107 : {
108 141 : MutexLocker lock(mutex);
109 141 : shutdown->signal();
110 141 : shutdown = 0;
111 141 : }
112 :
113 141 : void FinalizerThreadCoordinator::join()
114 : {
115 141 : Condition cond_shutdown;
116 141 : MutexLocker lock(mutex);
117 141 : if (disabled)
118 : // deliberately hang forever
119 0 : for (;;)
120 0 : cond_shutdown.wait(&mutex);
121 141 : running = true;
122 141 : pending = true;
123 141 : disabled = true;
124 141 : shutdown = &cond_shutdown;
125 141 : cond.signal();
126 423 : while (shutdown)
127 141 : cond_shutdown.wait(&mutex);
128 141 : }
129 :
130 : #if defined(ENABLE_GC_BOEHM)
131 :
132 : struct FinalizerData {
133 : Finalizer::FinalizerFunc f;
134 : void *data;
135 20506 : FinalizerData(Finalizer::FinalizerFunc f, void *data): f(f), data(data) { }
136 : };
137 :
138 : Mutex *final_mutex;
139 : // final_map contains registered custom finalizers for a given Java
140 : // object. Must be accessed with held final_mutex.
141 : std::multimap<java_handle_t *, FinalizerData> *final_map;
142 :
143 : #endif
144 :
145 : /* finalizer_init **************************************************************
146 :
147 : Initializes the finalizer global lock and the linked list.
148 :
149 : *******************************************************************************/
150 :
151 163 : bool finalizer_init()
152 : {
153 163 : TRACESUBSYSTEMINITIALIZATION("finalizer_init");
154 :
155 163 : finalizer_thread_coord = new FinalizerThreadCoordinator;
156 :
157 : #if defined(ENABLE_GC_BOEHM)
158 163 : final_map = new std::multimap<java_handle_t *, FinalizerData>;
159 163 : final_mutex = new Mutex;
160 : #endif
161 :
162 : /* everything's ok */
163 :
164 163 : return true;
165 : }
166 :
167 :
168 : /* finalizer_thread ************************************************************
169 :
170 : This thread waits on an object for a notification and the runs the
171 : finalizers (finalizer thread). This is necessary because of a
172 : possible deadlock in the GC.
173 :
174 : *******************************************************************************/
175 :
176 211 : static void finalizer_thread()
177 : {
178 48 : while (true) {
179 : /* get the lock on the finalizer mutex, so we can call wait */
180 :
181 211 : if (!finalizer_thread_coord->accept()) {
182 141 : finalizer_thread_coord->shutdown_ack();
183 : break;
184 : }
185 : LOG("[finalizer thread : status=awake]" << cacao::nl);
186 :
187 : /* and call the finalizers */
188 :
189 48 : gc_invoke_finalizers();
190 :
191 : LOG("[finalizer thread : status=sleeping]" << cacao::nl);
192 48 : finalizer_thread_coord->done();
193 : }
194 141 : }
195 :
196 :
197 : /* finalizer_start_thread ******************************************************
198 :
199 : Starts the finalizer thread.
200 :
201 : *******************************************************************************/
202 :
203 163 : bool finalizer_start_thread()
204 : {
205 163 : Utf8String name = Utf8String::from_utf8("Finalizer");
206 :
207 163 : if (!threads_thread_start_internal(name, finalizer_thread))
208 0 : return false;
209 :
210 : /* everything's ok */
211 :
212 163 : return true;
213 : }
214 :
215 141 : void finalizer_join_thread()
216 : {
217 141 : finalizer_thread_coord->join();
218 141 : }
219 :
220 : /* finalizer_notify ************************************************************
221 :
222 : Notifies the finalizer thread that it should run the
223 : gc_invoke_finalizers from the GC.
224 :
225 : *******************************************************************************/
226 :
227 48 : void finalizer_notify()
228 : {
229 : LOG("[finalizer notified]" << cacao::nl);
230 :
231 : #if defined(ENABLE_THREADS)
232 : /* get the lock on the finalizer lock object, so we can call wait */
233 :
234 48 : finalizer_thread_coord->request();
235 :
236 : #else
237 : /* if we don't have threads, just run the finalizers */
238 :
239 : gc_invoke_finalizers();
240 : #endif
241 48 : }
242 :
243 :
244 : /* finalizer_run ***************************************************************
245 :
246 : Actually run the finalizer functions.
247 :
248 : *******************************************************************************/
249 :
250 18287 : void finalizer_run(void *o, void *p)
251 : {
252 : java_handle_t *h;
253 : classinfo *c;
254 :
255 18287 : h = (java_handle_t *) o;
256 :
257 : #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
258 : /* XXX this is only a dirty hack to make Boehm work with handles */
259 :
260 : h = LLNI_WRAP((java_object_t *) h);
261 : #endif
262 :
263 18287 : LLNI_class_get(h, c);
264 :
265 : LOG("[finalizer running :"
266 : << " o=" << o
267 : << " p=" << p
268 : << " class=" << c
269 : << "]" << cacao::nl);
270 :
271 : /* call the finalizer function */
272 :
273 18287 : (void) vm_call_method(c->finalizer, h);
274 :
275 18287 : if (exceptions_get_exception() != NULL) {
276 : LOG("[finalizer exception]" << cacao::nl);
277 : DEBUG(exceptions_print_stacktrace());
278 : }
279 :
280 : /* if we had an exception in the finalizer, ignore it */
281 :
282 18287 : exceptions_clear_exception();
283 :
284 : #if defined(ENABLE_GC_BOEHM)
285 18287 : Finalizer::reinstall_custom_finalizer(h);
286 : #endif
287 18287 : }
288 :
289 : #if defined(ENABLE_GC_BOEHM)
290 :
291 0 : static void custom_finalizer_handler(void *object, void *data)
292 : {
293 : typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
294 0 : java_handle_t *hdl = (java_handle_t *) object;
295 0 : MutexLocker l(*final_mutex);
296 0 : MI it_first = final_map->lower_bound(hdl), it = it_first;
297 0 : assert(it->first == hdl);
298 0 : for (; it->first == hdl; ++it) {
299 0 : final_mutex->unlock();
300 0 : it->second.f(hdl, it->second.data);
301 0 : final_mutex->lock();
302 : }
303 0 : final_map->erase(it_first, it);
304 0 : }
305 :
306 : /* attach_custom_finalizer *****************************************************
307 :
308 : Register a custom handler that is run when the object becomes
309 : unreachable. This is intended for internal cleanup actions. If the
310 : handler already exists, it is not registered again, and its data
311 : pointer is returned.
312 :
313 : *******************************************************************************/
314 :
315 20506 : void *Finalizer::attach_custom_finalizer(java_handle_t *h, Finalizer::FinalizerFunc f, void *data)
316 : {
317 20506 : MutexLocker l(*final_mutex);
318 :
319 20506 : GC_finalization_proc ofinal = 0;
320 20506 : void *odata = 0;
321 :
322 20506 : GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, &ofinal, &odata);
323 :
324 : /* There was a finalizer -- reinstall it. We do not want to
325 : disrupt the normal finalizer operation. This is thread-safe
326 : because the other finalizer is only installed at object
327 : creation time. */
328 20506 : if (ofinal && ofinal != custom_finalizer_handler)
329 0 : GC_REGISTER_FINALIZER_NO_ORDER(LLNI_DIRECT(h), ofinal, odata, 0, 0);
330 :
331 : typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
332 20506 : std::pair<MI, MI> r = final_map->equal_range(h);
333 20506 : for (MI it = r.first; it != r.second; ++it)
334 0 : if (it->second.f == f)
335 0 : return it->second.data;
336 20506 : final_map->insert(r.first, std::make_pair(h, FinalizerData(f, data)));
337 20506 : return data;
338 : }
339 :
340 : /* reinstall_custom_finalizer **************************************************
341 :
342 : Arranges for the custom finalizers to be called after the Java
343 : finalizer, possibly much later, because the object needs to become
344 : unreachable.
345 :
346 : *******************************************************************************/
347 :
348 18287 : void Finalizer::reinstall_custom_finalizer(java_handle_t *h)
349 : {
350 18287 : MutexLocker l(*final_mutex);
351 18287 : std::multimap<java_handle_t *, FinalizerData>::iterator it = final_map->find(h);
352 18287 : if (it == final_map->end())
353 : return;
354 :
355 0 : GC_REGISTER_FINALIZER_UNREACHABLE(LLNI_DIRECT(h), custom_finalizer_handler, 0, 0, 0);
356 : }
357 : #endif
358 :
359 : /*
360 : * These are local overrides for various environment variables in Emacs.
361 : * Please do not remove this and leave it at the end of the file, where
362 : * Emacs will automagically detect them.
363 : * ---------------------------------------------------------------------
364 : * Local variables:
365 : * mode: c++
366 : * indent-tabs-mode: t
367 : * c-basic-offset: 4
368 : * tab-width: 4
369 : * End:
370 : * vim:noexpandtab:sw=4:ts=4:
371 : */
|