Signed-off-by: Tomek Grabiec <[email protected]>
---
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, ×pec);
+
+ 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, ×pec);
+ 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel