Line data Source code
1 : /* src/threads/threadlist.cpp - thread list maintenance
2 :
3 : Copyright (C) 1996-2013
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 : #include <algorithm>
30 : #include <functional>
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 : ThreadList *ThreadList::the_threadlist = 0;
42 :
43 : /**
44 : * Dumps info for all threads running in the VM. This function is
45 : * called when SIGQUIT (<ctrl>-\) is sent to the VM.
46 : */
47 0 : void ThreadList::dump_threads()
48 : {
49 : // XXX we should stop the world here and remove explicit
50 : // thread suspension from the loop below.
51 : // Lock the thread lists.
52 0 : MutexLocker lock(_mutex);
53 :
54 0 : printf("Full thread dump CACAO "VERSION_FULL":\n");
55 :
56 : // Iterate over all started threads.
57 0 : threadobject* self = THREADOBJECT;
58 0 : for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
59 0 : threadobject* t = *it;
60 :
61 : // Ignore threads which are in state NEW.
62 0 : if (t->state == THREAD_STATE_NEW)
63 0 : continue;
64 :
65 : /* Suspend the thread (and ignore return value). */
66 :
67 0 : if (t != self)
68 0 : (void) threads_suspend_thread(t, SUSPEND_REASON_DUMP);
69 :
70 : /* Print thread info. */
71 :
72 0 : printf("\n");
73 0 : thread_print_info(t);
74 0 : printf("\n");
75 :
76 : /* Print trace of thread. */
77 :
78 0 : stacktrace_print_of_thread(t);
79 :
80 : /* Resume the thread (and ignore return value). */
81 :
82 0 : if (t != self)
83 0 : (void) threads_resume_thread(t, SUSPEND_REASON_DUMP);
84 0 : }
85 0 : }
86 :
87 :
88 : /**
89 : * Fills the passed list with all currently active threads. Creating a copy
90 : * of the thread list here, is the only way to ensure we do not end up in a
91 : * dead-lock when iterating over the list.
92 : *
93 : * @param list list class to be filled
94 : */
95 0 : void ThreadList::get_active_threads(List<threadobject*> &list)
96 : {
97 0 : MutexLocker lock(_mutex);
98 :
99 : // Use the assignment operator to create a copy of the thread list.
100 0 : list = _active_thread_list;
101 0 : }
102 :
103 :
104 : /**
105 : * Fills the passed list with all currently active threads which should be
106 : * visible to Java. Creating a copy of the thread list here, is the only way
107 : * to ensure we do not end up in a dead-lock when iterating over the list.
108 : *
109 : * @param list list class to be filled
110 : */
111 0 : void ThreadList::get_active_java_threads(List<threadobject*> &list)
112 : {
113 0 : MutexLocker lock(_mutex);
114 :
115 : // Iterate over all active threads.
116 0 : for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
117 0 : threadobject* t = *it;
118 :
119 : // We skip internal threads.
120 0 : if (t->flags & THREAD_FLAG_INTERNAL)
121 0 : continue;
122 :
123 0 : list.push_back(t);
124 0 : }
125 0 : }
126 :
127 :
128 : /**
129 : * Get the next free thread object.
130 : *
131 : * Gets the next free thread object and a thread index for it.
132 : * The results are stored into the passed pointers.
133 : *
134 : * If no free thread is available `*thread' will contain NULL.
135 : * `*index' will always, even if no free thread is available,
136 : * contain a valid index you can use for a new thread.
137 : */
138 793 : void ThreadList::get_free_thread(threadobject **thread, int32_t *index) {
139 793 : MutexLocker lock(_mutex);
140 :
141 : // Do we have free threads in the free-list?
142 793 : if (_free_thread_list.empty() == false) {
143 : // Yes, get the index and remove it from the free list.
144 0 : threadobject* t = _free_thread_list.front();
145 0 : _free_thread_list.pop_front();
146 :
147 0 : *thread = t;
148 0 : *index = t->index;
149 : } else {
150 793 : *thread = NULL;
151 793 : *index = ++_last_index;
152 0 : }
153 793 : }
154 :
155 :
156 : /**
157 : * Return the number of daemon threads visible to Java.
158 : *
159 : * NOTE: This function does a linear-search over the threads list,
160 : * because it is only used by the management interface.
161 : *
162 : * @return number of daemon threads
163 : */
164 0 : int32_t ThreadList::get_number_of_daemon_java_threads(void)
165 : {
166 0 : int number = 0;
167 :
168 : // Lock the thread lists.
169 0 : MutexLocker lock(_mutex);
170 :
171 : // Iterate over all active threads.
172 0 : for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
173 0 : threadobject* t = *it;
174 :
175 : // We skip internal threads.
176 0 : if (t->flags & THREAD_FLAG_INTERNAL)
177 0 : continue;
178 :
179 0 : if (thread_is_daemon(t))
180 0 : number++;
181 : }
182 :
183 0 : return number;
184 : }
185 :
186 :
187 : /**
188 : * Return the number of non-daemon threads.
189 : *
190 : * NOTE: This function does a linear-search over the threads list,
191 : * because it is only used for joining the threads.
192 : *
193 : * @return number of non daemon threads
194 : */
195 131 : int32_t ThreadList::get_number_of_non_daemon_threads(void)
196 : {
197 131 : MutexLocker lock(_mutex);
198 :
199 131 : int nondaemons = 0;
200 :
201 655 : for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
202 524 : threadobject* t = *it;
203 :
204 524 : if (!thread_is_daemon(t))
205 131 : nondaemons++;
206 : }
207 :
208 131 : return nondaemons;
209 : }
210 :
211 : // Comparator class.
212 : class comparator : public std::binary_function<threadobject*, int32_t, bool> {
213 : public:
214 15 : bool operator() (const threadobject* t, const int32_t index) const {
215 15 : return (t->index == index);
216 : }
217 : };
218 :
219 : /**
220 : * Return the thread object with the given index.
221 : *
222 : * @return thread object
223 : */
224 5 : threadobject* ThreadList::get_thread_by_index(int32_t index)
225 : {
226 5 : MutexLocker lock(_mutex);
227 :
228 5 : List<threadobject*>::iterator it = find_if(_active_thread_list.begin(), _active_thread_list.end(), std::bind2nd(comparator(), index));
229 :
230 : // No thread found.
231 5 : if (it == _active_thread_list.end()) {
232 0 : return NULL;
233 : }
234 :
235 5 : threadobject* t = *it;
236 :
237 : // The thread found is in state new.
238 5 : if (t->state == THREAD_STATE_NEW) {
239 1 : return NULL;
240 : }
241 :
242 4 : return t;
243 : }
244 :
245 :
246 : /**
247 : * Return the Java thread object from the given thread object.
248 : *
249 : * @return Java thread object
250 : */
251 0 : threadobject* ThreadList::get_thread_from_java_object(java_handle_t* h)
252 : {
253 0 : MutexLocker lock(_mutex);
254 :
255 0 : for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
256 0 : threadobject* t = *it;
257 :
258 : bool equal;
259 0 : LLNI_equals(t->object, h, equal);
260 :
261 0 : if (equal == true) {
262 0 : return t;
263 : }
264 : }
265 :
266 0 : return NULL;
267 : }
268 :
269 282 : void ThreadList::deactivate_thread(threadobject *t)
270 : {
271 282 : MutexLocker lock(_mutex);
272 :
273 282 : remove_from_active_thread_list(t);
274 282 : threads_impl_clear_heap_pointers(t); // allow it to be garbage collected
275 282 : }
276 :
277 : /**
278 : * Release the thread.
279 : *
280 : * @return free thread index
281 : */
282 0 : void ThreadList::release_thread(threadobject* t, bool needs_deactivate)
283 : {
284 0 : MutexLocker lock(_mutex);
285 :
286 0 : if (needs_deactivate)
287 : // Move thread from active thread list to free thread list.
288 0 : remove_from_active_thread_list(t);
289 : else
290 0 : assert(!t->is_in_active_list);
291 :
292 0 : _free_thread_list.push_back(t);
293 0 : }
294 :
295 :
296 : /*
297 : * These are local overrides for various environment variables in Emacs.
298 : * Please do not remove this and leave it at the end of the file, where
299 : * Emacs will automagically detect them.
300 : * ---------------------------------------------------------------------
301 : * Local variables:
302 : * mode: c++
303 : * indent-tabs-mode: t
304 : * c-basic-offset: 4
305 : * tab-width: 4
306 : * End:
307 : * vim:noexpandtab:sw=4:ts=4:
308 : */
|