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