When there are multiple threads waiting for a class to
be loaded then the entry is removed from hash map and
freed by the last thread which gives up on it.

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

diff --git a/vm/classloader.c b/vm/classloader.c
index c559842..5011b3e 100644
--- a/vm/classloader.c
+++ b/vm/classloader.c
@@ -183,9 +183,18 @@ int classloader_add_to_classpath(const char *classpath)
        return 0;
 }
 
+enum class_load_status {
+       CLASS_LOADING,
+       CLASS_LOADED,
+       CLASS_NOT_FOUND,
+};
+
 struct classloader_class {
-       bool loaded;
+       enum class_load_status status;
        struct vm_class *class;
+
+       /* number of threads waiting for a class. */
+       unsigned long nr_waiting;
 };
 
 static struct hash_map *classes;
@@ -466,6 +475,32 @@ out_filename:
        return result;
 }
 
+static struct classloader_class *find_class(const char *name)
+{
+       struct classloader_class *class;
+
+       class = lookup_class(name);
+       if (class) {
+               /*
+                * If class is being loaded by another thread then wait
+                * until loading is completed.
+                */
+
+               ++class->nr_waiting;
+               while (class->status == CLASS_LOADING)
+                       pthread_cond_wait(&classloader_cond, 
&classloader_mutex);
+               --class->nr_waiting;
+
+               if (class->status == CLASS_NOT_FOUND && !class->nr_waiting) {
+                       hash_map_remove(classes, name);
+                       free(class);
+                       class = NULL;
+               }
+       }
+
+       return class;
+}
+
 /* XXX: Should use hash table or tree, not linear search. -Vegard */
 struct vm_class *classloader_load(const char *class_name)
 {
@@ -480,24 +515,22 @@ struct vm_class *classloader_load(const char *class_name)
                return NULL;
        }
 
+       vmc = NULL;
+
        pthread_mutex_lock(&classloader_mutex);
 
-       class = lookup_class(slash_class_name);
+       class = find_class(slash_class_name);
        if (class) {
-               /* If class is being loaded by another thread then wait
-                * until loading is completed. */
-               while (!class->loaded)
-                       pthread_cond_wait(&classloader_cond, 
&classloader_mutex);
+               if (class->status == CLASS_LOADED)
+                       vmc = class->class;
 
-               vmc = class->class;
                goto out_unlock;
        }
 
        class = malloc(sizeof(*class));
-       class->loaded = false;
+       class->status = CLASS_LOADING;
 
        if (hash_map_put(classes, strdup(slash_class_name), class)) {
-               NOT_IMPLEMENTED;
                vmc = NULL;
                goto out_unlock;
        }
@@ -511,13 +544,23 @@ struct vm_class *classloader_load(const char *class_name)
         */
        vmc = load_class(slash_class_name);
        if (!vmc) {
+               pthread_mutex_lock(&classloader_mutex);
+
                /*
-                * We should remove the entry from map but other threads
-                * might be waiting on it.
+                * If there are other threads waiting for class to be
+                * loaded then do not remove the entry. Last thread
+                * removes the entry.
                 */
-               NOT_IMPLEMENTED;
+               if (class->nr_waiting == 0) {
+                       hash_map_remove(classes, slash_class_name);
+                       free(class);
+               } else {
+                       class->status = CLASS_NOT_FOUND;
+                       pthread_cond_broadcast(&classloader_cond);
+               }
+
                vmc = NULL;
-               goto out;
+               goto out_unlock;
        }
 
        pthread_mutex_lock(&classloader_mutex);
@@ -525,7 +568,7 @@ struct vm_class *classloader_load(const char *class_name)
        vmc->classloader = NULL;
 
        class->class = vmc;
-       class->loaded = true;
+       class->status = CLASS_LOADED;
 
        /* Tell other threads that the class has been loaded. Would it
         * be worth to use a per-class condition variable for that? */
@@ -533,8 +576,6 @@ struct vm_class *classloader_load(const char *class_name)
 
  out_unlock:
        pthread_mutex_unlock(&classloader_mutex);
-
- out:
        free(slash_class_name);
        trace_pop();
        return vmc;
@@ -560,15 +601,9 @@ struct vm_class *classloader_find_class(const char *name)
 
        pthread_mutex_lock(&classloader_mutex);
 
-       class = lookup_class(slash_class_name);
-       if (class) {
-               /* If class is being loaded by another thread then wait
-                * until loading is completed. */
-               while (!class->loaded)
-                       pthread_cond_wait(&classloader_cond, 
&classloader_mutex);
-
+       class = find_class(slash_class_name);
+       if (class && class->status == CLASS_LOADED)
                vmc = class->class;
-       }
 
        free(slash_class_name);
 
-- 
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