* src/toolbox/hashtable.hpp: Added preliminary C++ hashtable class.
[cacao.git] / src / threads / threadlist.cpp
1 /* src/threads/threadlist.cpp - thread list
2
3    Copyright (C) 2008, 2009
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 <stdint.h>
29
30 #include <algorithm>
31
32 #include "threads/mutex.hpp"
33 #include "threads/threadlist.hpp"
34 #include "threads/thread.hpp"
35
36 #include "toolbox/list.hpp"
37 #include "toolbox/logging.hpp"
38
39 #include "vm/jit/stacktrace.hpp"
40
41
42 /* class variables */
43
44 Mutex               ThreadList::_mutex;                // a mutex for all thread lists
45
46 List<threadobject*> ThreadList::_active_thread_list;   // list of active threads
47 List<threadobject*> ThreadList::_free_thread_list;     // list of free threads
48 List<int32_t>       ThreadList::_free_index_list;      // list of free thread indexes
49
50 int32_t             ThreadList::_number_of_started_java_threads;
51 int32_t             ThreadList::_number_of_active_java_threads;
52 int32_t             ThreadList::_peak_of_active_java_threads;
53 int32_t             ThreadList::_number_of_non_daemon_threads;
54
55
56 /**
57  * Dumps info for all threads running in the VM.  This function is
58  * called when SIGQUIT (<ctrl>-\) is sent to the VM.
59  */
60 void ThreadList::dump_threads()
61 {
62         // XXX we should stop the world here
63         // Lock the thread lists.
64         lock();
65
66         printf("Full thread dump CACAO "VERSION":\n");
67
68         // Iterate over all started threads.
69         for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
70                 threadobject* t = *it;
71
72                 // Ignore threads which are in state NEW.
73                 if (t->state == THREAD_STATE_NEW)
74                         continue;
75
76 #if defined(ENABLE_GC_CACAO)
77                 /* Suspend the thread. */
78                 /* XXX Is the suspend reason correct? */
79
80                 if (threads_suspend_thread(t, SUSPEND_REASON_JNI) == false)
81                         vm_abort("threads_dump: threads_suspend_thread failed");
82 #endif
83
84                 /* Print thread info. */
85
86                 printf("\n");
87                 thread_print_info(t);
88                 printf("\n");
89
90                 /* Print trace of thread. */
91
92                 stacktrace_print_of_thread(t);
93
94 #if defined(ENABLE_GC_CACAO)
95                 /* Resume the thread. */
96
97                 if (threads_resume_thread(t) == false)
98                         vm_abort("threads_dump: threads_resume_thread failed");
99 #endif
100         }
101
102         // Unlock the thread lists.
103         unlock();
104 }
105
106
107 /**
108  * Fills the passed list with all currently active threads. Creating a copy
109  * of the thread list here, is the only way to ensure we do not end up in a
110  * dead-lock when iterating over the list.
111  *
112  * @param list list class to be filled
113  */
114 void ThreadList::get_active_threads(List<threadobject*> &list)
115 {
116         // Lock the thread lists.
117         lock();
118
119         // Use the assignment operator to create a copy of the thread list.
120         list = _active_thread_list;
121
122         // Unlock the thread lists.
123         unlock();
124 }
125
126
127 /**
128  * Fills the passed list with all currently active threads which should be
129  * visible to Java. Creating a copy of the thread list here, is the only way
130  * to ensure we do not end up in a dead-lock when iterating over the list.
131  *
132  * @param list list class to be filled
133  */
134 void ThreadList::get_active_java_threads(List<threadobject*> &list)
135 {
136         // Lock the thread lists.
137         lock();
138
139         // Iterate over all active threads.
140         for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
141                 threadobject* t = *it;
142
143                 // We skip internal threads.
144                 if (t->flags & THREAD_FLAG_INTERNAL)
145                         continue;
146
147                 list.push_back(t);
148         }
149
150         // Unlock the thread lists.
151         unlock();
152 }
153
154
155 /**
156  * Return a free thread object.
157  *
158  * @return free thread object or NULL if none available
159  */
160 threadobject* ThreadList::get_free_thread()
161 {
162         threadobject* t = NULL;
163
164         // Do we have free threads in the free-list?
165         if (_free_thread_list.empty() == false) {
166                 // Yes, get the index and remove it from the free list.
167                 threadobject* t = _free_thread_list.front();
168                 _free_thread_list.remove(t);
169         }
170
171         return t;
172 }
173
174
175 /**
176  * Return a free thread index.
177  *
178  * @return free thread index
179  */
180 int32_t ThreadList::get_free_thread_index()
181 {
182         int32_t index;
183
184         // Do we have free indexes in the free-list?
185         if (_free_index_list.empty() == false) {
186                 // Yes, get the index and remove it from the free list.
187                 index = _free_index_list.front();
188                 _free_index_list.remove(index);
189         }
190         else {
191                 // Get a new the thread index.
192                 index = _active_thread_list.size() + 1;
193         }
194
195         return index;
196 }
197
198
199 /**
200  * Return the number of daemon threads visible to Java.
201  *
202  * NOTE: This function does a linear-search over the threads list,
203  *       because it is only used by the management interface.
204  *
205  * @return number of daemon threads
206  */
207 int32_t ThreadList::get_number_of_daemon_java_threads(void)
208 {
209         int number = 0;
210
211         // Lock the thread lists.
212         lock();
213
214         // Iterate over all active threads.
215         for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
216                 threadobject* t = *it;
217
218                 // We skip internal threads.
219                 if (t->flags & THREAD_FLAG_INTERNAL)
220                         continue;
221
222                 if (thread_is_daemon(t))
223                         number++;
224         }
225
226         // Unlock the thread lists.
227         unlock();
228
229         return number;
230 }
231
232
233 /**
234  * Return the number of non-daemon threads.
235  *
236  * NOTE: This function does a linear-search over the threads list,
237  *       because it is only used for joining the threads.
238  *
239  * @return number of non daemon threads
240  */
241 int32_t ThreadList::get_number_of_non_daemon_threads(void)
242 {
243         int nondaemons = 0;
244
245         lock();
246
247         for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
248                 threadobject* t = *it;
249
250                 if (!thread_is_daemon(t))
251                         nondaemons++;
252         }
253
254         unlock();
255
256         return nondaemons;
257 }
258
259
260 /**
261  * Return the thread object with the given index.
262  *
263  * @return thread object
264  */
265 threadobject* ThreadList::get_thread_by_index(int32_t index)
266 {
267         lock();
268
269         List<threadobject*>::iterator it = find_if(_active_thread_list.begin(), _active_thread_list.end(), std::bind2nd(comparator(), index));
270
271         // No thread found.
272         if (it == _active_thread_list.end()) {
273                 unlock();
274                 return NULL;
275         }
276
277         threadobject* t = *it;
278
279         // The thread found is in state new.
280         if (t->state == THREAD_STATE_NEW) {
281                 unlock();
282                 return NULL;
283         }
284
285         unlock();
286         return t;
287 }
288
289
290 /**
291  * Return the Java thread object from the given thread object.
292  *
293  * @return Java thread object
294  */
295 threadobject* ThreadList::get_thread_from_java_object(java_handle_t* h)
296 {
297         List<threadobject*>::iterator it;
298         threadobject* t;
299         bool          equal;
300
301         lock();
302
303         for (it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
304                 t = *it;
305
306                 LLNI_equals(t->object, h, equal);
307
308                 if (equal == true) {
309                         unlock();
310                         return t;
311                 }
312         }
313
314         unlock();
315
316         return NULL;
317 }
318
319
320 /**
321  * Release the thread.
322  *
323  * @return free thread index
324  */
325 void ThreadList::release_thread(threadobject* t)
326 {
327         lock();
328
329         // Move thread from active thread list to free thread list.
330         remove_from_active_thread_list(t);
331         add_to_free_thread_list(t);
332
333         // Add thread index to free index list.
334         add_to_free_index_list(t->index);
335
336         unlock();
337 }
338
339
340 /* C interface functions ******************************************************/
341
342 extern "C" {
343         void ThreadList_lock() { ThreadList::lock(); }
344         void ThreadList_unlock() { ThreadList::unlock(); }
345         void ThreadList_dump_threads() { ThreadList::dump_threads(); }
346         void ThreadList_release_thread(threadobject* t) { ThreadList::release_thread(t); }
347         threadobject* ThreadList_get_free_thread() { return ThreadList::get_free_thread(); }
348         int32_t ThreadList_get_free_thread_index() { return ThreadList::get_free_thread_index(); }
349         void ThreadList_add_to_active_thread_list(threadobject* t) { ThreadList::add_to_active_thread_list(t); }
350         threadobject* ThreadList_get_thread_by_index(int32_t index) { return ThreadList::get_thread_by_index(index); }
351         threadobject* ThreadList_get_main_thread() { return ThreadList::get_main_thread(); }
352         threadobject* ThreadList_get_thread_from_java_object(java_handle_t* h) { return ThreadList::get_thread_from_java_object(h); }
353
354         int32_t ThreadList_get_number_of_non_daemon_threads() { return ThreadList::get_number_of_non_daemon_threads(); }
355 }
356
357 /*
358  * These are local overrides for various environment variables in Emacs.
359  * Please do not remove this and leave it at the end of the file, where
360  * Emacs will automagically detect them.
361  * ---------------------------------------------------------------------
362  * Local variables:
363  * mode: c++
364  * indent-tabs-mode: t
365  * c-basic-offset: 4
366  * tab-width: 4
367  * End:
368  * vim:noexpandtab:sw=4:ts=4:
369  */