diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..026b4da --- /dev/null +++ b/src/hash.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 + * Robert Lougher . + * + * This file is part of JamVM. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "jam.h" +#include "hash.h" +#include "class.h" +#include "classlib.h" + +void lockHashTable0(HashTable *table, Thread *self) { + if(!tryLockVMLock(table->lock, self)) { + disableSuspend(self); + lockVMLock(table->lock, self); + enableSuspend(self); + } + fastDisableSuspend(self); +} + +void unlockHashTable0(HashTable *table, Thread *self) { + fastEnableSuspend(self); + unlockVMLock(table->lock, self); +} + +void resizeHash(HashTable *table, int new_size) { + HashEntry *new_table = gcMemMalloc(sizeof(HashEntry)*new_size); + int i; + + memset(new_table, 0, sizeof(HashEntry)*new_size); + + for(i = table->hash_size-1; i >= 0; i--) { + void *ptr = table->hash_table[i].data; + if(ptr != NULL) { + int hash = table->hash_table[i].hash; + int new_index = hash & (new_size - 1); + + while(new_table[new_index].data != NULL) + new_index = (new_index+1) & (new_size - 1); + + new_table[new_index].hash = hash; + new_table[new_index].data = ptr; + } + } + + gcMemFree(table->hash_table); + table->hash_table = new_table; + table->hash_size = new_size; +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..3e66fb3 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011 + * Robert Lougher . + * + * This file is part of JamVM. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "thread.h" + +typedef struct hash_entry { + void *data; + int hash; +} HashEntry; + +typedef struct hash_table { + HashEntry *hash_table; + int hash_size; + int hash_count; + VMLock lock; +} HashTable; + +extern void resizeHash(HashTable *table, int new_size); +extern void lockHashTable0(HashTable *table, Thread *self); +extern void unlockHashTable0(HashTable *table, Thread *self); + +#define initHashTable(table, initial_size, create_lock) \ +{ \ + table.hash_table = gcMemMalloc(sizeof(HashEntry)*initial_size); \ + memset(table.hash_table, 0, sizeof(HashEntry)*initial_size); \ + table.hash_size = initial_size; \ + table.hash_count = 0; \ + if(create_lock) \ + initVMLock(table.lock); \ +} + +#define lockHashTable(table) \ + lockHashTable0(&table, threadSelf()); + +#define unlockHashTable(table) \ + unlockHashTable0(&table, threadSelf()); + +#define hashTableCount(table) \ + table.hash_count + +#define findHashEntry(table, ptr, ptr2, add_if_absent, scavenge, \ + locked) \ +{ \ + int hash = HASH(ptr); \ + int i; \ + \ + Thread *self; \ + if(locked) { \ + self = threadSelf(); \ + lockHashTable0(&table, self); \ + } \ + \ + i = hash & (table.hash_size - 1); \ + \ + for(;;) { \ + ptr2 = table.hash_table[i].data; \ + if((ptr2 == NULL) || \ + (COMPARE(ptr, ptr2, hash, table.hash_table[i].hash))) \ + break; \ + \ + i = (i+1) & (table.hash_size - 1); \ + } \ + \ + if(ptr2) { \ + ptr2 = FOUND(ptr, ptr2); \ + } else \ + if(add_if_absent) { \ + table.hash_table[i].hash = hash; \ + ptr2 = table.hash_table[i].data = PREPARE(ptr); \ + \ + if(ptr2) { \ + table.hash_count++; \ + if((table.hash_count * 4) > (table.hash_size * 3)) { \ + int new_size; \ + if(scavenge) { \ + HashEntry *entry = table.hash_table; \ + int cnt = table.hash_count; \ + for(; cnt; entry++) { \ + void *data = entry->data; \ + if(data) { \ + if(SCAVENGE(data)) { \ + entry->data = NULL; \ + table.hash_count--; \ + } \ + cnt--; \ + } \ + } \ + if((table.hash_count * 3) > \ + (table.hash_size * 2)) \ + new_size = table.hash_size*2; \ + else \ + new_size = table.hash_size; \ + } else \ + new_size = table.hash_size*2; \ + \ + resizeHash(&table, new_size); \ + } \ + } \ + } \ + \ + if(locked) \ + unlockHashTable0(&table, self); \ +} + +#define deleteHashEntry(table, ptr, locked) \ +{ \ + int hash = HASH(ptr); \ + void *ptr2; \ + int i; \ + \ + Thread *self; \ + if(locked) { \ + self = threadSelf(); \ + lockHashTable0(&table, self); \ + } \ + \ + i = hash & (table.hash_size - 1); \ + \ + for(;;) { \ + ptr2 = table.hash_table[i].data; \ + if((ptr2 == NULL) || \ + (COMPARE(ptr, ptr2, hash, table.hash_table[i].hash))) \ + break; \ + \ + i = (i+1) & (table.hash_size - 1); \ + } \ + \ + if(ptr2) \ + table.hash_table[i].data = DELETED; \ + \ + if(locked) \ + unlockHashTable0(&table, self); \ +} + +#define hashIterate(table) \ +{ \ + HashEntry *_entry = table.hash_table; \ + int _cnt = table.hash_count; \ + \ + while(_cnt) { \ + void *_data = _entry++->data; \ + if(_data) { \ + ITERATE(_data); \ + _cnt--; \ + } \ + } \ +} + +#define hashIterateP(table) \ +{ \ + HashEntry *entry = table.hash_table; \ + int cnt = table.hash_count; \ + \ + while(cnt) { \ + void **data_pntr = &entry++->data; \ + if(*data_pntr) { \ + ITERATE(data_pntr); \ + cnt--; \ + } \ + } \ +} + +#define freeHashTable(table) \ + gcMemFree(table.hash_table) + +#define gcFreeHashTable(table) \ + freeHashTable(table) diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 0000000..4c1d77b --- /dev/null +++ b/src/thread.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 + * Robert Lougher . + * + * This file is part of JamVM. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CREATING +#include +#include +#include + +#ifdef HAVE_ALLOCA_H +#include +#endif + +/* Thread states */ + +#define JVMTI_THREAD_STATE_ALIVE 0x001 +#define JVMTI_THREAD_STATE_TERMINATED 0x002 +#define JVMTI_THREAD_STATE_RUNNABLE 0x004 +#define JVMTI_THREAD_STATE_WAITING_INDEFINITELY 0x010 +#define JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT 0x020 +#define JVMTI_THREAD_STATE_SLEEPING 0x040 +#define JVMTI_THREAD_STATE_WAITING 0x080 +#define JVMTI_THREAD_STATE_IN_OBJECT_WAIT 0x100 +#define JVMTI_THREAD_STATE_PARKED 0x200 +#define JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER 0x400 + +#define CREATING 0x0 +#define RUNNING (JVMTI_THREAD_STATE_ALIVE \ + |JVMTI_THREAD_STATE_RUNNABLE) +#define WAITING (JVMTI_THREAD_STATE_ALIVE \ + |JVMTI_THREAD_STATE_WAITING \ + |JVMTI_THREAD_STATE_WAITING_INDEFINITELY) +#define TIMED_WAITING (JVMTI_THREAD_STATE_ALIVE \ + |JVMTI_THREAD_STATE_WAITING \ + |JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) +#define OBJECT_WAIT (JVMTI_THREAD_STATE_IN_OBJECT_WAIT|WAITING) +#define OBJECT_TIMED_WAIT (JVMTI_THREAD_STATE_IN_OBJECT_WAIT|TIMED_WAITING) +#define SLEEPING (JVMTI_THREAD_STATE_SLEEPING|TIMED_WAITING) +#define PARKED (JVMTI_THREAD_STATE_PARKED|WAITING) +#define TIMED_PARKED (JVMTI_THREAD_STATE_PARKED|TIMED_WAITING) +#define BLOCKED JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER +#define TERMINATED JVMTI_THREAD_STATE_TERMINATED + +/* thread priorities */ + +#define MIN_PRIORITY 1 +#define NORM_PRIORITY 5 +#define MAX_PRIORITY 10 + +/* Suspend states */ + +#define SUSP_NONE 0 +#define SUSP_BLOCKING 1 +#define SUSP_CRITICAL 2 +#define SUSP_SUSPENDED 3 + +/* Park states */ + +#define PARK_BLOCKED 0 +#define PARK_RUNNING 1 +#define PARK_PERMIT 2 + +typedef struct thread Thread; + +typedef struct monitor { + pthread_mutex_t lock; + Thread *owner; + Object *obj; + int count; + int in_wait; + uintptr_t entering; + int wait_count; + Thread *wait_set; + struct monitor *next; +} Monitor; + +struct thread { + int id; + pthread_t tid; + ExecEnv *ee; + void *stack_top; + void *stack_base; + Monitor *wait_mon; + Monitor *blocked_mon; + Thread *wait_prev; + Thread *wait_next; + pthread_cond_t wait_cv; + pthread_cond_t park_cv; + pthread_mutex_t park_lock; + long long blocked_count; + long long waited_count; + Thread *prev, *next; + unsigned int wait_id; + unsigned int notify_id; + char suspend; + char park_state; + char interrupted; + char interrupting; + char suspend_state; + CLASSLIB_THREAD_EXTRA_FIELDS +}; + +extern Thread *threadSelf(); +extern long long javaThreadId(Thread *thread); +extern Thread *jThread2Thread(Object *jThread); +extern long long jThread2ThreadId(Object *jthread); + +extern void *getStackTop(Thread *thread); +extern void *getStackBase(Thread *thread); + +extern int getThreadsCount(); +extern int getPeakThreadsCount(); +extern void resetPeakThreadsCount(); +extern long long getTotalStartedThreadsCount(); + +extern void threadInterrupt(Thread *thread); +extern void threadSleep(Thread *thread, long long ms, int ns); +extern void threadYield(Thread *thread); + +extern int threadIsAlive(Thread *thread); +extern int threadInterrupted(Thread *thread); +extern int threadIsInterrupted(Thread *thread); +extern int systemIdle(Thread *self); + +extern void threadPark(Thread *thread, int absolute, long long time); +extern void threadUnpark(Thread *thread); + +extern void suspendAllThreads(Thread *thread); +extern void resumeAllThreads(Thread *thread); + +extern void createVMThread(char *name, void (*start)(Thread*)); + +extern void disableSuspend0(Thread *thread, void *stack_top); +extern void enableSuspend(Thread *thread); +extern void fastEnableSuspend(Thread *thread); + +extern Thread *attachJNIThread(char *name, char is_daemon, Object *group); +extern void detachJNIThread(Thread *thread); + +extern char *getThreadStateString(Thread *thread); + +extern Thread *findThreadById(long long id); +extern Thread *findRunningThreadByTid(int tid); +extern void suspendThread(Thread *thread); +extern void resumeThread(Thread *thread); +extern Object *runningThreadStackTrace(Thread *thread, int max_depth, + int *in_native); +extern Object *runningThreadObjects(); +extern void printThreadsDump(Thread *self); + +#define disableSuspend(thread) \ +{ \ + sigjmp_buf *env; \ + env = alloca(sizeof(sigjmp_buf)); \ + sigsetjmp(*env, FALSE); \ + disableSuspend0(thread, (void*)env); \ +} + +#define fastDisableSuspend(thread) \ +{ \ + thread->suspend_state = SUSP_CRITICAL; \ + MBARRIER(); \ +} + +typedef struct { + pthread_mutex_t lock; + pthread_cond_t cv; +} VMWaitLock; + +typedef pthread_mutex_t VMLock; + +#define initVMLock(lock) pthread_mutex_init(&lock, NULL) +#define initVMWaitLock(wait_lock) { \ + pthread_mutex_init(&wait_lock.lock, NULL); \ + pthread_cond_init(&wait_lock.cv, NULL); \ +} + +#define lockVMLock(lock, self) { \ + classlibSetThreadState(self, BLOCKED); \ + pthread_mutex_lock(&lock); \ + classlibSetThreadState(self, RUNNING); \ +} + +#define tryLockVMLock(lock, self) \ + (pthread_mutex_trylock(&lock) == 0) + +#define unlockVMLock(lock, self) if(self) pthread_mutex_unlock(&lock) + +#define lockVMWaitLock(wait_lock, self) lockVMLock(wait_lock.lock, self) +#define unlockVMWaitLock(wait_lock, self) unlockVMLock(wait_lock.lock, self) + +#define waitVMWaitLock(wait_lock, self) { \ + classlibSetThreadState(self, WAITING); \ + pthread_cond_wait(&wait_lock.cv, &wait_lock.lock); \ + classlibSetThreadState(self, RUNNING); \ +} + +#define timedWaitVMWaitLock(wait_lock, self, ms) { \ + struct timeval tv; \ + struct timespec ts; \ + gettimeofday(&tv, 0); \ + ts.tv_sec = tv.tv_sec + ms/1000; \ + ts.tv_nsec = (tv.tv_usec + ((ms%1000)*1000))*1000; \ + if(ts.tv_nsec > 999999999L) { \ + ts.tv_sec++; \ + ts.tv_nsec -= 1000000000L; \ + } \ + classlibSetThreadState(self, TIMED_WAITING); \ + pthread_cond_timedwait(&wait_lock.cv, &wait_lock.lock, &ts); \ + classlibSetThreadState(self, RUNNING); \ +} + +#define notifyVMWaitLock(wait_lock, self) pthread_cond_signal(&wait_lock.cv) +#define notifyAllVMWaitLock(wait_lock, self) pthread_cond_broadcast(&wait_lock.cv) +#endif +