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