Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 Makefile              |    2 +-
 include/vm/object.h   |   36 +++++++++-
 scripts/build/test.mk |    2 +-
 vm/object.c           |  196 +++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 225 insertions(+), 11 deletions(-)

diff --git a/Makefile b/Makefile
index 8a0fbe9..5f65093 100644
--- a/Makefile
+++ b/Makefile
@@ -181,7 +181,7 @@ DEFAULT_CFLAGS      += $(INCLUDES)
 DEFINES = -DINSTALL_DIR=\"$(JAMVM_INSTALL_DIR)\" 
-DCLASSPATH_INSTALL_DIR=\"$(CLASSPATH_INSTALL_DIR)\"
 DEFAULT_CFLAGS += $(DEFINES)
 
-DEFAULT_LIBS   = -lpthread -lm -ldl -lz -lzip -lbfd -lopcodes -liberty 
$(ARCH_LIBS)
+DEFAULT_LIBS   = -lrt -lpthread -lm -ldl -lz -lzip -lbfd -lopcodes -liberty 
$(ARCH_LIBS)
 
 all: $(PROGRAM) $(TEST)
 .PHONY: all
diff --git a/include/vm/object.h b/include/vm/object.h
index 864f7c3..c293c41 100644
--- a/include/vm/object.h
+++ b/include/vm/object.h
@@ -6,11 +6,35 @@
 #include <stdint.h>
 
 #include "vm/field.h"
+#include "vm/thread.h"
 #include "vm/vm.h"
 
 struct vm_class;
 enum vm_type;
 
+struct vm_monitor {
+       pthread_mutex_t mutex;
+       pthread_cond_t cond;
+
+       /* Holds the owner of this monitor or NULL when not locked. */
+       struct vm_thread *owner;
+
+       /*
+        * owner field might be read by other threads even if lock on
+        * @mutex is not held by them. For example vm_monitor_unlock()
+        * checks if the current thread is the owner of monitor. In
+        * SMP systems we must either ensure atomicity and use memory
+        * barriers or use a mutex. The latter approach is choosed.
+        */
+       pthread_mutex_t owner_mutex;
+
+       /*
+        * Holds the number of recursive locks on this monitor. This
+        * field is protected by @mutex.
+        */
+       int lock_count;
+};
+
 struct vm_object {
        /* For arrays, this points to the array type, e.g. for int arrays,
         * this points to the (artificial) class named "[I". We actually rely
@@ -19,7 +43,7 @@ struct vm_object {
         * we access ->class first. */
        struct vm_class *class;
 
-       pthread_mutex_t mutex;
+       struct vm_monitor monitor;
 
        int array_length;
        uint8_t fields[];
@@ -55,6 +79,16 @@ void array_size_check(int size);
 void multiarray_size_check(int n, ...);
 char *vm_string_to_cstr(const struct vm_object *string);
 
+int vm_monitor_init(struct vm_monitor *mon);
+int vm_monitor_lock(struct vm_monitor *mon);
+int vm_monitor_unlock(struct vm_monitor *mon);
+int vm_monitor_wait(struct vm_monitor *mon);
+int vm_monitor_timed_wait(struct vm_monitor *mon, long long ms, int ns);
+int vm_monitor_notify(struct vm_monitor *mon);
+int vm_monitor_notify_all(struct vm_monitor *mon);
+struct vm_thread *vm_monitor_get_owner(struct vm_monitor *mon);
+void vm_monitor_set_owner(struct vm_monitor *mon, struct vm_thread *owner);
+
 static inline void
 field_set_int32(struct vm_object *obj, const struct vm_field *field, int32_t 
value)
 {
diff --git a/scripts/build/test.mk b/scripts/build/test.mk
index bba5ff5..bbfc279 100644
--- a/scripts/build/test.mk
+++ b/scripts/build/test.mk
@@ -5,7 +5,7 @@ DEFAULT_CFLAGS  ?= -rdynamic -g -Wall -Wundef -Wsign-compare 
-Os -std=gnu99 -D_GN
 DEFAULT_CFLAGS += -DNOT_IMPLEMENTED='fprintf(stderr, "%s:%d: warning: %s not 
implemented\n", __FILE__, __LINE__, __func__)'
 
 INCLUDE                ?= -I../include/ -I. -I../libharness -I../../include 
-I../../jit/glib -I../../cafebabe/include/ -include $(ARCH_CONFIG)
-DEFAULT_LIBS   ?= -lpthread -lm -ldl -lz -lbfd -lopcodes -liberty
+DEFAULT_LIBS   ?= -lrt -lpthread -lm -ldl -lz -lbfd -lopcodes -liberty
 
 ifdef TESTS
        TESTS_C = $(TESTS:.o=.c)
diff --git a/vm/object.c b/vm/object.c
index 7c16231..509e92d 100644
--- a/vm/object.c
+++ b/vm/object.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdio.h>
+#include <time.h>
 
 #include "jit/exception.h"
 
@@ -51,8 +52,10 @@ struct vm_object *vm_object_alloc(struct vm_class *class)
 
        res->class = class;
 
-       if (pthread_mutex_init(&res->mutex, &obj_mutexattr))
+       if (vm_monitor_init(&res->monitor)) {
                NOT_IMPLEMENTED;
+               return NULL;
+       }
 
        return res;
 }
@@ -110,8 +113,10 @@ struct vm_object *vm_object_alloc_native_array(int type, 
int count)
 
        res->array_length = count;
 
-       if (pthread_mutex_init(&res->mutex, &obj_mutexattr))
+       if (vm_monitor_init(&res->monitor)) {
                NOT_IMPLEMENTED;
+               return NULL;
+       }
 
        return res;
 }
@@ -132,8 +137,10 @@ struct vm_object *vm_object_alloc_multi_array(struct 
vm_class *class,
                return NULL;
        }
 
-       if (pthread_mutex_init(&res->mutex, &obj_mutexattr))
+       if (vm_monitor_init(&res->monitor)) {
                NOT_IMPLEMENTED;
+               return NULL;
+       }
 
        res->array_length = counts[0];
 
@@ -171,8 +178,10 @@ struct vm_object *vm_object_alloc_array(struct vm_class 
*class, int count)
                return NULL;
        }
 
-       if (pthread_mutex_init(&res->mutex, &obj_mutexattr))
+       if (vm_monitor_init(&res->monitor)) {
                NOT_IMPLEMENTED;
+               return NULL;
+       }
 
        res->array_length = count;
 
@@ -263,14 +272,12 @@ struct vm_object *vm_object_clone(struct vm_object *obj)
 
 void vm_object_lock(struct vm_object *obj)
 {
-       if (pthread_mutex_lock(&obj->mutex))
-               NOT_IMPLEMENTED;
+       vm_monitor_lock(&obj->monitor);
 }
 
 void vm_object_unlock(struct vm_object *obj)
 {
-       if (pthread_mutex_unlock(&obj->mutex))
-               NOT_IMPLEMENTED;
+       vm_monitor_unlock(&obj->monitor);
 }
 
 struct vm_object *
@@ -572,3 +579,176 @@ char *vm_string_to_cstr(const struct vm_object 
*string_obj)
        free_str(str);
        return result;
 }
+
+int vm_monitor_init(struct vm_monitor *mon)
+{
+       if (pthread_mutex_init(&mon->owner_mutex, NULL)) {
+               NOT_IMPLEMENTED;
+               return -1;
+       }
+
+       if (pthread_mutex_init(&mon->mutex, &obj_mutexattr)) {
+               NOT_IMPLEMENTED;
+               return -1;
+       }
+
+       if (pthread_cond_init(&mon->cond, NULL)) {
+               NOT_IMPLEMENTED;
+               return -1;
+       }
+
+       return 0;
+}
+
+struct vm_thread *vm_monitor_get_owner(struct vm_monitor *mon)
+{
+       struct vm_thread *owner;
+
+       pthread_mutex_lock(&mon->owner_mutex);
+       owner = mon->owner;
+       pthread_mutex_unlock(&mon->owner_mutex);
+
+       return owner;
+}
+
+void vm_monitor_set_owner(struct vm_monitor *mon, struct vm_thread *owner)
+{
+       pthread_mutex_lock(&mon->owner_mutex);
+       mon->owner = owner;
+       pthread_mutex_unlock(&mon->owner_mutex);
+}
+
+int vm_monitor_lock(struct vm_monitor *mon)
+{
+       struct vm_thread *self = vm_thread_self();
+
+       if (pthread_mutex_trylock(&mon->mutex)) {
+               /*
+                * XXX: according to Thread.getState() documentation thread
+                * state does not have to be precise, it's used rather
+                * for monitoring.
+                */
+               vm_thread_set_state(self, VM_THREAD_STATE_BLOCKED);
+               pthread_mutex_lock(&mon->mutex);
+               vm_thread_set_state(self, VM_THREAD_STATE_RUNNABLE);
+       }
+
+       vm_monitor_set_owner(mon, self);
+       mon->lock_count++;
+
+       return 0;
+}
+
+int vm_monitor_unlock(struct vm_monitor *mon)
+{
+       if (vm_monitor_get_owner(mon) != vm_thread_self()) {
+               signal_new_exception(vm_java_lang_IllegalMonitorStateException,
+                                    NULL);
+               return -1;
+       }
+
+       if (--mon->lock_count == 0)
+               vm_monitor_set_owner(mon, NULL);
+
+       return pthread_mutex_unlock(&mon->mutex);
+}
+
+int vm_monitor_timed_wait(struct vm_monitor *mon, long long ms, int ns)
+{
+       struct vm_thread *self;
+       struct timespec timespec;
+       int err;
+
+       if (vm_monitor_get_owner(mon) != vm_thread_self()) {
+               signal_new_exception(vm_java_lang_IllegalMonitorStateException,
+                                    NULL);
+               return -1;
+       }
+
+       /*
+        * XXX: we must use CLOCK_REALTIME here because
+        * pthread_cond_timedwait() uses this clock.
+        */
+       clock_gettime(CLOCK_REALTIME, &timespec);
+
+       timespec.tv_sec += ms / 1000;
+       timespec.tv_nsec += (long)ns + (long)(ms % 1000) * 1000000l;
+
+       if (timespec.tv_nsec >= 1000000000l) {
+               timespec.tv_sec++;
+               timespec.tv_nsec -= 1000000000l;
+       }
+
+       if (--mon->lock_count == 0)
+               vm_monitor_set_owner(mon, NULL);
+
+       self = vm_thread_self();
+
+       vm_thread_set_state(self, VM_THREAD_STATE_TIMED_WAITING);
+       err = pthread_cond_timedwait(&mon->cond, &mon->mutex, &timespec);
+       vm_thread_set_state(self, VM_THREAD_STATE_RUNNABLE);
+
+       if (err == ETIMEDOUT)
+               err = 0;
+
+       if (!err) {
+               /* reacquire the lock */
+               vm_monitor_set_owner(mon, self);
+               mon->lock_count++;
+       }
+
+       /* TODO: check if thread has been interrupted. */
+       return err;
+}
+
+int vm_monitor_wait(struct vm_monitor *mon)
+{
+       struct vm_thread *self;
+       int err;
+
+       self = vm_thread_self();
+
+       if (vm_monitor_get_owner(mon) != vm_thread_self()) {
+               signal_new_exception(vm_java_lang_IllegalMonitorStateException,
+                                    NULL);
+               return -1;
+       }
+
+       if (--mon->lock_count == 0)
+               vm_monitor_set_owner(mon, NULL);
+
+       vm_thread_set_state(self, VM_THREAD_STATE_WAITING);
+       err = pthread_cond_wait(&mon->cond, &mon->mutex);
+       vm_thread_set_state(self, VM_THREAD_STATE_RUNNABLE);
+
+       if (!err) {
+               /* reacquire the lock */
+               vm_monitor_set_owner(mon, self);
+               mon->lock_count++;
+       }
+
+       /* TODO: check if thread has been interrupted. */
+       return err;
+}
+
+int vm_monitor_notify(struct vm_monitor *mon)
+{
+       if (vm_monitor_get_owner(mon) != vm_thread_self()) {
+               signal_new_exception(vm_java_lang_IllegalMonitorStateException,
+                                    NULL);
+               return -1;
+       }
+
+       return pthread_cond_signal(&mon->cond);
+}
+
+int vm_monitor_notify_all(struct vm_monitor *mon)
+{
+       if (vm_monitor_get_owner(mon) != vm_get_exec_env()->thread) {
+               signal_new_exception(vm_java_lang_IllegalMonitorStateException,
+                                    NULL);
+               return -1;
+       }
+
+       return pthread_cond_broadcast(&mon->cond);
+}
-- 
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