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, ×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 Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel