Logo Search packages:      
Sourcecode: jmp version File versions  Download package

threads_window.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <jni.h>
#include <jmp-config.h>
#include <jmp.h>
#include <hash.h>
#include <obj.h>
#include <method.h>
#include <jthread.h>
#include <methodtime.h>
#include <threads_window.h>
#include <comparators.h>
#include <timerstack.h>

enum {
    TNAME_COLUMN,
    TGROUP_COLUMN,
    TPARENT_COLUMN,
    TCONTENATION_COLUMN,
    TJTHREAD_COLUMN,
    TSTATUS_COLUMN,
    TTIME_COLUMN,
    TN_COLUMNS
};

enum {
    SCLASS_COLUMN,
    SMETHOD_COLUMN,
    SN_COLUMNS
};

char *thread_states[8];

static size_t num_threads = 0;
static size_t current_row = 0;
static jthread** threadlist = NULL;
static int ((*jthread_comprs[])(const void* v1, const void* v2)) = { jthread_compr_name, 
                                                     jthread_compr_group,
                                                     jthread_compr_parent,
                                                     jthread_compr_contenation,
                                                     jthread_compr_state,
                                                     jthread_compr_cputime
};

/** our current comparator */
static int (*jthread_compr) (const void* v1, const void* v2) = jthread_compr_name;

/** This function will also update the threads state-flag. */
static void count_threads (void* thread, void* counter) {
    jthread* jt = (jthread*)thread;
    int* c = (int*)counter;
    (*c)++;
    jt->state = get_thread_state (jt);
}

static void add_thread (void* thread, GtkListStore* thread_store, int row_num) {
    char* row[4];
    char buf[32],cpu_time[32];
    char printable_state[32];
    jlong sec, nsec; 
    jthread* jt = (jthread*)thread;
    GtkTreeIter   iter;

    row[0] = jthread_get_thread_name (jt);
    row[1] = jthread_get_group_name (jt);
    row[2] = jthread_get_parent_name (jt);
    timerstack_lock (jt->timerstack);
    sec = jt->timerstack->contendtime / 1000000000;
    nsec = jt->timerstack->contendtime % 1000000000;
    snprintf (buf, 32, "%lld.%09lld", sec, nsec);
    row[3] = buf;
    
    sec = jt->timerstack->cpu_time / 1000000000;
    nsec = jt->timerstack->cpu_time % 1000000000;
    snprintf (cpu_time, 32, "%lld.%09lld", sec, nsec);
    timerstack_unlock (jt->timerstack);

    strncpy (printable_state, thread_states[(jt->state & 0x03) - 1], 32);
    strncat (printable_state, thread_states[(jt->state >> 14) + 3], 32);
    if (row_num < num_threads) 
      gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (thread_store), &iter, NULL, row_num);
    else
      gtk_list_store_append (thread_store, &iter);
    gtk_list_store_set (thread_store, &iter,
                  TNAME_COLUMN, row[0],
                  TGROUP_COLUMN, row[1],
                  TPARENT_COLUMN, row[2],
                  TCONTENATION_COLUMN, row[3],
                  TJTHREAD_COLUMN, jt,
                  TSTATUS_COLUMN,printable_state,
                  TTIME_COLUMN,cpu_time,
                  -1);
}

static void add_thread1 (void* thread, void* tl) {
    jthread** threadlist = (jthread**)tl;
    threadlist[current_row++] = (jthread*)thread;
}

static void update_threads_table (GtkListStore* thread_store, hashtab* threads) {
    int counter = 0;
    int i;

    jmphash_lock (threads);
    jmphash_for_each_with_arg ((jmphash_iter_fa)count_threads, threads, &counter);
    if (counter != num_threads)
      threadlist = realloc (threadlist, sizeof (jthread*) * counter);
    current_row = 0;
    jmphash_for_each_with_arg ((jmphash_iter_fa)add_thread1, threads, threadlist);
    jmphash_unlock (threads);
    qsort (threadlist, counter, sizeof (jthread*), jthread_compr);
    current_row = 0;
    
    for (i = 0; i < counter; i++) 
      add_thread (threadlist[i], thread_store, i);

    if (counter < num_threads) {
      GtkTreeIter   iter;
      gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (thread_store), &iter, NULL, counter);
      for (i = num_threads - 1; i >= counter; i--) {
            /* this updates iter to point to next valid iter.. */
          gtk_list_store_remove (thread_store, &iter);  
      }
    }

    num_threads = counter;
}

static gint delete_event (GtkWidget *widget, GdkEvent  *event, gpointer   data) {
    gtk_widget_hide (widget);
    timerstacks_set_need_locks (0);
    return (TRUE);
}

static void thread_changed (GtkTreeSelection *selection, gpointer data) {
    GtkTreeIter iter;
    GtkTreeModel *model;
    jthread *t;
    char* row[2];
    timerstack* ts;
    int i;
    threads_window* tw = (threads_window*)data;
    GtkListStore *stackstore = tw->stackstore;
    
    gtk_list_store_clear (stackstore);
    if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
      gtk_tree_model_get (model, &iter, TJTHREAD_COLUMN, &t, -1);
      ts = get_timerstack (jthread_get_env_id (t));
      if (ts != NULL) {
          timerstack_lock (ts);
          for (i = ts->top - 1; i >= 0; i--) {
            method* m;
            methodtime* mt = ts->times + i;
            m = mt->method;
            row[0] = (m ? cls_get_name (method_get_owner (m)) : "???");
            row[1] = (m ? method_get_method_jmpname (m) : "???");
            gtk_list_store_append (stackstore, &iter);
            gtk_list_store_set (stackstore, &iter,
                            SCLASS_COLUMN, row[0],
                            SMETHOD_COLUMN, row[1],
                            -1);
          }
          if (ts->waiting) {
            char buf[255];
            obj* o = ts->waiting;
            snprintf (buf, 255, _("waiting for %p of class %s"), 
                    o ? obj_get_object_id (o) : NULL, 
                    o ? cls_get_name (obj_get_class (o)) : _("<unknown>"));
            gtk_statusbar_pop (GTK_STATUSBAR (tw->statusbar), 1);
            gtk_statusbar_push (GTK_STATUSBAR (tw->statusbar), 1, buf);
          } else {
            gtk_statusbar_pop (GTK_STATUSBAR (tw->statusbar), 1);
          }
          timerstack_unlock (ts);
      }
    }
}

static void threads_column_clicked (GtkWidget* treeviewcolumn, gpointer user_data) {
    int column = (int)user_data;
    if (jthread_comprs[column] != NULL) {
      if (jthread_compr != jthread_comprs[column]) {
          jthread_compr = jthread_comprs[column];
      }
    } else {
      fprintf (stdout, "Sort order not yet implemented.\n");
    }
}

static void add_column (GtkWidget *tree, char* label, int pos, 
                  gpointer data, void (*cb)(GtkWidget*, gpointer)) {
    GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
    GtkTreeViewColumn *column = 
      gtk_tree_view_column_new_with_attributes (label, renderer,
                                      "text", pos, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
    if (cb != NULL)
      g_signal_connect (G_OBJECT (column), "clicked", G_CALLBACK (cb), data);
}

threads_window* create_threads_window (hashtab* threads) {
    GtkWidget *window;
    GtkWidget *hpane;
    GtkWidget *tbox;
    GtkWidget *sbox;
    GtkWidget *mbox;
    threads_window *tw;
    GtkWidget *threadslabel;
    GtkWidget *stacklabel;
    GtkListStore *threadsstore;
    GtkListStore *stackstore;
    GtkWidget *ttree;
    GtkWidget *stree;
    GtkWidget *scrolledwindow;
    GtkWidget *statusbar;
    GtkTreeSelection *select;
    
    thread_states[JVMPI_THREAD_RUNNABLE-1] = _("Runnable");
    thread_states[JVMPI_THREAD_MONITOR_WAIT-1] = _("Monitor wait");
    thread_states[JVMPI_THREAD_CONDVAR_WAIT-1] = _("Condition wait");
    thread_states[3]="";
    thread_states[(JVMPI_THREAD_SUSPENDED>>14)+3] = _(" (S)");
    thread_states[(JVMPI_THREAD_INTERRUPTED>>14)+3] = _(" (I)");
    thread_states[((JVMPI_THREAD_SUSPENDED|JVMPI_THREAD_INTERRUPTED)>>14)+3] = _(" (SI)");

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                  GTK_SIGNAL_FUNC (delete_event), NULL);
    gtk_widget_set_usize (window, 800, 400);
    gtk_window_set_title (GTK_WINDOW (window), _("Current threads"));

    hpane = gtk_vpaned_new ();
    tbox = gtk_vbox_new (FALSE, 0);
    sbox = gtk_vbox_new (FALSE, 0);
    mbox = gtk_vbox_new (FALSE, 0);
    statusbar = gtk_statusbar_new ();
    
    gtk_container_add (GTK_CONTAINER (window), mbox);
    gtk_box_pack_start (GTK_BOX (mbox), hpane, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (mbox), statusbar, FALSE, FALSE, 0);

    gtk_paned_add1 (GTK_PANED (hpane), tbox);
    gtk_paned_add2 (GTK_PANED (hpane), sbox);
    gtk_paned_set_position (GTK_PANED (hpane), 200);

    threadslabel = gtk_label_new (_("Threads"));
    gtk_box_pack_start (GTK_BOX (tbox), threadslabel, FALSE, FALSE, 0);
    stacklabel = gtk_label_new (_("Stack"));
    gtk_box_pack_start (GTK_BOX (sbox), stacklabel, FALSE, FALSE, 0);
    
    threadsstore = gtk_list_store_new (TN_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, 
                               G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
    ttree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (threadsstore));

    add_column (ttree, _("Name"), TNAME_COLUMN, (gpointer)0, threads_column_clicked);
    add_column (ttree, _("Group"), TGROUP_COLUMN, (gpointer)1, threads_column_clicked);
    add_column (ttree, _("Parent"), TPARENT_COLUMN, (gpointer)2, threads_column_clicked);
    add_column (ttree, _("Contenation"), TCONTENATION_COLUMN, (gpointer)3, threads_column_clicked);
    add_column (ttree, _("Status"), TSTATUS_COLUMN, (gpointer) 4, threads_column_clicked);
    add_column (ttree, _("Time"), TTIME_COLUMN, (gpointer) 5, threads_column_clicked);
    scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
    gtk_container_add (GTK_CONTAINER (scrolledwindow), ttree);
    gtk_box_pack_start (GTK_BOX (tbox), scrolledwindow, TRUE, TRUE, 0);


    stackstore = gtk_list_store_new (SN_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
    stree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (stackstore));
    
    
    add_column (stree, _("Class"), SCLASS_COLUMN, (gpointer)0, NULL);
    add_column (stree, _("Method"), SMETHOD_COLUMN, (gpointer)1, NULL);

    scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
    gtk_container_add (GTK_CONTAINER (scrolledwindow), stree);
    gtk_box_pack_start (GTK_BOX (sbox), scrolledwindow, TRUE, TRUE, 0);
    gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (ttree), TRUE);

    update_threads_table (threadsstore, threads);

    tw = malloc (sizeof (threads_window));
    tw->window = window;
    tw->threads_table = threadsstore;
    tw->stackstore = stackstore;
    tw->statusbar = statusbar;

    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttree));
    g_signal_connect (G_OBJECT (select), "changed",
                  G_CALLBACK (thread_changed),
                  tw);
    return tw;
}

void update_threads_window (threads_window* tw, hashtab* threads) {
    update_threads_table (tw->threads_table, threads);
}

void destroy_threads_window (threads_window* tw) {
    if (!tw)
      return;
    free (threadlist);
    threadlist = NULL;
    gtk_widget_destroy (tw->window);
    free (tw);
}

/* Emacs Local Variables: */
/* Emacs mode:C */
/* Emacs c-indentation-style:"gnu" */
/* Emacs c-hanging-braces-alist:((brace-list-open)(brace-entry-open)(defun-open after)(substatement-open after)(block-close . c-snug-do-while)(extern-lang-open after)) */
/* Emacs c-cleanup-list:(brace-else-brace brace-elseif-brace space-before-funcall) */
/* Emacs c-basic-offset:4 */
/* Emacs End: */

Generated by  Doxygen 1.6.0   Back to index