+++ /dev/null
-## src/threads/native/Makefile.am
-##
-## Copyright (C) 1996-2005, 2006, 2007, 2008
-## CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-##
-## This file is part of CACAO.
-##
-## This program is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2, or (at
-## your option) any later version.
-##
-## This program is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-## 02110-1301, USA.
-
-
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR) -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR)/$(OS_DIR) -I$(top_builddir)/src -I$(top_srcdir)/contrib/vmlog
-
-LIBS =
-
-noinst_LTLIBRARIES = \
- libthreadsposix.la
-
-libthreadsposix_la_SOURCES = \
- lock.c \
- lock.h \
- threadlist-posix.c \
- threads.c \
- threads.h
-
-
-## Local variables:
-## mode: Makefile
-## indent-tabs-mode: t
-## c-basic-offset: 4
-## tab-width: 8
-## compile-command: "automake --add-missing"
-## End:
\ No newline at end of file
+++ /dev/null
-/* src/threads/native/generic-primitives.h - machine independent atomic
- operations
-
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
- C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
- E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
- J. Wenninger, Institut f. Computersprachen - TU Wien
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Contact: cacao@cacaojvm.org
-
- Authors: Christian Thalinger
- Anton Ertl
-
- Changes:
-
-
-*/
-
-
-#ifndef _MACHINE_INSTR_H
-#define _MACHINE_INSTR_H
-
-#include <pthread.h>
-
-extern pthread_mutex_t _cas_lock;
-extern pthread_mutex_t _mb_lock;
-
-
-static inline long compare_and_swap(volatile long *p, long oldval, long newval)
-{
- long ret;
-
- pthread_mutex_lock(&_cas_lock);
-
- /* do the compare-and-swap */
-
- ret = *p;
-
- if (oldval == ret)
- *p = newval;
-
- pthread_mutex_unlock(&_cas_lock);
-
- return ret;
-}
-
-
-#define MEMORY_BARRIER() (pthread_mutex_lock(&_mb_lock), \
- pthread_mutex_unlock(&_mb_lock))
-#define STORE_ORDER_BARRIER() MEMORY_BARRIER()
-#define MEMORY_BARRIER_AFTER_ATOMIC() /* nothing */
-
-#endif /* _MACHINE_INSTR_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
+++ /dev/null
-/* src/threads/native/lock.c - lock implementation
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <pthread.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/llni.h"
-
-#include "threads/lock-common.h"
-#include "threads/threadlist.h"
-#include "threads/threads-common.h"
-
-#include "threads/native/lock.h"
-#include "threads/native/threads.h"
-
-#include "toolbox/list.h"
-
-#include "vm/global.h"
-#include "vm/exceptions.h"
-#include "vm/finalizer.h"
-#include "vm/stringlocal.h"
-#include "vm/vm.h"
-
-#include "vmcore/options.h"
-
-#if defined(ENABLE_STATISTICS)
-# include "vmcore/statistics.h"
-#endif
-
-#if defined(ENABLE_VMLOG)
-#include <vmlog_cacao.h>
-#endif
-
-/* arch.h must be here because it defines USE_FAKE_ATOMIC_INSTRUCTIONS */
-
-#include "arch.h"
-
-/* includes for atomic instructions: */
-
-#if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
-#include "threads/native/generic-primitives.h"
-#else
-#include "machine-instr.h"
-#endif
-
-#if defined(ENABLE_JVMTI)
-#include "native/jvmti/cacaodbg.h"
-#endif
-
-#if defined(ENABLE_GC_BOEHM)
-# include "mm/boehm-gc/include/gc.h"
-#endif
-
-
-/* debug **********************************************************************/
-
-#if !defined(NDEBUG)
-# define DEBUGLOCKS(format) \
- do { \
- if (opt_DebugLocks) { \
- log_println format; \
- } \
- } while (0)
-#else
-# define DEBUGLOCKS(format)
-#endif
-
-
-/******************************************************************************/
-/* MACROS */
-/******************************************************************************/
-
-/* number of lock records in the first pool allocated for a thread */
-#define LOCK_INITIAL_LOCK_RECORDS 8
-
-#define LOCK_INITIAL_HASHTABLE_SIZE 1613 /* a prime in the middle between 1024 and 2048 */
-
-#define COMPARE_AND_SWAP_OLD_VALUE(address, oldvalue, newvalue) \
- ((ptrint) compare_and_swap((long *)(address), (long)(oldvalue), (long)(newvalue)))
-
-
-/******************************************************************************/
-/* MACROS FOR THIN/FAT LOCKS */
-/******************************************************************************/
-
-/* We use a variant of the tasuki locks described in the paper
- *
- * Tamiya Onodera, Kiyokuni Kawachiya
- * A Study of Locking Objects with Bimodal Fields
- * Proceedings of the ACM OOPSLA '99, pp. 223-237
- * 1999
- *
- * The underlying thin locks are a variant of the thin locks described in
- *
- * Bacon, Konuru, Murthy, Serrano
- * Thin Locks: Featherweight Synchronization for Java
- * Proceedings of the ACM Conference on Programming Language Design and
- * Implementation (Montreal, Canada), SIGPLAN Notices volume 33, number 6,
- * June 1998
- *
- * In thin lock mode the lockword looks like this:
- *
- * ,----------------------,-----------,---,
- * | thread ID | count | 0 |
- * `----------------------'-----------'---´
- *
- * thread ID......the 'index' of the owning thread, or 0
- * count..........number of times the lock has been entered minus 1
- * 0..............the shape bit is 0 in thin lock mode
- *
- * In fat lock mode it is basically a lock_record_t *:
- *
- * ,----------------------------------,---,
- * | lock_record_t * (without LSB) | 1 |
- * `----------------------------------'---´
- *
- * 1..............the shape bit is 1 in fat lock mode
- */
-
-#if SIZEOF_VOID_P == 8
-#define THIN_LOCK_WORD_SIZE 64
-#else
-#define THIN_LOCK_WORD_SIZE 32
-#endif
-
-#define THIN_LOCK_SHAPE_BIT 0x01
-
-#define THIN_UNLOCKED 0
-
-#define THIN_LOCK_COUNT_SHIFT 1
-#define THIN_LOCK_COUNT_SIZE 8
-#define THIN_LOCK_COUNT_INCR (1 << THIN_LOCK_COUNT_SHIFT)
-#define THIN_LOCK_COUNT_MAX ((1 << THIN_LOCK_COUNT_SIZE) - 1)
-#define THIN_LOCK_COUNT_MASK (THIN_LOCK_COUNT_MAX << THIN_LOCK_COUNT_SHIFT)
-
-#define THIN_LOCK_TID_SHIFT (THIN_LOCK_COUNT_SIZE + THIN_LOCK_COUNT_SHIFT)
-#define THIN_LOCK_TID_SIZE (THIN_LOCK_WORD_SIZE - THIN_LOCK_TID_SHIFT)
-
-#define IS_THIN_LOCK(lockword) (!((lockword) & THIN_LOCK_SHAPE_BIT))
-#define IS_FAT_LOCK(lockword) ((lockword) & THIN_LOCK_SHAPE_BIT)
-
-#define GET_FAT_LOCK(lockword) ((lock_record_t *) ((lockword) & ~THIN_LOCK_SHAPE_BIT))
-#define MAKE_FAT_LOCK(ptr) ((uintptr_t) (ptr) | THIN_LOCK_SHAPE_BIT)
-
-#define LOCK_WORD_WITHOUT_COUNT(lockword) ((lockword) & ~THIN_LOCK_COUNT_MASK)
-#define GET_THREAD_INDEX(lockword) ((unsigned) lockword >> THIN_LOCK_TID_SHIFT)
-
-
-/* global variables ***********************************************************/
-
-/* hashtable mapping objects to lock records */
-static lock_hashtable_t lock_hashtable;
-
-
-/******************************************************************************/
-/* PROTOTYPES */
-/******************************************************************************/
-
-static void lock_hashtable_init(void);
-
-static inline uintptr_t lock_lockword_get(threadobject *t, java_handle_t *o);
-static inline void lock_lockword_set(threadobject *t, java_handle_t *o, uintptr_t lockword);
-static void lock_record_enter(threadobject *t, lock_record_t *lr);
-static void lock_record_exit(threadobject *t, lock_record_t *lr);
-static bool lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 nanos);
-static void lock_record_notify(threadobject *t, lock_record_t *lr, bool one);
-
-
-/*============================================================================*/
-/* INITIALIZATION OF DATA STRUCTURES */
-/*============================================================================*/
-
-
-/* lock_init *******************************************************************
-
- Initialize global data for locking.
-
-*******************************************************************************/
-
-void lock_init(void)
-{
- /* initialize lock hashtable */
-
- lock_hashtable_init();
-
-#if defined(ENABLE_VMLOG)
- vmlog_cacao_init_lock();
-#endif
-}
-
-
-/* lock_pre_compute_thinlock ***************************************************
-
- Pre-compute the thin lock value for a thread index.
-
- IN:
- index........the thead index (>= 1)
-
- RETURN VALUE:
- the thin lock value for this thread index
-
-*******************************************************************************/
-
-ptrint lock_pre_compute_thinlock(s4 index)
-{
- return (index << THIN_LOCK_TID_SHIFT) | THIN_UNLOCKED;
-}
-
-
-/* lock_record_new *************************************************************
-
- Allocate a lock record.
-
-*******************************************************************************/
-
-static lock_record_t *lock_record_new(void)
-{
- int result;
- lock_record_t *lr;
-
- /* allocate the data structure on the C heap */
-
- lr = NEW(lock_record_t);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_record += sizeof(lock_record_t);
-#endif
-
- /* initialize the members */
-
- lr->object = NULL;
- lr->owner = NULL;
- lr->count = 0;
- lr->waiters = list_create(OFFSET(lock_waiter_t, linkage));
-
-#if defined(ENABLE_GC_CACAO)
- /* register the lock object as weak reference with the GC */
-
- gc_weakreference_register(&(lr->object), GC_REFTYPE_LOCKRECORD);
-#endif
-
- /* initialize the mutex */
-
- result = pthread_mutex_init(&(lr->mutex), NULL);
- if (result != 0)
- vm_abort_errnum(result, "lock_record_new: pthread_mutex_init failed");
-
- DEBUGLOCKS(("[lock_record_new : lr=%p]", (void *) lr));
-
- return lr;
-}
-
-
-/* lock_record_free ************************************************************
-
- Free a lock record.
-
- IN:
- lr....lock record to free
-
-*******************************************************************************/
-
-static void lock_record_free(lock_record_t *lr)
-{
- int result;
-
- DEBUGLOCKS(("[lock_record_free : lr=%p]", (void *) lr));
-
- /* Destroy the mutex. */
-
- result = pthread_mutex_destroy(&(lr->mutex));
- if (result != 0)
- vm_abort_errnum(result, "lock_record_free: pthread_mutex_destroy failed");
-
-#if defined(ENABLE_GC_CACAO)
- /* unregister the lock object reference with the GC */
-
- gc_weakreference_unregister(&(lr->object));
-#endif
-
- /* Free the waiters list. */
-
- list_free(lr->waiters);
-
- /* Free the data structure. */
-
- FREE(lr, lock_record_t);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_record -= sizeof(lock_record_t);
-#endif
-}
-
-
-/*============================================================================*/
-/* HASHTABLE MAPPING OBJECTS TO LOCK RECORDS */
-/*============================================================================*/
-
-/* lock_hashtable_init *********************************************************
-
- Initialize the global hashtable mapping objects to lock records.
-
-*******************************************************************************/
-
-static void lock_hashtable_init(void)
-{
- pthread_mutex_init(&(lock_hashtable.mutex), NULL);
-
- lock_hashtable.size = LOCK_INITIAL_HASHTABLE_SIZE;
- lock_hashtable.entries = 0;
- lock_hashtable.ptr = MNEW(lock_record_t *, lock_hashtable.size);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_hashtable += sizeof(lock_record_t *) * lock_hashtable.size;
-#endif
-
- MZERO(lock_hashtable.ptr, lock_record_t *, lock_hashtable.size);
-}
-
-
-/* lock_hashtable_grow *********************************************************
-
- Grow the lock record hashtable to about twice its current size and
- rehash the entries.
-
-*******************************************************************************/
-
-/* must be called with hashtable mutex locked */
-static void lock_hashtable_grow(void)
-{
- u4 oldsize;
- u4 newsize;
- lock_record_t **oldtable;
- lock_record_t **newtable;
- lock_record_t *lr;
- lock_record_t *next;
- u4 i;
- u4 h;
- u4 newslot;
-
- /* allocate a new table */
-
- oldsize = lock_hashtable.size;
- newsize = oldsize*2 + 1; /* XXX should use prime numbers */
-
- DEBUGLOCKS(("growing lock hashtable to size %d", newsize));
-
- oldtable = lock_hashtable.ptr;
- newtable = MNEW(lock_record_t *, newsize);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_hashtable += sizeof(lock_record_t *) * newsize;
-#endif
-
- MZERO(newtable, lock_record_t *, newsize);
-
- /* rehash the entries */
-
- for (i = 0; i < oldsize; i++) {
- lr = oldtable[i];
- while (lr) {
- next = lr->hashlink;
-
- h = heap_hashcode(lr->object);
- newslot = h % newsize;
-
- lr->hashlink = newtable[newslot];
- newtable[newslot] = lr;
-
- lr = next;
- }
- }
-
- /* replace the old table */
-
- lock_hashtable.ptr = newtable;
- lock_hashtable.size = newsize;
-
- MFREE(oldtable, lock_record_t *, oldsize);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_hashtable -= sizeof(lock_record_t *) * oldsize;
-#endif
-}
-
-
-/* lock_hashtable_cleanup ******************************************************
-
- Removes (and frees) lock records which have a cleared object reference
- from the hashtable. The locked object was reclaimed by the GC.
-
-*******************************************************************************/
-
-#if defined(ENABLE_GC_CACAO)
-void lock_hashtable_cleanup(void)
-{
- threadobject *t;
- lock_record_t *lr;
- lock_record_t *prev;
- lock_record_t *next;
- int i;
-
- t = THREADOBJECT;
-
- /* lock the hashtable */
-
- pthread_mutex_lock(&(lock_hashtable.mutex));
-
- /* search the hashtable for cleared references */
-
- for (i = 0; i < lock_hashtable.size; i++) {
- lr = lock_hashtable.ptr[i];
- prev = NULL;
-
- while (lr) {
- next = lr->hashlink;
-
- /* remove lock records with cleared references */
-
- if (lr->object == NULL) {
-
- /* unlink the lock record from the hashtable */
-
- if (prev == NULL)
- lock_hashtable.ptr[i] = next;
- else
- prev->hashlink = next;
-
- /* free the lock record */
-
- lock_record_free(lr);
-
- } else {
- prev = lr;
- }
-
- lr = next;
- }
- }
-
- /* unlock the hashtable */
-
- pthread_mutex_unlock(&(lock_hashtable.mutex));
-}
-#endif
-
-
-/* lock_hashtable_get **********************************************************
-
- Find the lock record for the given object. If it does not exists,
- yet, create it and enter it in the hashtable.
-
- IN:
- t....the current thread
- o....the object to look up
-
- RETURN VALUE:
- the lock record to use for this object
-
-*******************************************************************************/
-
-#if defined(ENABLE_GC_BOEHM)
-static void lock_record_finalizer(void *object, void *p);
-#endif
-
-static lock_record_t *lock_hashtable_get(threadobject *t, java_handle_t *o)
-{
- uintptr_t lockword;
- u4 slot;
- lock_record_t *lr;
-
- lockword = lock_lockword_get(t, o);
-
- if (IS_FAT_LOCK(lockword))
- return GET_FAT_LOCK(lockword);
-
- /* lock the hashtable */
-
- pthread_mutex_lock(&(lock_hashtable.mutex));
-
- /* lookup the lock record in the hashtable */
-
- LLNI_CRITICAL_START_THREAD(t);
- slot = heap_hashcode(LLNI_DIRECT(o)) % lock_hashtable.size;
- lr = lock_hashtable.ptr[slot];
-
- for (; lr != NULL; lr = lr->hashlink) {
- if (lr->object == LLNI_DIRECT(o))
- break;
- }
- LLNI_CRITICAL_END_THREAD(t);
-
- if (lr == NULL) {
- /* not found, we must create a new one */
-
- lr = lock_record_new();
-
- LLNI_CRITICAL_START_THREAD(t);
- lr->object = LLNI_DIRECT(o);
- LLNI_CRITICAL_END_THREAD(t);
-
-#if defined(ENABLE_GC_BOEHM)
- /* register new finalizer to clean up the lock record */
-
- GC_REGISTER_FINALIZER(LLNI_DIRECT(o), lock_record_finalizer, 0, 0, 0);
-#endif
-
- /* enter it in the hashtable */
-
- lr->hashlink = lock_hashtable.ptr[slot];
- lock_hashtable.ptr[slot] = lr;
- lock_hashtable.entries++;
-
- /* check whether the hash should grow */
-
- if (lock_hashtable.entries * 3 > lock_hashtable.size * 4) {
- lock_hashtable_grow();
- }
- }
-
- /* unlock the hashtable */
-
- pthread_mutex_unlock(&(lock_hashtable.mutex));
-
- /* return the new lock record */
-
- return lr;
-}
-
-
-/* lock_hashtable_remove *******************************************************
-
- Remove the lock record for the given object from the hashtable
- and free it afterwards.
-
- IN:
- t....the current thread
- o....the object to look up
-
-*******************************************************************************/
-
-static void lock_hashtable_remove(threadobject *t, java_handle_t *o)
-{
- uintptr_t lockword;
- lock_record_t *lr;
- u4 slot;
- lock_record_t *tmplr;
-
- /* lock the hashtable */
-
- pthread_mutex_lock(&(lock_hashtable.mutex));
-
- /* get lock record */
-
- lockword = lock_lockword_get(t, o);
-
- assert(IS_FAT_LOCK(lockword));
-
- lr = GET_FAT_LOCK(lockword);
-
- /* remove the lock-record from the hashtable */
-
- LLNI_CRITICAL_START_THREAD(t);
- slot = heap_hashcode(LLNI_DIRECT(o)) % lock_hashtable.size;
- tmplr = lock_hashtable.ptr[slot];
- LLNI_CRITICAL_END_THREAD(t);
-
- if (tmplr == lr) {
- /* special handling if it's the first in the chain */
-
- lock_hashtable.ptr[slot] = lr->hashlink;
- }
- else {
- for (; tmplr != NULL; tmplr = tmplr->hashlink) {
- if (tmplr->hashlink == lr) {
- tmplr->hashlink = lr->hashlink;
- break;
- }
- }
-
- assert(tmplr != NULL);
- }
-
- /* decrease entry count */
-
- lock_hashtable.entries--;
-
- /* unlock the hashtable */
-
- pthread_mutex_unlock(&(lock_hashtable.mutex));
-
- /* free the lock record */
-
- lock_record_free(lr);
-}
-
-
-/* lock_record_finalizer *******************************************************
-
- XXX Remove me for exact GC.
-
-*******************************************************************************/
-
-static void lock_record_finalizer(void *object, void *p)
-{
- java_handle_t *o;
- classinfo *c;
-
- o = (java_handle_t *) object;
-
-#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
- /* XXX this is only a dirty hack to make Boehm work with handles */
-
- o = LLNI_WRAP((java_object_t *) o);
-#endif
-
- LLNI_class_get(o, c);
-
-#if !defined(NDEBUG)
- if (opt_DebugFinalizer) {
- log_start();
- log_print("[finalizer lockrecord: o=%p p=%p class=", object, p);
- class_print(c);
- log_print("]");
- log_finish();
- }
-#endif
-
- /* check for a finalizer function */
-
- if (c->finalizer != NULL)
- finalizer_run(object, p);
-
- /* remove the lock-record entry from the hashtable and free it */
-
- lock_hashtable_remove(THREADOBJECT, o);
-}
-
-
-/*============================================================================*/
-/* OBJECT LOCK INITIALIZATION */
-/*============================================================================*/
-
-
-/* lock_init_object_lock *******************************************************
-
- Initialize the monitor pointer of the given object. The monitor gets
- initialized to an unlocked state.
-
-*******************************************************************************/
-
-void lock_init_object_lock(java_object_t *o)
-{
- assert(o);
-
- o->lockword = THIN_UNLOCKED;
-}
-
-
-/*============================================================================*/
-/* LOCKING ALGORITHM */
-/*============================================================================*/
-
-
-/* lock_lockword_get ***********************************************************
-
- Get the lockword for the given object.
-
- IN:
- t............the current thread
- o............the object
-
-*******************************************************************************/
-
-static inline uintptr_t lock_lockword_get(threadobject *t, java_handle_t *o)
-{
- uintptr_t lockword;
-
- LLNI_CRITICAL_START_THREAD(t);
- lockword = LLNI_DIRECT(o)->lockword;
- LLNI_CRITICAL_END_THREAD(t);
-
- return lockword;
-}
-
-
-/* lock_lockword_set ***********************************************************
-
- Set the lockword for the given object.
-
- IN:
- t............the current thread
- o............the object
- lockword.....the new lockword value
-
-*******************************************************************************/
-
-static inline void lock_lockword_set(threadobject *t, java_handle_t *o, uintptr_t lockword)
-{
- LLNI_CRITICAL_START_THREAD(t);
- LLNI_DIRECT(o)->lockword = lockword;
- LLNI_CRITICAL_END_THREAD(t);
-}
-
-
-/* lock_record_enter ***********************************************************
-
- Enter the lock represented by the given lock record.
-
- IN:
- t.................the current thread
- lr................the lock record
-
-*******************************************************************************/
-
-static inline void lock_record_enter(threadobject *t, lock_record_t *lr)
-{
- pthread_mutex_lock(&(lr->mutex));
- lr->owner = t;
-}
-
-
-/* lock_record_exit ************************************************************
-
- Release the lock represented by the given lock record.
-
- IN:
- t.................the current thread
- lr................the lock record
-
- PRE-CONDITION:
- The current thread must own the lock represented by this lock record.
- This is NOT checked by this function!
-
-*******************************************************************************/
-
-static inline void lock_record_exit(threadobject *t, lock_record_t *lr)
-{
- lr->owner = NULL;
- pthread_mutex_unlock(&(lr->mutex));
-}
-
-
-/* lock_inflate ****************************************************************
-
- Inflate the lock of the given object. This may only be called by the
- owner of the monitor of the object.
-
- IN:
- t............the current thread
- o............the object of which to inflate the lock
- lr...........the lock record to install. The current thread must
- own the lock of this lock record!
-
- PRE-CONDITION:
- The current thread must be the owner of this object's monitor AND
- of the lock record's lock!
-
-*******************************************************************************/
-
-static void lock_inflate(threadobject *t, java_handle_t *o, lock_record_t *lr)
-{
- uintptr_t lockword;
-
- /* get the current lock count */
-
- lockword = lock_lockword_get(t, o);
-
- if (IS_FAT_LOCK(lockword)) {
- assert(GET_FAT_LOCK(lockword) == lr);
- return;
- }
- else {
- assert(LOCK_WORD_WITHOUT_COUNT(lockword) == t->thinlock);
-
- /* copy the count from the thin lock */
-
- lr->count = (lockword & THIN_LOCK_COUNT_MASK) >> THIN_LOCK_COUNT_SHIFT;
- }
-
- DEBUGLOCKS(("[lock_inflate : lr=%p, t=%p, o=%p, o->lockword=%lx, count=%d]",
- lr, t, o, lockword, lr->count));
-
- /* install it */
-
- lock_lockword_set(t, o, MAKE_FAT_LOCK(lr));
-}
-
-
-/* TODO Move this function into threadlist.[ch]. */
-
-static threadobject *threads_lookup_thread_id(int index)
-{
- threadobject *t;
-
- threadlist_lock();
-
- for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
- if (t->state == THREAD_STATE_NEW)
- continue;
- if (t->index == index)
- break;
- }
-
- threadlist_unlock();
- return t;
-}
-
-static void sable_flc_waiting(ptrint lockword, threadobject *t, java_handle_t *o)
-{
- int index;
- threadobject *t_other;
- int old_flc;
-
- index = GET_THREAD_INDEX(lockword);
- t_other = threads_lookup_thread_id(index);
- if (!t_other)
-/* failure, TODO: add statistics */
- return;
-
- pthread_mutex_lock(&t_other->flc_lock);
- old_flc = t_other->flc_bit;
- t_other->flc_bit = true;
-
- DEBUGLOCKS(("thread %d set flc bit for lock-holding thread %d",
- t->index, t_other->index));
-
- /* Set FLC bit first, then read the lockword again */
- MEMORY_BARRIER();
-
- lockword = lock_lockword_get(t, o);
-
- /* Lockword is still the way it was seen before */
- if (IS_THIN_LOCK(lockword) && (GET_THREAD_INDEX(lockword) == index))
- {
- /* Add tuple (t, o) to the other thread's FLC list */
- t->flc_object = o;
- t->flc_next = t_other->flc_list;
- t_other->flc_list = t;
-
- for (;;)
- {
- threadobject *current;
-
- /* Wait until another thread sees the flc bit and notifies
- us of unlocking. */
- pthread_cond_wait(&t->flc_cond, &t_other->flc_lock);
-
- /* Traverse FLC list looking if we're still there */
- current = t_other->flc_list;
- while (current && current != t)
- current = current->flc_next;
- if (!current)
- /* not in list anymore, can stop waiting */
- break;
-
- /* We are still in the list -- the other thread cannot have seen
- the FLC bit yet */
- assert(t_other->flc_bit);
- }
-
- t->flc_object = NULL; /* for garbage collector? */
- t->flc_next = NULL;
- }
- else
- t_other->flc_bit = old_flc;
-
- pthread_mutex_unlock(&t_other->flc_lock);
-}
-
-static void notify_flc_waiters(threadobject *t, java_handle_t *o)
-{
- threadobject *current;
-
- pthread_mutex_lock(&t->flc_lock);
-
- current = t->flc_list;
- while (current)
- {
- if (current->flc_object != o)
- {
- /* The object has to be inflated so the other threads can properly
- block on it. */
-
- /* Only if not already inflated */
- ptrint lockword = lock_lockword_get(t, current->flc_object);
- if (IS_THIN_LOCK(lockword)) {
- lock_record_t *lr = lock_hashtable_get(t, current->flc_object);
- lock_record_enter(t, lr);
-
- DEBUGLOCKS(("thread %d inflating lock of %p to lr %p",
- t->index, (void*) current->flc_object, (void*) lr));
-
- lock_inflate(t, current->flc_object, lr);
- }
- }
- /* Wake the waiting thread */
- pthread_cond_broadcast(¤t->flc_cond);
-
- current = current->flc_next;
- }
-
- t->flc_list = NULL;
- t->flc_bit = false;
- pthread_mutex_unlock(&t->flc_lock);
-}
-
-/* lock_monitor_enter **********************************************************
-
- Acquire the monitor of the given object. If the current thread already
- owns the monitor, the lock counter is simply increased.
-
- This function blocks until it can acquire the monitor.
-
- IN:
- t............the current thread
- o............the object of which to enter the monitor
-
- RETURN VALUE:
- true.........the lock has been successfully acquired
- false........an exception has been thrown
-
-*******************************************************************************/
-
-bool lock_monitor_enter(java_handle_t *o)
-{
- threadobject *t;
- /* CAUTION: This code assumes that ptrint is unsigned! */
- ptrint lockword;
- ptrint thinlock;
- lock_record_t *lr;
-
- if (o == NULL) {
- exceptions_throw_nullpointerexception();
- return false;
- }
-
- t = THREADOBJECT;
-
- thinlock = t->thinlock;
-
-retry:
- /* most common case: try to thin-lock an unlocked object */
-
- LLNI_CRITICAL_START_THREAD(t);
- lockword = COMPARE_AND_SWAP_OLD_VALUE(&(LLNI_DIRECT(o)->lockword), THIN_UNLOCKED, thinlock);
- LLNI_CRITICAL_END_THREAD(t);
-
- if (lockword == THIN_UNLOCKED) {
- /* success. we locked it */
- /* The Java Memory Model requires a memory barrier here: */
- /* Because of the CAS above, this barrier is a nop on x86 / x86_64 */
- MEMORY_BARRIER_AFTER_ATOMIC();
- return true;
- }
-
- /* next common case: recursive lock with small recursion count */
- /* We don't have to worry about stale values here, as any stale value */
- /* will indicate another thread holding the lock (or an inflated lock) */
-
- if (LOCK_WORD_WITHOUT_COUNT(lockword) == thinlock) {
- /* we own this monitor */
- /* check the current recursion count */
-
- if ((lockword ^ thinlock) < (THIN_LOCK_COUNT_MAX << THIN_LOCK_COUNT_SHIFT))
- {
- /* the recursion count is low enough */
-
- lock_lockword_set(t, o, lockword + THIN_LOCK_COUNT_INCR);
-
- /* success. we locked it */
- return true;
- }
- else {
- /* recursion count overflow */
-
- lr = lock_hashtable_get(t, o);
- lock_record_enter(t, lr);
- lock_inflate(t, o, lr);
- lr->count++;
-
- notify_flc_waiters(t, o);
-
- return true;
- }
- }
-
- /* the lock is either contented or fat */
-
- if (IS_FAT_LOCK(lockword)) {
-
- lr = GET_FAT_LOCK(lockword);
-
- /* check for recursive entering */
- if (lr->owner == t) {
- lr->count++;
- return true;
- }
-
- /* acquire the mutex of the lock record */
-
- lock_record_enter(t, lr);
-
- assert(lr->count == 0);
-
- return true;
- }
-
- /****** inflation path ******/
-
-#if defined(ENABLE_JVMTI)
- /* Monitor Contended Enter */
- jvmti_MonitorContendedEntering(false, o);
-#endif
-
- sable_flc_waiting(lockword, t, o);
-
-#if defined(ENABLE_JVMTI)
- /* Monitor Contended Entered */
- jvmti_MonitorContendedEntering(true, o);
-#endif
- goto retry;
-}
-
-
-/* lock_monitor_exit ***********************************************************
-
- Decrement the counter of a (currently owned) monitor. If the counter
- reaches zero, release the monitor.
-
- If the current thread is not the owner of the monitor, an
- IllegalMonitorState exception is thrown.
-
- IN:
- t............the current thread
- o............the object of which to exit the monitor
-
- RETURN VALUE:
- true.........everything ok,
- false........an exception has been thrown
-
-*******************************************************************************/
-
-bool lock_monitor_exit(java_handle_t *o)
-{
- threadobject *t;
- uintptr_t lockword;
- ptrint thinlock;
-
- if (o == NULL) {
- exceptions_throw_nullpointerexception();
- return false;
- }
-
- t = THREADOBJECT;
-
- thinlock = t->thinlock;
-
- /* We don't have to worry about stale values here, as any stale value */
- /* will indicate that we don't own the lock. */
-
- lockword = lock_lockword_get(t, o);
-
- /* most common case: we release a thin lock that we hold once */
-
- if (lockword == thinlock) {
- /* memory barrier for Java Memory Model */
- STORE_ORDER_BARRIER();
- lock_lockword_set(t, o, THIN_UNLOCKED);
- /* memory barrier for thin locking */
- MEMORY_BARRIER();
-
- /* check if there has been a flat lock contention on this object */
-
- if (t->flc_bit) {
- DEBUGLOCKS(("thread %d saw flc bit", t->index));
-
- /* there has been a contention on this thin lock */
- notify_flc_waiters(t, o);
- }
-
- return true;
- }
-
- /* next common case: we release a recursive lock, count > 0 */
-
- if (LOCK_WORD_WITHOUT_COUNT(lockword) == thinlock) {
- lock_lockword_set(t, o, lockword - THIN_LOCK_COUNT_INCR);
- return true;
- }
-
- /* either the lock is fat, or we don't hold it at all */
-
- if (IS_FAT_LOCK(lockword)) {
-
- lock_record_t *lr;
-
- lr = GET_FAT_LOCK(lockword);
-
- /* check if we own this monitor */
- /* We don't have to worry about stale values here, as any stale value */
- /* will be != t and thus fail this check. */
-
- if (lr->owner != t) {
- exceptions_throw_illegalmonitorstateexception();
- return false;
- }
-
- /* { the current thread `t` owns the lock record `lr` on object `o` } */
-
- if (lr->count != 0) {
- /* we had locked this one recursively. just decrement, it will */
- /* still be locked. */
- lr->count--;
- return true;
- }
-
- /* unlock this lock record */
-
- lr->owner = NULL;
- pthread_mutex_unlock(&(lr->mutex));
-
- return true;
- }
-
- /* legal thin lock cases have been handled above, so this is an error */
-
- exceptions_throw_illegalmonitorstateexception();
-
- return false;
-}
-
-
-/* lock_record_add_waiter ******************************************************
-
- Add a thread to the list of waiting threads of a lock record.
-
- IN:
- lr...........the lock record
- thread.......the thread to add
-
-*******************************************************************************/
-
-static void lock_record_add_waiter(lock_record_t *lr, threadobject *thread)
-{
- lock_waiter_t *w;
-
- /* Allocate a waiter data structure. */
-
- w = NEW(lock_waiter_t);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_waiter += sizeof(lock_waiter_t);
-#endif
-
- /* Store the thread in the waiter structure. */
-
- w->thread = thread;
-
- /* Add the waiter as last entry to waiters list. */
-
- list_add_last(lr->waiters, w);
-}
-
-
-/* lock_record_remove_waiter ***************************************************
-
- Remove a thread from the list of waiting threads of a lock record.
-
- IN:
- lr...........the lock record
- t............the current thread
-
- PRE-CONDITION:
- The current thread must be the owner of the lock record.
-
-*******************************************************************************/
-
-static void lock_record_remove_waiter(lock_record_t *lr, threadobject *thread)
-{
- list_t *l;
- lock_waiter_t *w;
-
- /* Get the waiters list. */
-
- l = lr->waiters;
-
- for (w = list_first(l); w != NULL; w = list_next(l, w)) {
- if (w->thread == thread) {
- /* Remove the waiter entry from the list. */
-
- list_remove(l, w);
-
- /* Free the waiter data structure. */
-
- FREE(w, lock_waiter_t);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lock_waiter -= sizeof(lock_waiter_t);
-#endif
-
- return;
- }
- }
-
- /* This should never happen. */
-
- vm_abort("lock_record_remove_waiter: thread not found in list of waiters\n");
-}
-
-
-/* lock_record_wait ************************************************************
-
- Wait on a lock record for a given (maximum) amount of time.
-
- IN:
- t............the current thread
- lr...........the lock record
- millis.......milliseconds of timeout
- nanos........nanoseconds of timeout
-
- RETURN VALUE:
- true.........we have been interrupted,
- false........everything ok
-
- PRE-CONDITION:
- The current thread must be the owner of the lock record.
- This is NOT checked by this function!
-
-*******************************************************************************/
-
-static bool lock_record_wait(threadobject *thread, lock_record_t *lr, s8 millis, s4 nanos)
-{
- s4 lockcount;
- bool wasinterrupted = false;
-
- DEBUGLOCKS(("[lock_record_wait : lr=%p, t=%p, millis=%lld, nanos=%d]",
- lr, thread, millis, nanos));
-
- /* { the thread t owns the fat lock record lr on the object o } */
-
- /* register us as waiter for this object */
-
- lock_record_add_waiter(lr, thread);
-
- /* remember the old lock count */
-
- lockcount = lr->count;
-
- /* unlock this record */
-
- lr->count = 0;
- lock_record_exit(thread, lr);
-
- /* wait until notified/interrupted/timed out */
-
- threads_wait_with_timeout_relative(thread, millis, nanos);
-
- /* re-enter the monitor */
-
- lock_record_enter(thread, lr);
-
- /* remove us from the list of waiting threads */
-
- lock_record_remove_waiter(lr, thread);
-
- /* restore the old lock count */
-
- lr->count = lockcount;
-
- /* We can only be signaled OR interrupted, not both. If both flags
- are set, reset only signaled and leave the thread in
- interrupted state. Otherwise, clear both. */
-
- if (!thread->signaled) {
- wasinterrupted = thread->interrupted;
- thread->interrupted = false;
- }
-
- thread->signaled = false;
-
- /* return if we have been interrupted */
-
- return wasinterrupted;
-}
-
-
-/* lock_monitor_wait ***********************************************************
-
- Wait on an object for a given (maximum) amount of time.
-
- IN:
- t............the current thread
- o............the object
- millis.......milliseconds of timeout
- nanos........nanoseconds of timeout
-
- PRE-CONDITION:
- The current thread must be the owner of the object's monitor.
-
-*******************************************************************************/
-
-static void lock_monitor_wait(threadobject *t, java_handle_t *o, s8 millis, s4 nanos)
-{
- uintptr_t lockword;
- lock_record_t *lr;
-
- lockword = lock_lockword_get(t, o);
-
- /* check if we own this monitor */
- /* We don't have to worry about stale values here, as any stale value */
- /* will fail this check. */
-
- if (IS_FAT_LOCK(lockword)) {
-
- lr = GET_FAT_LOCK(lockword);
-
- if (lr->owner != t) {
- exceptions_throw_illegalmonitorstateexception();
- return;
- }
- }
- else {
- /* it's a thin lock */
-
- if (LOCK_WORD_WITHOUT_COUNT(lockword) != t->thinlock) {
- exceptions_throw_illegalmonitorstateexception();
- return;
- }
-
- /* inflate this lock */
-
- lr = lock_hashtable_get(t, o);
- lock_record_enter(t, lr);
- lock_inflate(t, o, lr);
-
- notify_flc_waiters(t, o);
- }
-
- /* { the thread t owns the fat lock record lr on the object o } */
-
- if (lock_record_wait(t, lr, millis, nanos))
- exceptions_throw_interruptedexception();
-}
-
-
-/* lock_record_notify **********************************************************
-
- Notify one thread or all threads waiting on the given lock record.
-
- IN:
- t............the current thread
- lr...........the lock record
- one..........if true, only notify one thread
-
- PRE-CONDITION:
- The current thread must be the owner of the lock record.
- This is NOT checked by this function!
-
-*******************************************************************************/
-
-static void lock_record_notify(threadobject *t, lock_record_t *lr, bool one)
-{
- list_t *l;
- lock_waiter_t *w;
- threadobject *waitingthread;
-
- /* { the thread t owns the fat lock record lr on the object o } */
-
- /* Get the waiters list. */
-
- l = lr->waiters;
-
- for (w = list_first(l); w != NULL; w = list_next(l, w)) {
- /* signal the waiting thread */
-
- waitingthread = w->thread;
-
- /* We must skip threads which have already been notified or
- interrupted. They will remove themselves from the list. */
-
- if (waitingthread->signaled || waitingthread->interrupted)
- continue;
-
- /* Enter the wait-mutex. */
-
- pthread_mutex_lock(&(waitingthread->waitmutex));
-
- DEBUGLOCKS(("[lock_record_notify: lr=%p, t=%p, waitingthread=%p, sleeping=%d, one=%d]",
- lr, t, waitingthread, waitingthread->sleeping, one));
-
- /* Signal the thread if it's sleeping. sleeping can be false
- when the waiting thread is blocked between giving up the
- monitor and entering the waitmutex. It will eventually
- observe that it's signaled and refrain from going to
- sleep. */
-
- if (waitingthread->sleeping)
- pthread_cond_signal(&(waitingthread->waitcond));
-
- /* Mark the thread as signaled. */
-
- waitingthread->signaled = true;
-
- /* Leave the wait-mutex. */
-
- pthread_mutex_unlock(&(waitingthread->waitmutex));
-
- /* if we should only wake one, we are done */
-
- if (one)
- break;
- }
-}
-
-
-/* lock_monitor_notify *********************************************************
-
- Notify one thread or all threads waiting on the given object.
-
- IN:
- t............the current thread
- o............the object
- one..........if true, only notify one thread
-
- PRE-CONDITION:
- The current thread must be the owner of the object's monitor.
-
-*******************************************************************************/
-
-static void lock_monitor_notify(threadobject *t, java_handle_t *o, bool one)
-{
- uintptr_t lockword;
- lock_record_t *lr;
-
- lockword = lock_lockword_get(t, o);
-
- /* check if we own this monitor */
- /* We don't have to worry about stale values here, as any stale value */
- /* will fail this check. */
-
- if (IS_FAT_LOCK(lockword)) {
-
- lr = GET_FAT_LOCK(lockword);
-
- if (lr->owner != t) {
- exceptions_throw_illegalmonitorstateexception();
- return;
- }
- }
- else {
- /* it's a thin lock */
-
- if (LOCK_WORD_WITHOUT_COUNT(lockword) != t->thinlock) {
- exceptions_throw_illegalmonitorstateexception();
- return;
- }
-
- /* no thread can wait on a thin lock, so there's nothing to do. */
- return;
- }
-
- /* { the thread t owns the fat lock record lr on the object o } */
-
- lock_record_notify(t, lr, one);
-}
-
-
-
-/*============================================================================*/
-/* INQUIRY FUNCIONS */
-/*============================================================================*/
-
-
-/* lock_is_held_by_current_thread **********************************************
-
- Return true if the current thread owns the monitor of the given object.
-
- IN:
- o............the object
-
- RETURN VALUE:
- true, if the current thread holds the lock of this object.
-
-*******************************************************************************/
-
-bool lock_is_held_by_current_thread(java_handle_t *o)
-{
- threadobject *t;
- uintptr_t lockword;
- lock_record_t *lr;
-
- t = THREADOBJECT;
-
- /* check if we own this monitor */
- /* We don't have to worry about stale values here, as any stale value */
- /* will fail this check. */
-
- lockword = lock_lockword_get(t, o);
-
- if (IS_FAT_LOCK(lockword)) {
- /* it's a fat lock */
-
- lr = GET_FAT_LOCK(lockword);
-
- return (lr->owner == t);
- }
- else {
- /* it's a thin lock */
-
- return (LOCK_WORD_WITHOUT_COUNT(lockword) == t->thinlock);
- }
-}
-
-
-
-/*============================================================================*/
-/* WRAPPERS FOR OPERATIONS ON THE CURRENT THREAD */
-/*============================================================================*/
-
-
-/* lock_wait_for_object ********************************************************
-
- Wait for the given object.
-
- IN:
- o............the object
- millis.......milliseconds to wait
- nanos........nanoseconds to wait
-
-*******************************************************************************/
-
-void lock_wait_for_object(java_handle_t *o, s8 millis, s4 nanos)
-{
- threadobject *thread;
-
- thread = THREADOBJECT;
-
- lock_monitor_wait(thread, o, millis, nanos);
-}
-
-
-/* lock_notify_object **********************************************************
-
- Notify one thread waiting on the given object.
-
- IN:
- o............the object
-
-*******************************************************************************/
-
-void lock_notify_object(java_handle_t *o)
-{
- threadobject *thread;
-
- thread = THREADOBJECT;
-
- lock_monitor_notify(thread, o, true);
-}
-
-
-/* lock_notify_all_object ******************************************************
-
- Notify all threads waiting on the given object.
-
- IN:
- o............the object
-
-*******************************************************************************/
-
-void lock_notify_all_object(java_handle_t *o)
-{
- threadobject *thread;
-
- thread = THREADOBJECT;
-
- lock_monitor_notify(thread, o, false);
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
+++ /dev/null
-/* src/threads/native/lock.h - lock implementation
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _LOCK_H
-#define _LOCK_H
-
-#include "config.h"
-
-#include <pthread.h>
-
-#include "vm/types.h"
-
-#include "native/llni.h"
-
-#include "toolbox/list.h"
-
-#include "vm/global.h"
-
-
-
-/* typedefs *******************************************************************/
-
-typedef struct lock_record_t lock_record_t;
-typedef struct lock_waiter_t lock_waiter_t;
-typedef struct lock_hashtable_t lock_hashtable_t;
-
-
-/* lock_waiter_t ***************************************************************
-
- List node for storing a waiting thread.
-
-*******************************************************************************/
-
-struct lock_waiter_t {
- struct threadobject *thread; /* the waiting thread */
- listnode_t linkage;
-};
-
-
-/* lock_record_t ***************************************************************
-
- Lock record struct representing an inflated ("fat") lock.
-
-*******************************************************************************/
-
-struct lock_record_t {
- java_object_t *object; /* object for which this lock is */
- struct threadobject *owner; /* current owner of this monitor */
- s4 count; /* recursive lock count */
- pthread_mutex_t mutex; /* mutex for synchronizing */
- list_t *waiters; /* list of threads waiting */
- lock_record_t *hashlink; /* next record in hash chain */
-};
-
-
-/* lock_hashtable_t ************************************************************
-
- The global hashtable mapping objects to lock records.
-
-*******************************************************************************/
-
-struct lock_hashtable_t {
- pthread_mutex_t mutex; /* mutex for synch. access to the table */
- u4 size; /* number of slots */
- u4 entries; /* current number of entries */
- lock_record_t **ptr; /* the table of slots, uses ext. chain. */
-};
-
-
-/* defines ********************************************************************/
-
-#define LOCK_INIT_OBJECT_LOCK(o) lock_init_object_lock((java_object_t *) (o))
-
-#define LOCK_MONITOR_ENTER(o) lock_monitor_enter((java_handle_t *) LLNI_QUICKWRAP(o))
-#define LOCK_MONITOR_EXIT(o) lock_monitor_exit((java_handle_t *) LLNI_QUICKWRAP(o))
-
-#define LOCK_WAIT_FOREVER(o) lock_wait_for_object((java_handle_t *) LLNI_QUICKWRAP(o), 0, 0)
-#define LOCK_NOTIFY(o) lock_notify_object((java_handle_t *) LLNI_QUICKWRAP(o))
-
-#endif /* _LOCK_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
+++ /dev/null
-/* src/threads/native/threadlist-posix.c - POSIX threadlist functions
-
- Copyright (C) 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <pthread.h>
-
-#include "vm/vm.h"
-
-#include "vmcore/options.h"
-
-
-/* global variables ***********************************************************/
-
-/* global mutex for the thread list */
-static pthread_mutex_t threadlist_mutex;
-
-
-/* threadlist_impl_init ********************************************************
-
- Do some early initialization of stuff required.
-
-*******************************************************************************/
-
-void threadlist_impl_init(void)
-{
- int result;
-
- TRACESUBSYSTEMINITIALIZATION("threadlist_impl_init");
-
- /* Initialize the thread list mutex. */
-
- result = pthread_mutex_init(&threadlist_mutex, NULL);
-
- if (result != 0)
- vm_abort_errnum(result, "threadlist_impl_init: pthread_mutex_init failed");
-}
-
-
-/* threadlist_lock *************************************************************
-
- Enter the thread list mutex.
-
- NOTE: We need this function as we can't use an internal lock for
- the threads lists because the thread's lock is initialized in
- threads_table_add (when we have the thread index), but we
- already need the lock at the entry of the function.
-
-*******************************************************************************/
-
-void threadlist_lock(void)
-{
- int result;
-
- result = pthread_mutex_lock(&threadlist_mutex);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_list_lock: pthread_mutex_lock failed");
-}
-
-
-/* threadlist_unlock *********************************************************
-
- Leave the thread list mutex.
-
-*******************************************************************************/
-
-void threadlist_unlock(void)
-{
- int result;
-
- result = pthread_mutex_unlock(&threadlist_mutex);
-
- if (result != 0)
- vm_abort_errnum(result, "threadlist_unlock: pthread_mutex_unlock failed");
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
+++ /dev/null
-/* src/threads/native/threads.c - native threads support
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-/* XXX cleanup these includes */
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-
-#include <pthread.h>
-
-#include "vm/types.h"
-
-#include "arch.h"
-
-#if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
-# include "machine-instr.h"
-#else
-# include "threads/native/generic-primitives.h"
-#endif
-
-#include "mm/gc-common.h"
-#include "mm/memory.h"
-
-#if defined(ENABLE_GC_CACAO)
-# include "mm/cacao-gc/gc.h"
-#endif
-
-#include "native/jni.h"
-#include "native/llni.h"
-#include "native/native.h"
-#include "native/include/java_lang_Object.h"
-#include "native/include/java_lang_String.h"
-#include "native/include/java_lang_Throwable.h"
-#include "native/include/java_lang_Thread.h"
-
-#if defined(ENABLE_JAVASE)
-# include "native/include/java_lang_ThreadGroup.h"
-#endif
-
-#if defined(WITH_CLASSPATH_GNU)
-# include "native/include/java_lang_VMThread.h"
-#endif
-
-#include "threads/lock-common.h"
-#include "threads/threadlist.h"
-#include "threads/threads-common.h"
-
-#include "threads/native/threads.h"
-
-#include "toolbox/logging.h"
-
-#include "vm/builtin.h"
-#include "vm/exceptions.h"
-#include "vm/global.h"
-#include "vm/stringlocal.h"
-#include "vm/vm.h"
-
-#include "vm/jit/asmpart.h"
-
-#include "vmcore/options.h"
-
-#if defined(ENABLE_STATISTICS)
-# include "vmcore/statistics.h"
-#endif
-
-#if !defined(__DARWIN__)
-# if defined(__LINUX__)
-# define GC_LINUX_THREADS
-# elif defined(__IRIX__)
-# define GC_IRIX_THREADS
-# endif
-# include <semaphore.h>
-# if defined(ENABLE_GC_BOEHM)
-# include "mm/boehm-gc/include/gc.h"
-# endif
-#endif
-
-#if defined(ENABLE_JVMTI)
-#include "native/jvmti/cacaodbg.h"
-#endif
-
-#if defined(__DARWIN__)
-/* Darwin has no working semaphore implementation. This one is taken
- from Boehm-GC. */
-
-/*
- This is a very simple semaphore implementation for darwin. It
- is implemented in terms of pthreads calls so it isn't async signal
- safe. This isn't a problem because signals aren't used to
- suspend threads on darwin.
-*/
-
-static int sem_init(sem_t *sem, int pshared, int value)
-{
- if (pshared)
- assert(0);
-
- sem->value = value;
-
- if (pthread_mutex_init(&sem->mutex, NULL) < 0)
- return -1;
-
- if (pthread_cond_init(&sem->cond, NULL) < 0)
- return -1;
-
- return 0;
-}
-
-static int sem_post(sem_t *sem)
-{
- if (pthread_mutex_lock(&sem->mutex) < 0)
- return -1;
-
- sem->value++;
-
- if (pthread_cond_signal(&sem->cond) < 0) {
- pthread_mutex_unlock(&sem->mutex);
- return -1;
- }
-
- if (pthread_mutex_unlock(&sem->mutex) < 0)
- return -1;
-
- return 0;
-}
-
-static int sem_wait(sem_t *sem)
-{
- if (pthread_mutex_lock(&sem->mutex) < 0)
- return -1;
-
- while (sem->value == 0) {
- pthread_cond_wait(&sem->cond, &sem->mutex);
- }
-
- sem->value--;
-
- if (pthread_mutex_unlock(&sem->mutex) < 0)
- return -1;
-
- return 0;
-}
-
-static int sem_destroy(sem_t *sem)
-{
- if (pthread_cond_destroy(&sem->cond) < 0)
- return -1;
-
- if (pthread_mutex_destroy(&sem->mutex) < 0)
- return -1;
-
- return 0;
-}
-#endif /* defined(__DARWIN__) */
-
-
-/* internally used constants **************************************************/
-
-/* CAUTION: Do not change these values. Boehm GC code depends on them. */
-#define STOPWORLD_FROM_GC 1
-#define STOPWORLD_FROM_CLASS_NUMBERING 2
-
-
-/* startupinfo *****************************************************************
-
- Struct used to pass info from threads_start_thread to
- threads_startup_thread.
-
-******************************************************************************/
-
-typedef struct {
- threadobject *thread; /* threadobject for this thread */
- functionptr function; /* function to run in the new thread */
- sem_t *psem; /* signals when thread has been entered */
- /* in the thread list */
- sem_t *psem_first; /* signals when pthread_create has returned */
-} startupinfo;
-
-
-/* prototypes *****************************************************************/
-
-static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos);
-
-
-/******************************************************************************/
-/* GLOBAL VARIABLES */
-/******************************************************************************/
-
-/* the thread object of the current thread */
-/* This is either a thread-local variable defined with __thread, or */
-/* a thread-specific value stored with key threads_current_threadobject_key. */
-#if defined(HAVE___THREAD)
-__thread threadobject *threads_current_threadobject;
-#else
-pthread_key_t threads_current_threadobject_key;
-#endif
-
-/* global mutex for stop-the-world */
-static pthread_mutex_t stopworldlock;
-
-#if defined(ENABLE_GC_CACAO)
-/* global mutex for the GC */
-static pthread_mutex_t mutex_gc;
-#endif
-
-/* global mutex and condition for joining threads on exit */
-static pthread_mutex_t mutex_join;
-static pthread_cond_t cond_join;
-
-/* XXX We disable that whole bunch of code until we have the exact-GC
- running. */
-
-#if 1
-
-/* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
-/* being stopped */
-static volatile int stopworldwhere;
-
-/* semaphore used for acknowleding thread suspension */
-static sem_t suspend_ack;
-#if defined(__IRIX__)
-static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
-#endif
-
-#endif /* 0 */
-
-/* mutexes used by the fake atomic instructions */
-#if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
-pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-
-/* threads_sem_init ************************************************************
-
- Initialize a semaphore. Checks against errors and interruptions.
-
- IN:
- sem..............the semaphore to initialize
- shared...........true if this semaphore will be shared between processes
- value............the initial value for the semaphore
-
-*******************************************************************************/
-
-void threads_sem_init(sem_t *sem, bool shared, int value)
-{
- int r;
-
- assert(sem);
-
- do {
- r = sem_init(sem, shared, value);
- if (r == 0)
- return;
- } while (errno == EINTR);
-
- vm_abort("sem_init failed: %s", strerror(errno));
-}
-
-
-/* threads_sem_wait ************************************************************
-
- Wait for a semaphore, non-interruptible.
-
- IMPORTANT: Always use this function instead of `sem_wait` directly, as
- `sem_wait` may be interrupted by signals!
-
- IN:
- sem..............the semaphore to wait on
-
-*******************************************************************************/
-
-void threads_sem_wait(sem_t *sem)
-{
- int r;
-
- assert(sem);
-
- do {
- r = sem_wait(sem);
- if (r == 0)
- return;
- } while (errno == EINTR);
-
- vm_abort("sem_wait failed: %s", strerror(errno));
-}
-
-
-/* threads_sem_post ************************************************************
-
- Increase the count of a semaphore. Checks for errors.
-
- IN:
- sem..............the semaphore to increase the count of
-
-*******************************************************************************/
-
-void threads_sem_post(sem_t *sem)
-{
- int r;
-
- assert(sem);
-
- /* unlike sem_wait, sem_post is not interruptible */
-
- r = sem_post(sem);
- if (r == 0)
- return;
-
- vm_abort("sem_post failed: %s", strerror(errno));
-}
-
-
-/* lock_stopworld **************************************************************
-
- Enter the stopworld lock, specifying why the world shall be stopped.
-
- IN:
- where........ STOPWORLD_FROM_GC (1) from within GC
- STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
-
-******************************************************************************/
-
-void lock_stopworld(int where)
-{
- pthread_mutex_lock(&stopworldlock);
-/* stopworldwhere = where; */
-}
-
-
-/* unlock_stopworld ************************************************************
-
- Release the stopworld lock.
-
-******************************************************************************/
-
-void unlock_stopworld(void)
-{
-/* stopworldwhere = 0; */
- pthread_mutex_unlock(&stopworldlock);
-}
-
-/* XXX We disable that whole bunch of code until we have the exact-GC
- running. */
-
-#if 0
-
-#if !defined(__DARWIN__)
-/* Caller must hold threadlistlock */
-static s4 threads_cast_sendsignals(s4 sig)
-{
- threadobject *t;
- threadobject *self;
- s4 count;
-
- self = THREADOBJECT;
-
- /* iterate over all started threads */
-
- count = 0;
-
- for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
- /* don't send the signal to ourself */
-
- if (t == self)
- continue;
-
- /* don't send the signal to NEW threads (because they are not
- completely initialized) */
-
- if (t->state == THREAD_STATE_NEW)
- continue;
-
- /* send the signal */
-
- pthread_kill(t->tid, sig);
-
- /* increase threads count */
-
- count++;
- }
-
- return count;
-}
-
-#else
-
-static void threads_cast_darwinstop(void)
-{
- threadobject *tobj = mainthreadobj;
- threadobject *self = THREADOBJECT;
-
- do {
- if (tobj != self)
- {
- thread_state_flavor_t flavor = MACHINE_THREAD_STATE;
- mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
-#if defined(__I386__)
- i386_thread_state_t thread_state;
-#else
- ppc_thread_state_t thread_state;
-#endif
- mach_port_t thread = tobj->mach_thread;
- kern_return_t r;
-
- r = thread_suspend(thread);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_suspend failed");
-
- r = thread_get_state(thread, flavor, (natural_t *) &thread_state,
- &thread_state_count);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_get_state failed");
-
- md_critical_section_restart((ucontext_t *) &thread_state);
-
- r = thread_set_state(thread, flavor, (natural_t *) &thread_state,
- thread_state_count);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_set_state failed");
- }
-
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
-}
-
-static void threads_cast_darwinresume(void)
-{
- threadobject *tobj = mainthreadobj;
- threadobject *self = THREADOBJECT;
-
- do {
- if (tobj != self)
- {
- mach_port_t thread = tobj->mach_thread;
- kern_return_t r;
-
- r = thread_resume(thread);
-
- if (r != KERN_SUCCESS)
- vm_abort("thread_resume failed");
- }
-
- tobj = tobj->next;
- } while (tobj != mainthreadobj);
-}
-
-#endif
-
-#if defined(__IRIX__)
-static void threads_cast_irixresume(void)
-{
- pthread_mutex_lock(&suspend_ack_lock);
- pthread_cond_broadcast(&suspend_cond);
- pthread_mutex_unlock(&suspend_ack_lock);
-}
-#endif
-
-#if defined(ENABLE_GC_BOEHM) && !defined(__DARWIN__)
-static void threads_sigsuspend_handler(ucontext_t *_uc)
-{
- int sig;
- sigset_t sigs;
-
- /* XXX TWISTI: this is just a quick hack */
-#if defined(ENABLE_JIT)
- md_critical_section_restart(_uc);
-#endif
-
- /* Do as Boehm does. On IRIX a condition variable is used for wake-up
- (not POSIX async-safe). */
-#if defined(__IRIX__)
- pthread_mutex_lock(&suspend_ack_lock);
- threads_sem_post(&suspend_ack);
- pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
- pthread_mutex_unlock(&suspend_ack_lock);
-#elif defined(__CYGWIN__)
- /* TODO */
- assert(0);
-#else
-
- sig = GC_signum2();
- sigfillset(&sigs);
- sigdelset(&sigs, sig);
- sigsuspend(&sigs);
-#endif
-}
-#endif
-
-#endif
-
-
-/* threads_stopworld ***********************************************************
-
- Stops the world from turning. All threads except the calling one
- are suspended. The function returns as soon as all threads have
- acknowledged their suspension.
-
-*******************************************************************************/
-
-#if !defined(DISABLE_GC)
-void threads_stopworld(void)
-{
-#if !defined(__DARWIN__) && !defined(__CYGWIN__)
- threadobject *t;
- threadobject *self;
- bool result;
- s4 count, i;
-#endif
-
- lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
-
- /* lock the threads lists */
-
- threadlist_lock();
-
-#if defined(__DARWIN__)
- /*threads_cast_darwinstop();*/
- assert(0);
-#elif defined(__CYGWIN__)
- /* TODO */
- assert(0);
-#else
- self = THREADOBJECT;
-
- DEBUGTHREADS("stops World", self);
-
- count = 0;
-
- /* suspend all running threads */
- for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
- /* don't send the signal to ourself */
-
- if (t == self)
- continue;
-
- /* don't send the signal to NEW threads (because they are not
- completely initialized) */
-
- if (t->state == THREAD_STATE_NEW)
- continue;
-
- /* send the signal */
-
- result = threads_suspend_thread(t, SUSPEND_REASON_STOPWORLD);
- assert(result);
-
- /* increase threads count */
-
- count++;
- }
-
- /* wait for all threads signaled to suspend */
- for (i = 0; i < count; i++)
- threads_sem_wait(&suspend_ack);
-#endif
-
- /* ATTENTION: Don't unlock the threads-lists here so that
- non-signaled NEW threads can't change their state and execute
- code. */
-}
-#endif /* !defined(DISABLE_GC) */
-
-
-/* threads_startworld **********************************************************
-
- Starts the world again after it has previously been stopped.
-
-*******************************************************************************/
-
-#if !defined(DISABLE_GC)
-void threads_startworld(void)
-{
-#if !defined(__DARWIN__) && !defined(__CYGWIN__)
- threadobject *t;
- threadobject *self;
- bool result;
- s4 count, i;
-#endif
-
-#if defined(__DARWIN__)
- /*threads_cast_darwinresume();*/
- assert(0);
-#elif defined(__IRIX__)
- threads_cast_irixresume();
-#elif defined(__CYGWIN__)
- /* TODO */
- assert(0);
-#else
- self = THREADOBJECT;
-
- DEBUGTHREADS("starts World", self);
-
- count = 0;
-
- /* resume all thread we haltet */
- for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
- /* don't send the signal to ourself */
-
- if (t == self)
- continue;
-
- /* don't send the signal to NEW threads (because they are not
- completely initialized) */
-
- if (t->state == THREAD_STATE_NEW)
- continue;
-
- /* send the signal */
-
- result = threads_resume_thread(t);
- assert(result);
-
- /* increase threads count */
-
- count++;
- }
-
- /* wait for all threads signaled to suspend */
- for (i = 0; i < count; i++)
- threads_sem_wait(&suspend_ack);
-
-#endif
-
- /* unlock the threads lists */
-
- threadlist_unlock();
-
- unlock_stopworld();
-}
-#endif
-
-
-/* threads_set_current_threadobject ********************************************
-
- Set the current thread object.
-
- IN:
- thread.......the thread object to set
-
-*******************************************************************************/
-
-void threads_set_current_threadobject(threadobject *thread)
-{
-#if !defined(HAVE___THREAD)
- if (pthread_setspecific(threads_current_threadobject_key, thread) != 0)
- vm_abort("threads_set_current_threadobject: pthread_setspecific failed: %s", strerror(errno));
-#else
- threads_current_threadobject = thread;
-#endif
-}
-
-
-/* threads_impl_thread_init ****************************************************
-
- Initialize OS-level locking constructs in threadobject.
-
- IN:
- t....the threadobject
-
-*******************************************************************************/
-
-void threads_impl_thread_init(threadobject *t)
-{
- int result;
-
- /* initialize the mutex and the condition */
-
- result = pthread_mutex_init(&t->flc_lock, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_mutex_init failed");
-
- result = pthread_cond_init(&t->flc_cond, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
-
- result = pthread_mutex_init(&(t->waitmutex), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_mutex_init failed");
-
- result = pthread_cond_init(&(t->waitcond), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
-
- result = pthread_mutex_init(&(t->suspendmutex), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_mutex_init failed");
-
- result = pthread_cond_init(&(t->suspendcond), NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_new: pthread_cond_init failed");
-}
-
-/* threads_impl_thread_clear ***************************************************
-
- Clears all fields in threadobject the way an MZERO would have
- done. MZERO cannot be used anymore because it would mess up the
- pthread_* bits.
-
- IN:
- t....the threadobject
-
-*******************************************************************************/
-
-void threads_impl_thread_clear(threadobject *t)
-{
- t->object = NULL;
-
- t->thinlock = 0;
-
- t->index = 0;
- t->flags = 0;
- t->state = 0;
-
- t->tid = 0;
-
-#if defined(__DARWIN__)
- t->mach_thread = 0;
-#endif
-
- t->interrupted = false;
- t->signaled = false;
- t->sleeping = false;
-
- t->suspended = false;
- t->suspend_reason = 0;
-
- t->pc = NULL;
-
- t->_exceptionptr = NULL;
- t->_stackframeinfo = NULL;
- t->_localref_table = NULL;
-
-#if defined(ENABLE_INTRP)
- t->_global_sp = NULL;
-#endif
-
-#if defined(ENABLE_GC_CACAO)
- t->gc_critical = false;
-
- t->ss = NULL;
- t->es = NULL;
-#endif
-
- MZERO(&t->dumpinfo, dumpinfo_t, 1);
-}
-
-/* threads_impl_thread_reuse ***************************************************
-
- Resets some implementation fields in threadobject. This was
- previously done in threads_impl_thread_new.
-
- IN:
- t....the threadobject
-
-*******************************************************************************/
-
-void threads_impl_thread_reuse(threadobject *t)
-{
- /* get the pthread id */
-
- t->tid = pthread_self();
-
-#if defined(ENABLE_DEBUG_FILTER)
- /* Initialize filter counters */
- t->filterverbosecallctr[0] = 0;
- t->filterverbosecallctr[1] = 0;
-#endif
-
-#if !defined(NDEBUG)
- t->tracejavacallindent = 0;
- t->tracejavacallcount = 0;
-#endif
-
- t->flc_bit = false;
- t->flc_next = NULL;
- t->flc_list = NULL;
-
-/* not really needed */
- t->flc_object = NULL;
-}
-
-
-/* threads_impl_thread_free ****************************************************
-
- Cleanup thread stuff.
-
- IN:
- t....the threadobject
-
-*******************************************************************************/
-
-#if 0
-/* never used */
-void threads_impl_thread_free(threadobject *t)
-{
- int result;
-
- /* Destroy the mutex and the condition. */
-
- result = pthread_mutex_destroy(&(t->flc_lock));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_mutex_destroy failed");
-
- result = pthread_cond_destroy(&(t->flc_cond));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-
- result = pthread_mutex_destroy(&(t->waitmutex));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_mutex_destroy failed");
-
- result = pthread_cond_destroy(&(t->waitcond));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-
- result = pthread_mutex_destroy(&(t->suspendmutex));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_mutex_destroy failed");
-
- result = pthread_cond_destroy(&(t->suspendcond));
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_free: pthread_cond_destroy failed");
-}
-#endif
-
-
-/* threads_get_current_threadobject ********************************************
-
- Return the threadobject of the current thread.
-
- RETURN VALUE:
- the current threadobject *
-
-*******************************************************************************/
-
-threadobject *threads_get_current_threadobject(void)
-{
- return THREADOBJECT;
-}
-
-
-/* threads_impl_preinit ********************************************************
-
- Do some early initialization of stuff required.
-
- ATTENTION: Do NOT use any Java heap allocation here, as gc_init()
- is called AFTER this function!
-
-*******************************************************************************/
-
-void threads_impl_preinit(void)
-{
- int result;
-
- result = pthread_mutex_init(&stopworldlock, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_mutex_init failed");
-
- /* initialize exit mutex and condition (on exit we join all
- threads) */
-
- result = pthread_mutex_init(&mutex_join, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_mutex_init failed");
-
- result = pthread_cond_init(&cond_join, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_cond_init failed");
-
-#if defined(ENABLE_GC_CACAO)
- /* initialize the GC mutext */
-
- result = pthread_mutex_init(&mutex_gc, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_mutex_init failed");
-#endif
-
-#if !defined(HAVE___THREAD)
- result = pthread_key_create(&threads_current_threadobject_key, NULL);
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_preinit: pthread_key_create failed");
-#endif
-
- threads_sem_init(&suspend_ack, 0, 0);
-}
-
-
-/* threads_mutex_gc_lock *******************************************************
-
- Enter the global GC mutex.
-
-*******************************************************************************/
-
-#if defined(ENABLE_GC_CACAO)
-void threads_mutex_gc_lock(void)
-{
- int result;
-
- result = pthread_mutex_lock(&mutex_gc);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_mutex_gc_lock: pthread_mutex_lock failed");
-}
-#endif
-
-
-/* threads_mutex_gc_unlock *****************************************************
-
- Leave the global GC mutex.
-
-*******************************************************************************/
-
-#if defined(ENABLE_GC_CACAO)
-void threads_mutex_gc_unlock(void)
-{
- int result;
-
- result = pthread_mutex_unlock(&mutex_gc);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_mutex_gc_unlock: pthread_mutex_unlock failed");
-}
-#endif
-
-/* threads_mutex_join_lock *****************************************************
-
- Enter the join mutex.
-
-*******************************************************************************/
-
-void threads_mutex_join_lock(void)
-{
- int result;
-
- result = pthread_mutex_lock(&mutex_join);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_mutex_join_lock: pthread_mutex_lock failed");
-}
-
-
-/* threads_mutex_join_unlock ***************************************************
-
- Leave the join mutex.
-
-*******************************************************************************/
-
-void threads_mutex_join_unlock(void)
-{
- int result;
-
- result = pthread_mutex_unlock(&mutex_join);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_mutex_join_unlock: pthread_mutex_unlock failed");
-}
-
-
-/* threads_impl_init ***********************************************************
-
- Initializes the implementation specific bits.
-
-*******************************************************************************/
-
-void threads_impl_init(void)
-{
- pthread_attr_t attr;
- int result;
-
- threads_set_thread_priority(pthread_self(), NORM_PRIORITY);
-
- /* Initialize the thread attribute object. */
-
- result = pthread_attr_init(&attr);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_init: pthread_attr_init failed");
-
- result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_init: pthread_attr_setdetachstate failed");
-}
-
-
-/* threads_startup_thread ******************************************************
-
- Thread startup function called by pthread_create.
-
- Thread which have a startup.function != NULL are marked as internal
- threads. All other threads are threated as normal Java threads.
-
- NOTE: This function is not called directly by pthread_create. The Boehm GC
- inserts its own GC_start_routine in between, which then calls
- threads_startup.
-
- IN:
- arg..........the argument passed to pthread_create, ie. a pointer to
- a startupinfo struct. CAUTION: When the `psem` semaphore
- is posted, the startupinfo struct becomes invalid! (It
- is allocated on the stack of threads_start_thread.)
-
-******************************************************************************/
-
-static void *threads_startup_thread(void *arg)
-{
- startupinfo *startup;
- threadobject *thread;
- java_lang_Thread *object;
-#if defined(WITH_CLASSPATH_GNU)
- java_lang_VMThread *vmt;
-#endif
- sem_t *psem;
- classinfo *c;
- methodinfo *m;
- java_handle_t *o;
- functionptr function;
-
-#if defined(ENABLE_INTRP)
- u1 *intrp_thread_stack;
-
- /* create interpreter stack */
-
- if (opt_intrp) {
- intrp_thread_stack = GCMNEW(u1, opt_stacksize);
- MSET(intrp_thread_stack, 0, u1, opt_stacksize);
- }
- else
- intrp_thread_stack = NULL;
-#endif
-
- /* get passed startupinfo structure and the values in there */
-
- startup = arg;
-
- thread = startup->thread;
- function = startup->function;
- psem = startup->psem;
-
- /* Seems like we've encountered a situation where thread->tid was
- not set by pthread_create. We alleviate this problem by waiting
- for pthread_create to return. */
-
- threads_sem_wait(startup->psem_first);
-
-#if defined(__DARWIN__)
- thread->mach_thread = mach_thread_self();
-#endif
-
- /* store the internal thread data-structure in the TSD */
-
- threads_set_current_threadobject(thread);
-
- /* get the java.lang.Thread object for this thread */
-
- object = (java_lang_Thread *) threads_thread_get_object(thread);
-
- /* set our priority */
-
- threads_set_thread_priority(thread->tid, LLNI_field_direct(object, priority));
-
- /* thread is completely initialized */
-
- threads_thread_state_runnable(thread);
-
- /* tell threads_startup_thread that we registered ourselves */
- /* CAUTION: *startup becomes invalid with this! */
-
- startup = NULL;
- threads_sem_post(psem);
-
-#if defined(ENABLE_INTRP)
- /* set interpreter stack */
-
- if (opt_intrp)
- thread->_global_sp = (Cell *) (intrp_thread_stack + opt_stacksize);
-#endif
-
-#if defined(ENABLE_JVMTI)
- /* fire thread start event */
-
- if (jvmti)
- jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
-#endif
-
- DEBUGTHREADS("starting", thread);
-
- /* find and run the Thread.run()V method if no other function was passed */
-
- if (function == NULL) {
-#if defined(WITH_CLASSPATH_GNU)
- /* We need to start the run method of
- java.lang.VMThread. Since this is a final class, we can use
- the class object directly. */
-
- c = class_java_lang_VMThread;
-#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
- LLNI_class_get(object, c);
-#else
-# error unknown classpath configuration
-#endif
-
- m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
-
- if (m == NULL)
- vm_abort("threads_startup_thread: run() method not found in class");
-
- /* set ThreadMXBean variables */
-
- _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
- _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
-
- if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
- _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
- _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
- _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
-
-#if defined(WITH_CLASSPATH_GNU)
- /* we need to start the run method of java.lang.VMThread */
-
- LLNI_field_get_ref(object, vmThread, vmt);
- o = (java_handle_t *) vmt;
-
-#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
- o = (java_handle_t *) object;
-#else
-# error unknown classpath configuration
-#endif
-
- /* run the thread */
-
- (void) vm_call_method(m, o);
- }
- else {
- /* set ThreadMXBean variables */
-
- _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
- _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
-
- if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
- _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
- _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
- _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
-
- /* call passed function, e.g. finalizer_thread */
-
- (function)();
- }
-
- DEBUGTHREADS("stopping", thread);
-
-#if defined(ENABLE_JVMTI)
- /* fire thread end event */
-
- if (jvmti)
- jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
-#endif
-
- /* We ignore the return value. */
-
- (void) threads_detach_thread(thread);
-
- /* set ThreadMXBean variables */
-
- _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--;
-
- return NULL;
-}
-
-
-/* threads_impl_thread_start ***************************************************
-
- Start a thread in the JVM. Both (vm internal and java) thread
- objects exist.
-
- IN:
- thread....the thread object
- f.........function to run in the new thread. NULL means that the
- "run" method of the object `t` should be called
-
-******************************************************************************/
-
-void threads_impl_thread_start(threadobject *thread, functionptr f)
-{
- sem_t sem;
- sem_t sem_first;
- pthread_attr_t attr;
- startupinfo startup;
- int result;
-
- /* fill startupinfo structure passed by pthread_create to
- * threads_startup_thread */
-
- startup.thread = thread;
- startup.function = f; /* maybe we don't call Thread.run()V */
- startup.psem = &sem;
- startup.psem_first = &sem_first;
-
- threads_sem_init(&sem, 0, 0);
- threads_sem_init(&sem_first, 0, 0);
-
- /* Initialize thread attributes. */
-
- result = pthread_attr_init(&attr);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_init failed");
-
- result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_setdetachstate failed");
-
- /* initialize thread stacksize */
-
- result = pthread_attr_setstacksize(&attr, opt_stacksize);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_setstacksize failed");
-
- /* create the thread */
-
- result = pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_start: pthread_create failed");
-
- /* destroy the thread attributes */
-
- result = pthread_attr_destroy(&attr);
-
- if (result != 0)
- vm_abort_errnum(result, "threads_impl_thread_start: pthread_attr_destroy failed");
-
- /* signal that pthread_create has returned, so thread->tid is valid */
-
- threads_sem_post(&sem_first);
-
- /* wait here until the thread has entered itself into the thread list */
-
- threads_sem_wait(&sem);
-
- /* cleanup */
-
- sem_destroy(&sem);
- sem_destroy(&sem_first);
-}
-
-
-/* threads_set_thread_priority *************************************************
-
- Set the priority of the given thread.
-
- IN:
- tid..........thread id
- priority.....priority to set
-
-******************************************************************************/
-
-void threads_set_thread_priority(pthread_t tid, int priority)
-{
- struct sched_param schedp;
- int policy;
-
- pthread_getschedparam(tid, &policy, &schedp);
- schedp.sched_priority = priority;
- pthread_setschedparam(tid, policy, &schedp);
-}
-
-
-/* threads_attach_current_thread ***********************************************
-
- Attaches the current thread to the VM. Used in JNI.
-
-*******************************************************************************/
-
-bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
-{
- threadobject *thread;
- utf *u;
- java_handle_t *s;
- java_handle_t *o;
- java_lang_Thread *t;
-
-#if defined(ENABLE_JAVASE)
- java_lang_ThreadGroup *group;
- threadobject *mainthread;
- java_lang_Thread *mainthreado;
- classinfo *c;
- methodinfo *m;
-#endif
-
-#if defined(WITH_CLASSPATH_GNU)
- java_lang_VMThread *vmt;
-#endif
-
- /* Enter the join-mutex, so if the main-thread is currently
- waiting to join all threads, the number of non-daemon threads
- is correct. */
-
- threads_mutex_join_lock();
-
- /* create internal thread data-structure */
-
- thread = threads_thread_new();
-
- /* thread is a Java thread and running */
-
- thread->flags = THREAD_FLAG_JAVA;
-
- if (isdaemon)
- thread->flags |= THREAD_FLAG_DAEMON;
-
- /* The thread is flagged and (non-)daemon thread, we can leave the
- mutex. */
-
- threads_mutex_join_unlock();
-
- /* create a java.lang.Thread object */
-
- t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
-
- /* XXX memory leak!!! */
- if (t == NULL)
- return false;
-
- threads_thread_set_object(thread, (java_handle_t *) t);
-
- /* thread is completely initialized */
-
- threads_thread_state_runnable(thread);
-
- DEBUGTHREADS("attaching", thread);
-
-#if defined(ENABLE_INTRP)
- /* create interpreter stack */
-
- if (opt_intrp) {
- MSET(intrp_main_stack, 0, u1, opt_stacksize);
- thread->_global_sp = (Cell *) (intrp_main_stack + opt_stacksize);
- }
-#endif
-
-#if defined(WITH_CLASSPATH_GNU)
-
- /* create a java.lang.VMThread object */
-
- vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
-
- /* XXX memory leak!!! */
- if (vmt == NULL)
- return false;
-
- /* set the thread */
-
- LLNI_field_set_ref(vmt, thread, t);
- LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread);
-
-#elif defined(WITH_CLASSPATH_SUN)
-
- vm_abort("threads_attach_current_thread: IMPLEMENT ME!");
-
-#elif defined(WITH_CLASSPATH_CLDC1_1)
-
- LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread);
-
-#else
-# error unknown classpath configuration
-#endif
-
- if (vm_aargs != NULL) {
- u = utf_new_char(vm_aargs->name);
-#if defined(ENABLE_JAVASE)
- group = (java_lang_ThreadGroup *) vm_aargs->group;
-#endif
- }
- else {
- u = utf_null;
-#if defined(ENABLE_JAVASE)
- /* get the main thread */
-
- mainthread = threadlist_first();
- mainthreado = (java_lang_Thread *) threads_thread_get_object(mainthread);
- LLNI_field_get_ref(mainthreado, group, group);
-#endif
- }
-
- /* the the thread name */
-
- s = javastring_new(u);
-
- /* for convenience */
-
- o = (java_handle_t *) t;
-
-#if defined(WITH_CLASSPATH_GNU)
- (void) vm_call_method(thread_method_init, o, vmt, s, NORM_PRIORITY,
- isdaemon);
-#elif defined(WITH_CLASSPATH_CLDC1_1)
- (void) vm_call_method(thread_method_init, o, s);
-#endif
-
- if (exceptions_get_exception())
- return false;
-
-#if defined(ENABLE_JAVASE)
- /* store the thread group in the object */
-
- LLNI_field_set_ref(t, group, group);
-
- /* add thread to given thread-group */
-
- LLNI_class_get(group, c);
-
- m = class_resolveclassmethod(c,
- utf_addThread,
- utf_java_lang_Thread__V,
- class_java_lang_ThreadGroup,
- true);
-
- o = (java_handle_t *) group;
-
- (void) vm_call_method(m, o, t);
-
- if (exceptions_get_exception())
- return false;
-#endif
-
- return true;
-}
-
-
-/* threads_detach_thread *******************************************************
-
- Detaches the passed thread from the VM. Used in JNI.
-
-*******************************************************************************/
-
-bool threads_detach_thread(threadobject *t)
-{
- java_lang_Thread *object;
- java_handle_t *o;
-#if defined(ENABLE_JAVASE)
- java_lang_ThreadGroup *group;
- java_handle_t *e;
- void *handler;
- classinfo *c;
- methodinfo *m;
-#endif
-
- DEBUGTHREADS("detaching", t);
-
- object = (java_lang_Thread *) threads_thread_get_object(t);
-
-#if defined(ENABLE_JAVASE)
- LLNI_field_get_ref(object, group, group);
-
- /* If there's an uncaught exception, call uncaughtException on the
- thread's exception handler, or the thread's group if this is
- unset. */
-
- e = exceptions_get_and_clear_exception();
-
- if (e != NULL) {
- /* We use the type void* for handler here, as it's not trivial
- to build the java_lang_Thread_UncaughtExceptionHandler
- header file with cacaoh. */
-
-# if defined(WITH_CLASSPATH_GNU)
- LLNI_field_get_ref(object, exceptionHandler, handler);
-# elif defined(WITH_CLASSPATH_SUN)
- LLNI_field_get_ref(object, uncaughtExceptionHandler, handler);
-# endif
-
- if (handler != NULL) {
- LLNI_class_get(handler, c);
- o = (java_handle_t *) handler;
- }
- else {
- LLNI_class_get(group, c);
- o = (java_handle_t *) group;
- }
-
- m = class_resolveclassmethod(c,
- utf_uncaughtException,
- utf_java_lang_Thread_java_lang_Throwable__V,
- NULL,
- true);
-
- if (m == NULL)
- return false;
-
- (void) vm_call_method(m, o, object, e);
-
- if (exceptions_get_exception())
- return false;
- }
-
- /* XXX TWISTI: should all threads be in a ThreadGroup? */
-
- /* Remove thread from the thread group. */
-
- if (group != NULL) {
- LLNI_class_get(group, c);
-
-# if defined(WITH_CLASSPATH_GNU)
- m = class_resolveclassmethod(c,
- utf_removeThread,
- utf_java_lang_Thread__V,
- class_java_lang_ThreadGroup,
- true);
-# elif defined(WITH_CLASSPATH_SUN)
- m = class_resolveclassmethod(c,
- utf_remove,
- utf_java_lang_Thread__V,
- class_java_lang_ThreadGroup,
- true);
-# else
-# error unknown classpath configuration
-# endif
-
- if (m == NULL)
- return false;
-
- o = (java_handle_t *) group;
-
- (void) vm_call_method(m, o, object);
-
- if (exceptions_get_exception())
- return false;
- }
-#endif
-
- /* Thread has terminated. */
-
- threads_thread_state_terminated(t);
-
- /* Notify all threads waiting on this thread. These are joining
- this thread. */
-
- o = (java_handle_t *) object;
-
- /* XXX Care about exceptions? */
- (void) lock_monitor_enter(o);
-
- lock_notify_all_object(o);
-
- /* XXX Care about exceptions? */
- (void) lock_monitor_exit(o);
-
- /* Enter the join-mutex before calling threads_thread_free, so
- threads_join_all_threads gets the correct number of non-daemon
- threads. */
-
- threads_mutex_join_lock();
-
- /* free the vm internal thread object */
-
- threads_thread_free(t);
-
- /* Signal that this thread has finished and leave the mutex. */
-
- pthread_cond_signal(&cond_join);
- threads_mutex_join_unlock();
-
- return true;
-}
-
-
-/* threads_suspend_thread ******************************************************
-
- Suspend the passed thread. Execution stops until the thread
- is explicitly resumend again.
-
- IN:
- reason.....Reason for suspending this thread.
-
-*******************************************************************************/
-
-bool threads_suspend_thread(threadobject *thread, s4 reason)
-{
- /* acquire the suspendmutex */
- if (pthread_mutex_lock(&(thread->suspendmutex)) != 0)
- vm_abort("threads_suspend_thread: pthread_mutex_lock failed: %s",
- strerror(errno));
-
- if (thread->suspended) {
- pthread_mutex_unlock(&(thread->suspendmutex));
- return false;
- }
-
- /* set the reason for the suspension */
- thread->suspend_reason = reason;
-
- /* send the suspend signal to the thread */
- assert(thread != THREADOBJECT);
- if (pthread_kill(thread->tid, SIGUSR1) != 0)
- vm_abort("threads_suspend_thread: pthread_kill failed: %s",
- strerror(errno));
-
- /* REMEMBER: do not release the suspendmutex, this is done
- by the thread itself in threads_suspend_ack(). */
-
- return true;
-}
-
-
-/* threads_suspend_ack *********************************************************
-
- Acknowledges the suspension of the current thread.
-
- IN:
- pc.....The PC where the thread suspended its execution.
- sp.....The SP before the thread suspended its execution.
-
-*******************************************************************************/
-
-void threads_suspend_ack(u1* pc, u1* sp)
-{
- threadobject *thread;
-
- thread = THREADOBJECT;
-
- assert(thread->suspend_reason != 0);
-
- /* TODO: remember dump memory size */
-
-#if defined(ENABLE_GC_CACAO)
- /* inform the GC about the suspension */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
-
- /* check if the GC wants to leave the thread running */
- if (!gc_suspend(thread, pc, sp)) {
-
- /* REMEMBER: we do not unlock the suspendmutex because the thread
- will suspend itself again at a later time */
- return;
-
- }
- }
-#endif
-
- /* mark this thread as suspended and remember the PC */
- thread->pc = pc;
- thread->suspended = true;
-
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
- }
-
- DEBUGTHREADS("suspending", thread);
-
- /* release the suspension mutex and wait till we are resumed */
- pthread_cond_wait(&(thread->suspendcond), &(thread->suspendmutex));
-
- DEBUGTHREADS("resuming", thread);
-
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
- }
-
- /* TODO: free dump memory */
-
- /* release the suspendmutex */
- if (pthread_mutex_unlock(&(thread->suspendmutex)) != 0)
- vm_abort("threads_suspend_ack: pthread_mutex_unlock failed: %s",
- strerror(errno));
-}
-
-
-/* threads_resume_thread *******************************************************
-
- Resumes the execution of the passed thread.
-
-*******************************************************************************/
-
-bool threads_resume_thread(threadobject *thread)
-{
- /* acquire the suspendmutex */
- if (pthread_mutex_lock(&(thread->suspendmutex)) != 0)
- vm_abort("threads_resume_ack: pthread_mutex_unlock failed: %s",
- strerror(errno));
-
- if (!thread->suspended) {
- pthread_mutex_unlock(&(thread->suspendmutex));
- return false;
- }
-
- thread->suspended = false;
-
- /* tell everyone that the thread should resume */
- assert(thread != THREADOBJECT);
- pthread_cond_broadcast(&(thread->suspendcond));
-
- /* release the suspendmutex */
- pthread_mutex_unlock(&(thread->suspendmutex));
-
- return true;
-}
-
-
-/* threads_join_all_threads ****************************************************
-
- Join all non-daemon threads.
-
-*******************************************************************************/
-
-void threads_join_all_threads(void)
-{
- threadobject *t;
-
- /* get current thread */
-
- t = THREADOBJECT;
-
- /* this thread is waiting for all non-daemon threads to exit */
-
- threads_thread_state_waiting(t);
-
- /* enter join mutex */
-
- threads_mutex_join_lock();
-
- /* Wait for condition as long as we have non-daemon threads. We
- compare against 1 because the current (main thread) is also a
- non-daemon thread. */
-
- while (threadlist_get_non_daemons() > 1)
- pthread_cond_wait(&cond_join, &mutex_join);
-
- /* leave join mutex */
-
- threads_mutex_join_unlock();
-}
-
-
-/* threads_timespec_earlier ****************************************************
-
- Return true if timespec tv1 is earlier than timespec tv2.
-
- IN:
- tv1..........first timespec
- tv2..........second timespec
-
- RETURN VALUE:
- true, if the first timespec is earlier
-
-*******************************************************************************/
-
-static inline bool threads_timespec_earlier(const struct timespec *tv1,
- const struct timespec *tv2)
-{
- return (tv1->tv_sec < tv2->tv_sec)
- ||
- (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
-}
-
-
-/* threads_current_time_is_earlier_than ****************************************
-
- Check if the current time is earlier than the given timespec.
-
- IN:
- tv...........the timespec to compare against
-
- RETURN VALUE:
- true, if the current time is earlier
-
-*******************************************************************************/
-
-static bool threads_current_time_is_earlier_than(const struct timespec *tv)
-{
- struct timeval tvnow;
- struct timespec tsnow;
-
- /* get current time */
-
- if (gettimeofday(&tvnow, NULL) != 0)
- vm_abort("gettimeofday failed: %s\n", strerror(errno));
-
- /* convert it to a timespec */
-
- tsnow.tv_sec = tvnow.tv_sec;
- tsnow.tv_nsec = tvnow.tv_usec * 1000;
-
- /* compare current time with the given timespec */
-
- return threads_timespec_earlier(&tsnow, tv);
-}
-
-
-/* threads_wait_with_timeout ***************************************************
-
- Wait until the given point in time on a monitor until either
- we are notified, we are interrupted, or the time is up.
-
- IN:
- t............the current thread
- wakeupTime...absolute (latest) wakeup time
- If both tv_sec and tv_nsec are zero, this function
- waits for an unlimited amount of time.
-
-*******************************************************************************/
-
-static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
-{
- /* acquire the waitmutex */
-
- pthread_mutex_lock(&t->waitmutex);
-
- /* mark us as sleeping */
-
- t->sleeping = true;
-
- /* wait on waitcond */
-
- if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
- /* with timeout */
- while (!t->interrupted && !t->signaled
- && threads_current_time_is_earlier_than(wakeupTime))
- {
- threads_thread_state_timed_waiting(t);
-
- pthread_cond_timedwait(&t->waitcond, &t->waitmutex,
- wakeupTime);
-
- threads_thread_state_runnable(t);
- }
- }
- else {
- /* no timeout */
- while (!t->interrupted && !t->signaled) {
- threads_thread_state_waiting(t);
-
- pthread_cond_wait(&t->waitcond, &t->waitmutex);
-
- threads_thread_state_runnable(t);
- }
- }
-
- t->sleeping = false;
-
- /* release the waitmutex */
-
- pthread_mutex_unlock(&t->waitmutex);
-}
-
-
-/* threads_wait_with_timeout_relative ******************************************
-
- Wait for the given maximum amount of time on a monitor until either
- we are notified, we are interrupted, or the time is up.
-
- IN:
- t............the current thread
- millis.......milliseconds to wait
- nanos........nanoseconds to wait
-
-*******************************************************************************/
-
-void threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
- s4 nanos)
-{
- struct timespec wakeupTime;
-
- /* calculate the the (latest) wakeup time */
-
- threads_calc_absolute_time(&wakeupTime, millis, nanos);
-
- /* wait */
-
- threads_wait_with_timeout(thread, &wakeupTime);
-}
-
-
-/* threads_calc_absolute_time **************************************************
-
- Calculate the absolute point in time a given number of ms and ns from now.
-
- IN:
- millis............milliseconds from now
- nanos.............nanoseconds from now
-
- OUT:
- *tm...............receives the timespec of the absolute point in time
-
-*******************************************************************************/
-
-static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
-{
- if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
- struct timeval tv;
- long nsec;
- gettimeofday(&tv, NULL);
- tv.tv_sec += millis / 1000;
- millis %= 1000;
- nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
- tm->tv_sec = tv.tv_sec + nsec / 1000000000;
- tm->tv_nsec = nsec % 1000000000;
- }
- else {
- tm->tv_sec = 0;
- tm->tv_nsec = 0;
- }
-}
-
-
-/* threads_thread_interrupt ****************************************************
-
- Interrupt the given thread.
-
- The thread gets the "waitcond" signal and
- its interrupted flag is set to true.
-
- IN:
- thread............the thread to interrupt
-
-*******************************************************************************/
-
-void threads_thread_interrupt(threadobject *thread)
-{
- /* Signal the thread a "waitcond" and tell it that it has been
- interrupted. */
-
- pthread_mutex_lock(&thread->waitmutex);
-
- DEBUGTHREADS("interrupted", thread);
-
- /* Interrupt blocking system call using a signal. */
-
- pthread_kill(thread->tid, SIGHUP);
-
- if (thread->sleeping)
- pthread_cond_signal(&thread->waitcond);
-
- thread->interrupted = true;
-
- pthread_mutex_unlock(&thread->waitmutex);
-}
-
-
-/* threads_check_if_interrupted_and_reset **************************************
-
- Check if the current thread has been interrupted and reset the
- interruption flag.
-
- RETURN VALUE:
- true, if the current thread had been interrupted
-
-*******************************************************************************/
-
-bool threads_check_if_interrupted_and_reset(void)
-{
- threadobject *thread;
- bool intr;
-
- thread = THREADOBJECT;
-
- pthread_mutex_lock(&thread->waitmutex);
-
- /* get interrupted flag */
-
- intr = thread->interrupted;
-
- /* reset interrupted flag */
-
- thread->interrupted = false;
-
- pthread_mutex_unlock(&thread->waitmutex);
-
- return intr;
-}
-
-
-/* threads_thread_has_been_interrupted *****************************************
-
- Check if the given thread has been interrupted
-
- IN:
- t............the thread to check
-
- RETURN VALUE:
- true, if the given thread had been interrupted
-
-*******************************************************************************/
-
-bool threads_thread_has_been_interrupted(threadobject *thread)
-{
- return thread->interrupted;
-}
-
-
-/* threads_sleep ***************************************************************
-
- Sleep the current thread for the specified amount of time.
-
-*******************************************************************************/
-
-void threads_sleep(s8 millis, s4 nanos)
-{
- threadobject *thread;
- struct timespec wakeupTime;
- bool wasinterrupted;
-
- thread = THREADOBJECT;
-
- threads_calc_absolute_time(&wakeupTime, millis, nanos);
-
- threads_wait_with_timeout(thread, &wakeupTime);
-
- wasinterrupted = threads_check_if_interrupted_and_reset();
-
- if (wasinterrupted)
- exceptions_throw_interruptedexception();
-}
-
-
-/* threads_yield ***************************************************************
-
- Yield to the scheduler.
-
-*******************************************************************************/
-
-void threads_yield(void)
-{
- sched_yield();
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
+++ /dev/null
-/* src/threads/native/threads.h - native threads header
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _THREADS_H
-#define _THREADS_H
-
-/* forward typedefs ***********************************************************/
-
-typedef struct threadobject threadobject;
-
-
-#include "config.h"
-
-#include <pthread.h>
-#include <ucontext.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-#include "native/jni.h"
-#include "native/localref.h"
-
-#include "threads/native/lock.h"
-
-#include "vm/global.h"
-
-#if defined(ENABLE_GC_CACAO)
-# include "vm/jit/replace.h"
-#endif
-
-#include "vm/jit/stacktrace.h"
-
-#if defined(ENABLE_INTRP)
-#include "vm/jit/intrp/intrp.h"
-#endif
-
-#if defined(__DARWIN__)
-# include <mach/mach.h>
-
-typedef struct {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- int value;
-} sem_t;
-
-#else
-# include <semaphore.h>
-#endif
-
-
-/* current threadobject *******************************************************/
-
-#if defined(HAVE___THREAD)
-
-#define THREADSPECIFIC __thread
-#define THREADOBJECT threads_current_threadobject
-
-extern __thread threadobject *threads_current_threadobject;
-
-#else /* defined(HAVE___THREAD) */
-
-#define THREADSPECIFIC
-#define THREADOBJECT \
- ((threadobject *) pthread_getspecific(threads_current_threadobject_key))
-
-extern pthread_key_t threads_current_threadobject_key;
-
-#endif /* defined(HAVE___THREAD) */
-
-
-/* threadobject ****************************************************************
-
- Struct holding thread local variables.
-
-*******************************************************************************/
-
-#define THREAD_FLAG_JAVA 0x01 /* a normal Java thread */
-#define THREAD_FLAG_INTERNAL 0x02 /* CACAO internal thread */
-#define THREAD_FLAG_DAEMON 0x04 /* daemon thread */
-#define THREAD_FLAG_IN_NATIVE 0x08 /* currently executing native code */
-
-#define SUSPEND_REASON_JNI 1 /* suspended from JNI */
-#define SUSPEND_REASON_STOPWORLD 2 /* suspended from stop-thw-world */
-
-
-struct threadobject {
- java_object_t *object; /* link to java.lang.Thread object */
-
- ptrint thinlock; /* pre-computed thin lock value */
-
- s4 index; /* thread index, starting with 1 */
- u4 flags; /* flag field */
- u4 state; /* state field */
-
- pthread_t tid; /* pthread id */
-
-#if defined(__DARWIN__)
- mach_port_t mach_thread; /* Darwin thread id */
-#endif
-
- /* for the sable tasuki lock extension */
- bool flc_bit;
- struct threadobject *flc_list; /* FLC list head for this thread */
- struct threadobject *flc_next; /* next pointer for FLC list */
- java_handle_t *flc_object;
- pthread_mutex_t flc_lock; /* controlling access to these fields */
- pthread_cond_t flc_cond;
-
- /* these are used for the wait/notify implementation */
- pthread_mutex_t waitmutex;
- pthread_cond_t waitcond;
-
- pthread_mutex_t suspendmutex; /* lock before suspending this thread */
- pthread_cond_t suspendcond; /* notify to resume this thread */
-
- bool interrupted;
- bool signaled;
- bool sleeping;
-
- bool suspended; /* is this thread suspended? */
- s4 suspend_reason; /* reason for suspending */
-
- u1 *pc; /* current PC (used for profiling) */
-
- java_object_t *_exceptionptr; /* current exception */
- stackframeinfo_t *_stackframeinfo; /* current native stackframeinfo */
- localref_table *_localref_table; /* JNI local references */
-
-#if defined(ENABLE_INTRP)
- Cell *_global_sp; /* stack pointer for interpreter */
-#endif
-
-#if defined(ENABLE_GC_CACAO)
- bool gc_critical; /* indicates a critical section */
-
- sourcestate_t *ss;
- executionstate_t *es;
-#endif
-
- dumpinfo_t dumpinfo; /* dump memory info structure */
-
-#if defined(ENABLE_DEBUG_FILTER)
- u2 filterverbosecallctr[2]; /* counters for verbose call filter */
-#endif
-
-#if !defined(NDEBUG)
- s4 tracejavacallindent;
- u4 tracejavacallcount;
-#endif
-
- listnode_t linkage; /* threads-list */
- listnode_t linkage_free; /* free-list */
-};
-
-
-/* native-world flags *********************************************************/
-
-#if defined(ENABLE_GC_CACAO)
-# define THREAD_NATIVEWORLD_ENTER THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE
-# define THREAD_NATIVEWORLD_EXIT THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE
-#else
-# define THREAD_NATIVEWORLD_ENTER /*nop*/
-# define THREAD_NATIVEWORLD_EXIT /*nop*/
-#endif
-
-
-/* counter for verbose call filter ********************************************/
-
-#if defined(ENABLE_DEBUG_FILTER)
-# define FILTERVERBOSECALLCTR (THREADOBJECT->filterverbosecallctr)
-#endif
-
-/* state for trace java call **************************************************/
-
-#if !defined(NDEBUG)
-# define TRACEJAVACALLINDENT (THREADOBJECT->tracejavacallindent)
-# define TRACEJAVACALLCOUNT (THREADOBJECT->tracejavacallcount)
-#endif
-
-
-/* inline functions ***********************************************************/
-
-inline static stackframeinfo_t *threads_get_current_stackframeinfo(void)
-{
- return THREADOBJECT->_stackframeinfo;
-}
-
-inline static void threads_set_current_stackframeinfo(stackframeinfo_t *sfi)
-{
- THREADOBJECT->_stackframeinfo = sfi;
-}
-
-
-/* functions ******************************************************************/
-
-void threads_sem_init(sem_t *sem, bool shared, int value);
-void threads_sem_wait(sem_t *sem);
-void threads_sem_post(sem_t *sem);
-
-threadobject *threads_get_current_threadobject(void);
-
-void threads_start_thread(threadobject *thread, functionptr function);
-
-void threads_set_thread_priority(pthread_t tid, int priority);
-
-bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon);
-bool threads_detach_thread(threadobject *thread);
-
-bool threads_suspend_thread(threadobject *thread, s4 reason);
-void threads_suspend_ack(u1* pc, u1* sp);
-bool threads_resume_thread(threadobject *thread);
-
-void threads_join_all_threads(void);
-
-void threads_sleep(s8 millis, s4 nanos);
-
-void threads_wait_with_timeout_relative(threadobject *t, s8 millis, s4 nanos);
-
-void threads_thread_interrupt(threadobject *thread);
-bool threads_check_if_interrupted_and_reset(void);
-bool threads_thread_has_been_interrupted(threadobject *thread);
-
-#if !defined(DISABLE_GC)
-void threads_stopworld(void);
-void threads_startworld(void);
-#endif
-
-#endif /* _THREADS_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */