CACAO
finalizer.cpp
Go to the documentation of this file.
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  */
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  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 };
79 
81 {
83  if (running)
84  pending = true;
85  else {
86  running = true;
87  cond.signal();
88  }
89 }
90 
92 {
94  while (!running)
95  cond.wait(&mutex);
96  return !shutdown;
97 }
98 
100 {
102  running = pending;
103  pending = false;
104 }
105 
107 {
109  shutdown->signal();
110  shutdown = 0;
111 }
112 
114 {
115  Condition cond_shutdown;
117  if (disabled)
118  // deliberately hang forever
119  for (;;)
120  cond_shutdown.wait(&mutex);
121  running = true;
122  pending = true;
123  disabled = true;
124  shutdown = &cond_shutdown;
125  cond.signal();
126  while (shutdown)
127  cond_shutdown.wait(&mutex);
128 }
129 
130 #if defined(ENABLE_GC_BOEHM)
131 
134  void *data;
135  FinalizerData(Finalizer::FinalizerFunc f, void *data): f(f), data(data) { }
136 };
137 
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 
152 {
153  TRACESUBSYSTEMINITIALIZATION("finalizer_init");
154 
155  finalizer_thread_coord = new FinalizerThreadCoordinator;
156 
157 #if defined(ENABLE_GC_BOEHM)
158  final_map = new std::multimap<java_handle_t *, FinalizerData>;
159  final_mutex = new Mutex;
160 #endif
161 
162  /* everything's ok */
163 
164  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 static void finalizer_thread()
177 {
178  while (true) {
179  /* get the lock on the finalizer mutex, so we can call wait */
180 
181  if (!finalizer_thread_coord->accept()) {
182  finalizer_thread_coord->shutdown_ack();
183  break;
184  }
185  LOG("[finalizer thread : status=awake]" << cacao::nl);
186 
187  /* and call the finalizers */
188 
190 
191  LOG("[finalizer thread : status=sleeping]" << cacao::nl);
192  finalizer_thread_coord->done();
193  }
194 }
195 
196 
197 /* finalizer_start_thread ******************************************************
198 
199  Starts the finalizer thread.
200 
201 *******************************************************************************/
202 
204 {
205  Utf8String name = Utf8String::from_utf8("Finalizer");
206 
208  return false;
209 
210  /* everything's ok */
211 
212  return true;
213 }
214 
216 {
217  finalizer_thread_coord->join();
218 }
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 
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  finalizer_thread_coord->request();
235 
236 #else
237  /* if we don't have threads, just run the finalizers */
238 
240 #endif
241 }
242 
243 
244 /* finalizer_run ***************************************************************
245 
246  Actually run the finalizer functions.
247 
248 *******************************************************************************/
249 
250 void finalizer_run(void *o, void *p)
251 {
252  java_handle_t *h;
253  classinfo *c;
254 
255  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  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  (void) vm_call_method(c->finalizer, h);
274 
275  if (exceptions_get_exception() != NULL) {
276  LOG("[finalizer exception]" << cacao::nl);
278  }
279 
280  /* if we had an exception in the finalizer, ignore it */
281 
283 
284 #if defined(ENABLE_GC_BOEHM)
286 #endif
287 }
288 
289 #if defined(ENABLE_GC_BOEHM)
290 
291 static void custom_finalizer_handler(void *object, void *data)
292 {
293  typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
294  java_handle_t *hdl = (java_handle_t *) object;
295  MutexLocker l(*final_mutex);
296  MI it_first = final_map->lower_bound(hdl), it = it_first;
297  assert(it->first == hdl);
298  for (; it->first == hdl; ++it) {
299  final_mutex->unlock();
300  it->second.f(hdl, it->second.data);
301  final_mutex->lock();
302  }
303  final_map->erase(it_first, it);
304 }
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 
316 {
317  MutexLocker l(*final_mutex);
318 
319  GC_finalization_proc ofinal = 0;
320  void *odata = 0;
321 
322  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  if (ofinal && ofinal != custom_finalizer_handler)
329  GC_REGISTER_FINALIZER_NO_ORDER(LLNI_DIRECT(h), ofinal, odata, 0, 0);
330 
331  typedef std::multimap<java_handle_t *, FinalizerData>::iterator MI;
332  std::pair<MI, MI> r = final_map->equal_range(h);
333  for (MI it = r.first; it != r.second; ++it)
334  if (it->second.f == f)
335  return it->second.data;
336  final_map->insert(r.first, std::make_pair(h, FinalizerData(f, data)));
337  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 
349 {
350  MutexLocker l(*final_mutex);
351  std::multimap<java_handle_t *, FinalizerData>::iterator it = final_map->find(h);
352  if (it == final_map->end())
353  return;
354 
355  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  */
void exceptions_print_stacktrace(void)
void signal()
Restarts one of the threads that are waiting on this condition variable.
#define DEBUG(STMT)
Execute debug statements in your current module.
Definition: Debug.hpp:125
bool threads_thread_start_internal(Utf8String name, functionptr f)
Definition: thread.cpp:402
typedef void(JNICALL *jvmtiEventSingleStep)(jvmtiEnv *jvmti_env
void(* FinalizerFunc)(java_handle_t *h, void *data)
Definition: finalizer.hpp:32
void finalizer_join_thread()
Definition: finalizer.cpp:215
Dummy implementation of a mutex.
Definition: mutex-none.hpp:33
Mutex * final_mutex
Definition: finalizer.cpp:138
java_handle_t * vm_call_method(methodinfo *m, java_handle_t *o,...)
static void * attach_custom_finalizer(java_handle_t *h, FinalizerFunc f, void *data)
Definition: finalizer.cpp:315
methodinfo * finalizer
Definition: class.hpp:123
JNIEnv jclass jobject const char * name
Definition: jvmti.h:312
FinalizerData(Finalizer::FinalizerFunc f, void *data)
Definition: finalizer.cpp:135
std::multimap< java_handle_t *, FinalizerData > * final_map
Definition: finalizer.cpp:141
#define TRACESUBSYSTEMINITIALIZATION(text)
Definition: options.hpp:258
static Mutex lock
Definition: atomic.cpp:34
void gc_invoke_finalizers(void)
Definition: gc.c:513
#define LLNI_class_get(obj, variable)
Definition: llni.hpp:60
#define LLNI_WRAP(obj)
Definition: llni.hpp:51
bool finalizer_start_thread()
Definition: finalizer.cpp:203
static Utf8String from_utf8(const char *, size_t)
Definition: utf8.cpp:335
Dummy condition variable.
static void finalizer_thread()
Definition: finalizer.cpp:176
Helper class used to implicitly acquire and release a mutex within a method scope.
Definition: mutex.hpp:42
void finalizer_run(void *o, void *p)
Definition: finalizer.cpp:250
Finalizer::FinalizerFunc f
Definition: finalizer.cpp:133
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
bool finalizer_init()
Definition: finalizer.cpp:151
static void custom_finalizer_handler(void *object, void *data)
Definition: finalizer.cpp:291
void finalizer_notify()
Definition: finalizer.cpp:227
static FinalizerThreadCoordinator * finalizer_thread_coord
Definition: finalizer.cpp:78
void exceptions_clear_exception(void)
Definition: exceptions.cpp:127
java_handle_t * exceptions_get_exception(void)
Definition: exceptions.cpp:76
void unlock()
Unlocks the given mutex object and checks for errors.
Definition: mutex-none.hpp:36
#define LLNI_DIRECT(hdl)
Definition: llni.hpp:54
Nl nl
Definition: OStream.cpp:56
void wait(Mutex *mutex)
Waits for the condition variable.
void lock()
Locks the given mutex object and checks for errors.
Definition: mutex-none.hpp:35
static void reinstall_custom_finalizer(java_handle_t *h)
Definition: finalizer.cpp:348