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

jthread.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <jvmpi.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <jthread.h>
#include <mvector.h>
#include <hash.h>
#include <obj.h>

static char* empty = "<unknown>";

jthread* jthread_new (const char* thread_name, const char* group_name, 
                  const char* parent_name, jobjectID thread_id,
                  JNIEnv* env_id, timerstack *s) {
    jthread* c;
    
    c = malloc (sizeof (*c));
    if (c == NULL)
      return NULL;
    
    if (thread_name)
      c->thread_name = strdup (thread_name);
    else 
      c->thread_name = empty;
    if (group_name)
      c->group_name = strdup (group_name);
    else 
      c->group_name = empty;
    if (parent_name)
      c->parent_name = strdup (parent_name);
    else 
      c->parent_name = empty;

    if (c->thread_name == NULL ||
      c->group_name == NULL ||
      c->parent_name == NULL) {
      jthread_free (c);
      return NULL;
    }
    
    c->thread_id = thread_id;
    c->env_id = env_id;
    c->timerstack = s;
    return c;
}

void jthread_free (jthread* t) {
    if (t == NULL)
      return;
    if (t->parent_name != empty)
      free (t->parent_name);
    if (t->group_name != empty)
      free (t->group_name);
    if (t->thread_name != empty)
      free (t->thread_name);
    free (t);
}

size_t jthread_jmphash_func (void* c, size_t len) {
    jthread* tp = (jthread*)c;
    return ((long)tp->env_id) % len;
}

int jthread_cmp_func (void* c1, void* c2) {
    jthread* tp1 = (jthread*)c1;
    jthread* tp2 = (jthread*)c2;
    return tp1->env_id != tp2->env_id;
}

JNIEnv* jthread_get_env_id (jthread* t) {
    return t->env_id;
}

void jthread_set_env_id (jthread* t, JNIEnv* env_id) {
    t->env_id = env_id;
}

void jthread_method_entry (timerstack* s, method *m, jlong tval) {
    methodtime* tvc;
    
    m->entered++;    

    timerstack_lock (s);
    s->cpu_time = tval;
    if (s->top == s->max) {
      fprintf (stderr, "time to expand timerstack: (%p, %d, %d)\n", s->times,
             s->top, s->max);
      timerstack_expand (s);
      fprintf (stderr, "timerstack expanded: (%p, %d, %d)\n", s->times,
             s->top, s->max);
    }
    
    tvc = s->times + s->top;
    s->top++;
    tvc->tv = tval;
    tvc->tv_hold = 0;
    tvc->method = m;
    if (allocs_follow_filter ()) {
      if (cls_get_filtered (method_get_owner (m))) {
          tvc->filtered_method = m;
      } else {
          if (s->top > 1) { /* we added one a few lines up... */
            methodtime* tvc_prev = s->times + s->top - 2;
            tvc->filtered_method = tvc_prev->filtered_method;
          } else {
            tvc->filtered_method = m;
          }
      }
    }
    timerstack_unlock (s);
}

void jthread_method_exit (timerstack* s, jmethodID method_id, jlong tval, JNIEnv* env) {
    jlong tdiff;
    methodtime* tvc = NULL;

    timerstack_lock (s);
    s->cpu_time = tval;
    if (s->top <= 0) {
      /** this should be rare, locking here should be ok.. /robo */
      fprintf (stderr, "jthread_method_exit: stack underflow, trying to get stack:\n");
      get_call_trace_env (env);
    }

    if (s->top > 0) {
      s->top--;
      tvc = s->times + s->top;
    }
    
    if (tvc) {
        method* m = tvc->method;
      if (m != NULL) {
          if (m->method_id != method_id) {
            fprintf (stderr, "jthread_method_exit stack mismatch for %p "
                   "got id = %p  have id = %p, requesting stack...\n",
                   env, method_id, m->method_id);
            timerstack_unlock (s);
            get_call_trace_env (env);
            timerstack_lock (s);
            if (s->top > 0) {
                s->top--;
                tvc = s->times + s->top;
            }
            if (tvc) {
                method* m = tvc->method; 
                if (m == NULL)
                  return;     
                if (m->method_id != method_id) {
                  fprintf (stderr, 
                         "jthread_method_exit stack stil in mismatch "
                         "for %p got id = %p  have id = %p\n",
                         env, method_id, m->method_id);
                  return;
                }
            }
          }

          /* update this methods total time. */
          tdiff = tval - tvc->tv - tvc->tv_hold;
          if (tdiff < 0) {
            /* Ok, this should normally not happen, but it can happen 
             * when a thread has had its stack messed up / missing.
             * negative values => incorrectly huge values for some 
             * methods so handle it nicely...
             */
            tdiff = 0;
          }
          m->calls++;
          m->entered--;    
            m->time_used.tv += tdiff;
          m->time_used.tv_hold += tvc->tv_hold;
          method_set_modified (m, 1);
      
          /* notify caller how much time this method took.. */
          tdiff = tval - tvc->tv;
      
          /* get caller and fill in values. */
          if (s->top > 0) {
            method* mc; 
            jlong hold = tdiff;
            tvc = s->times + s->top - 1;
            mc = tvc->method;     
            tvc->tv_hold += hold;
            /* not sure if this should be here? /robo
               method_set_modified (mc, 1);
            */
            if (mc && mc->called_methods) {
                long i = mvector_search (mc->called_methods, m);
                if (i == -1)
                  i = mvector_add_method (mc->called_methods, m);
                if (m->callee_methods) {
                  i = mvector_search (m->callee_methods, mc);
                  if (i == -1)
                      i = mvector_add_method (m->callee_methods, mc);
                }
            }
          } else {
            tvc = NULL;
          }
      } else {
          fprintf (stderr,
                 "jthread_method_exit: exited method (%p) is null, env = %p\n", 
                 method_id, env);
      }
      /* if we have no parent method we just ignore for now. 
         Im not sure if we should take actions */
    }

    timerstack_unlock (s);
}


/** The given thread has is waiting for a monitor. */
void jthread_contenation_enter (timerstack* s,
                        obj* monitor,
                        jlong tval) {
    timerstack_lock (s);
    s->last_contentation = tval;
    timerstack_unlock (s);
}

/** The given thread got the monitor it was waiting for. */
void jthread_contenation_entered (timerstack* s,
                          obj* monitor,
                          jlong tval) {
    timerstack_lock (s);
    if (s->last_contentation != -1)
      s->contendtime += tval - s->last_contentation;
    else 
      fprintf (stderr, "jthread_contenation_entered: stack underflow\n");
    /* I dont think we need it, but maybe we should do this: 
    s->last_contentation = -1;
    */
    timerstack_unlock (s);
}

char* jthread_get_thread_name (jthread* t) {
    return (t->thread_name);
}
char* jthread_get_group_name (jthread* t) {
    return (t->group_name);
}
char* jthread_get_parent_name (jthread* t) {
    return (t->parent_name);
}


/* 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