Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 vm/classloader.c |   94 +++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 76 insertions(+), 18 deletions(-)

diff --git a/vm/classloader.c b/vm/classloader.c
index dfc8010..a0add9d 100644
--- a/vm/classloader.c
+++ b/vm/classloader.c
@@ -12,17 +12,23 @@
 #include "vm/preload.h"
 #include "vm/class.h"
 #include "vm/die.h"
+#include "vm/backtrace.h"
 
 bool opt_trace_classloader;
-static int trace_classloader_level = 0;
+static __thread int trace_classloader_level = 0;
+
+static pthread_mutex_t classloader_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t classloader_cond = PTHREAD_COND_INITIALIZER;
 
 static inline void trace_push(const char *class_name)
 {
        assert(trace_classloader_level >= 0);
 
        if (opt_trace_classloader) {
+               trace_begin();
                fprintf(stderr, "classloader: %*s%s\n",
                        trace_classloader_level, "", class_name);
+               trace_end();
        }
 
        ++trace_classloader_level;
@@ -147,25 +153,39 @@ int classloader_add_to_classpath(const char *classpath)
 }
 
 struct classloader_class {
-       struct vm_class *class;
+       /* If false then the class loading is in progress. */
+       bool loaded;
+
+       union {
+               /* When @loaded is false this holds the class's name. It
+                * should not be referenced when class is loaded. */
+               const char *class_name;
+
+               struct vm_class *class;
+       };
 };
 
 static struct classloader_class *classes;
 static unsigned long max_classes;
 static unsigned long nr_classes;
 
-static struct classloader_class *lookup_class(const char *class_name)
+static int lookup_class(const char *class_name)
 {
        unsigned long i;
 
        for (i = 0; i < nr_classes; ++i) {
                struct classloader_class *class = &classes[i];
 
-               if (!strcmp(class->class->name, class_name))
-                       return class;
+               if (!class->loaded) {
+                       if (!strcmp(class->class_name, class_name))
+                               return i;
+               } else {
+                       if (!strcmp(class->class->name, class_name))
+                               return i;
+               }
        }
 
-       return NULL;
+       return -1;
 }
 
 static char *class_name_to_file_name(const char *class_name)
@@ -423,26 +443,38 @@ out_filename:
 /* XXX: Should use hash table or tree, not linear search. -Vegard */
 struct vm_class *classloader_load(const char *class_name)
 {
-       struct classloader_class *class;
        struct vm_class *vmc;
        struct classloader_class *new_array;
        unsigned long new_max_classes;
+       int class_index;
 
        trace_push(class_name);
 
-       class = lookup_class(class_name);
-       if (class) {
-               vmc = class->class;
-               goto out;
-       }
+       pthread_mutex_lock(&classloader_mutex);
 
-       vmc = load_class(class_name);
-       if (!vmc) {
-               NOT_IMPLEMENTED;
-               vmc = NULL;
+       /*
+        * XXX: we must use index here not the entry pointer because
+        * while we're loading a class or waiting for a class to get
+        * loaded the classes array might get relocated.
+        */
+       class_index = lookup_class(class_name);
+
+       if (class_index >= 0) {
+               /* If class is being loaded by another thread then wait
+                * until loading is completed. */
+               while (!classes[class_index].loaded)
+                       pthread_cond_wait(&classloader_cond,
+                                         &classloader_mutex);
+
+               vmc = classes[class_index].class;
                goto out;
        }
 
+       /*
+        * We allocate cache space before loading to indicate that we
+        * are loading this class and other threads wanting to load
+        * that class in the same time should wait for us.
+        */
        if (nr_classes == max_classes) {
                new_max_classes = 1 + max_classes * 2;
                new_array = realloc(classes,
@@ -457,10 +489,36 @@ struct vm_class *classloader_load(const char *class_name)
                classes = new_array;
        }
 
-       class = &classes[nr_classes++];
-       class->class = vmc;
+       class_index = nr_classes++;
+
+       classes[class_index].loaded = false;
+       classes[class_index].class_name = class_name;
+
+       pthread_mutex_unlock(&classloader_mutex);
+
+       /*
+        * XXX: We cannot hold classloader_mutex lock when calling
+        * load_class() because for example vm_class_init() might call
+        * classloader_load() for superclasses.
+        */
+       vmc = load_class(class_name);
+       if (!vmc) {
+               NOT_IMPLEMENTED;
+               vmc = NULL;
+               goto out;
+       }
+
+       pthread_mutex_lock(&classloader_mutex);
+
+       classes[class_index].loaded = true;
+       classes[class_index].class = vmc;
+
+       /* Tell other threads that the class has been loaded. Would it
+        * be worth to use a per-class condition variable for that? */
+       pthread_cond_broadcast(&classloader_cond);
 
 out:
+       pthread_mutex_unlock(&classloader_mutex);
        trace_pop();
        return vmc;
 }
-- 
1.6.0.6


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to