* src/threads/thread.cpp: Use a finalizer to remove dead threads.
[cacao.git] / src / threads / threadlist.cpp
index 9284bdb8412cc58226563cbba8279a9e76b17ac1..0350a1620b150f24aabcda1ca07462c671cc7bb3 100644 (file)
@@ -1,6 +1,6 @@
 /* src/threads/threadlist.cpp - thread list
 
-   Copyright (C) 2008
+   Copyright (C) 2008, 2009
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 Mutex               ThreadList::_mutex;                // a mutex for all thread lists
 
-list<threadobject*> ThreadList::_active_thread_list;   // list of active threads
-list<threadobject*> ThreadList::_free_thread_list;     // list of free threads
-list<int32_t>       ThreadList::_free_index_list;      // list of free thread indexes
+List<threadobject*> ThreadList::_active_thread_list;   // list of active threads
+List<threadobject*> ThreadList::_free_thread_list;     // list of free threads
+List<int32_t>       ThreadList::_free_index_list;      // list of free thread indexes
 
+int32_t             ThreadList::_number_of_started_java_threads;
+int32_t             ThreadList::_number_of_active_java_threads;
+int32_t             ThreadList::_peak_of_active_java_threads;
 int32_t             ThreadList::_number_of_non_daemon_threads;
 
 
@@ -56,13 +59,15 @@ int32_t             ThreadList::_number_of_non_daemon_threads;
  */
 void ThreadList::dump_threads()
 {
-       // XXX we should stop the world here
+       // XXX we should stop the world here and remove explicit
+       //     thread suspension from the loop below.
        // Lock the thread lists.
        lock();
 
-       printf("Full thread dump CACAO "VERSION":\n");
+       printf("Full thread dump CACAO "VERSION_FULL":\n");
 
        // Iterate over all started threads.
+       threadobject* self = THREADOBJECT;
        for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
                threadobject* t = *it;
 
@@ -70,13 +75,10 @@ void ThreadList::dump_threads()
                if (t->state == THREAD_STATE_NEW)
                        continue;
 
-#if defined(ENABLE_GC_CACAO)
-               /* Suspend the thread. */
-               /* XXX Is the suspend reason correct? */
+               /* Suspend the thread (and ignore return value). */
 
-               if (threads_suspend_thread(t, SUSPEND_REASON_JNI) == false)
-                       vm_abort("threads_dump: threads_suspend_thread failed");
-#endif
+               if (t != self)
+                       (void) threads_suspend_thread(t, SUSPEND_REASON_DUMP);
 
                /* Print thread info. */
 
@@ -88,12 +90,10 @@ void ThreadList::dump_threads()
 
                stacktrace_print_of_thread(t);
 
-#if defined(ENABLE_GC_CACAO)
-               /* Resume the thread. */
+               /* Resume the thread (and ignore return value). */
 
-               if (threads_resume_thread(t) == false)
-                       vm_abort("threads_dump: threads_resume_thread failed");
-#endif
+               if (t != self)
+                       (void) threads_resume_thread(t, SUSPEND_REASON_DUMP);
        }
 
        // Unlock the thread lists.
@@ -108,7 +108,7 @@ void ThreadList::dump_threads()
  *
  * @param list list class to be filled
  */
-void ThreadList::get_active_threads(list<threadobject*> &list)
+void ThreadList::get_active_threads(List<threadobject*> &list)
 {
        // Lock the thread lists.
        lock();
@@ -121,6 +121,34 @@ void ThreadList::get_active_threads(list<threadobject*> &list)
 }
 
 
+/**
+ * Fills the passed list with all currently active threads which should be
+ * visible to Java. Creating a copy of the thread list here, is the only way
+ * to ensure we do not end up in a dead-lock when iterating over the list.
+ *
+ * @param list list class to be filled
+ */
+void ThreadList::get_active_java_threads(List<threadobject*> &list)
+{
+       // Lock the thread lists.
+       lock();
+
+       // Iterate over all active threads.
+       for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
+               threadobject* t = *it;
+
+               // We skip internal threads.
+               if (t->flags & THREAD_FLAG_INTERNAL)
+                       continue;
+
+               list.push_back(t);
+       }
+
+       // Unlock the thread lists.
+       unlock();
+}
+
+
 /**
  * Return a free thread object.
  *
@@ -130,13 +158,17 @@ threadobject* ThreadList::get_free_thread()
 {
        threadobject* t = NULL;
 
+       lock();
+
        // Do we have free threads in the free-list?
        if (_free_thread_list.empty() == false) {
                // Yes, get the index and remove it from the free list.
-               threadobject* t = _free_thread_list.front();
+               t = _free_thread_list.front();
                _free_thread_list.remove(t);
        }
 
+       unlock();
+
        return t;
 }
 
@@ -150,6 +182,8 @@ int32_t ThreadList::get_free_thread_index()
 {
        int32_t index;
 
+       lock();
+
        // Do we have free indexes in the free-list?
        if (_free_index_list.empty() == false) {
                // Yes, get the index and remove it from the free list.
@@ -161,10 +195,46 @@ int32_t ThreadList::get_free_thread_index()
                index = _active_thread_list.size() + 1;
        }
 
+       unlock();
+
        return index;
 }
 
 
+/**
+ * Return the number of daemon threads visible to Java.
+ *
+ * NOTE: This function does a linear-search over the threads list,
+ *       because it is only used by the management interface.
+ *
+ * @return number of daemon threads
+ */
+int32_t ThreadList::get_number_of_daemon_java_threads(void)
+{
+       int number = 0;
+
+       // Lock the thread lists.
+       lock();
+
+       // Iterate over all active threads.
+       for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
+               threadobject* t = *it;
+
+               // We skip internal threads.
+               if (t->flags & THREAD_FLAG_INTERNAL)
+                       continue;
+
+               if (thread_is_daemon(t))
+                       number++;
+       }
+
+       // Unlock the thread lists.
+       unlock();
+
+       return number;
+}
+
+
 /**
  * Return the number of non-daemon threads.
  *
@@ -251,18 +321,28 @@ threadobject* ThreadList::get_thread_from_java_object(java_handle_t* h)
        return NULL;
 }
 
+void ThreadList::deactivate_thread(threadobject *t)
+{
+       ThreadListLocker lock;
+       remove_from_active_thread_list(t);
+       threads_impl_clear_heap_pointers(t); // allow it to be garbage collected
+}
 
 /**
  * Release the thread.
  *
  * @return free thread index
  */
-void ThreadList::release_thread(threadobject* t)
+void ThreadList::release_thread(threadobject* t, bool needs_deactivate)
 {
        lock();
 
-       // Move thread from active thread list to free thread list.
-       remove_from_active_thread_list(t);
+       if (needs_deactivate)
+               // Move thread from active thread list to free thread list.
+               remove_from_active_thread_list(t);
+       else
+               assert(!t->is_in_active_list);
+
        add_to_free_thread_list(t);
 
        // Add thread index to free index list.
@@ -278,7 +358,6 @@ extern "C" {
        void ThreadList_lock() { ThreadList::lock(); }
        void ThreadList_unlock() { ThreadList::unlock(); }
        void ThreadList_dump_threads() { ThreadList::dump_threads(); }
-       void ThreadList_release_thread(threadobject* t) { ThreadList::release_thread(t); }
        threadobject* ThreadList_get_free_thread() { return ThreadList::get_free_thread(); }
        int32_t ThreadList_get_free_thread_index() { return ThreadList::get_free_thread_index(); }
        void ThreadList_add_to_active_thread_list(threadobject* t) { ThreadList::add_to_active_thread_list(t); }