implement primitive testing framework and provide for GC stress testing

This commit is contained in:
Joel Dice 2007-07-15 19:03:02 -06:00
parent 3121002ffd
commit 4670055b03
11 changed files with 298 additions and 297 deletions

194
makefile
View File

@ -1,4 +1,4 @@
MAKEFLAGS = -s
#MAKEFLAGS = -s
arch = $(shell uname -m)
ifeq ($(arch),i586)
@ -8,9 +8,13 @@ ifeq ($(arch),i686)
arch = i386
endif
bld = build/$(arch)
mode = debug
bld = build/$(arch)/$(mode)
cls = build/classes
src = src
classpath = classpath
test = test
cxx = g++
cc = gcc
@ -21,32 +25,37 @@ javac = javac
warnings = -Wall -Wextra -Werror -Wold-style-cast -Wunused-parameter \
-Winit-self -Wconversion
slow = -O0 -g3
fast = -Os -DNDEBUG
#thread-cflags = -DNO_THREADS
thread-cflags = -pthread
thread-lflags = -lpthread
cflags = $(warnings) -fPIC -fno-rtti -fno-exceptions -fvisibility=hidden \
-I$(src) -I$(bld) $(thread-cflags) -D__STDC_LIMIT_MACROS
ifeq ($(mode),debug)
cflags += -O0 -g3
endif
ifeq ($(mode),stress)
cflags += -O0 -g3 -DVM_STRESS
endif
ifeq ($(mode),stress-major)
cflags += -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR
endif
ifeq ($(mode),fast)
fast = -Os -DNDEBUG
endif
lflags = $(thread-lflags) -ldl
test-cflags = -DDEBUG_MEMORY
stress-cflags = -DDEBUG_MEMORY -DDEBUG_MEMORY_MAJOR
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(bld)/%.o,$(x)))
asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(bld)/%.o,$(x)))
java-classes = \
$(foreach x,$(1),$(patsubst $(2)/%.java,$(bld)/classes/%.class,$(x)))
java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(cls)/%.class,$(x)))
stdcpp-sources = $(src)/stdc++.cpp
stdcpp-objects = $(call cpp-objects,$(stdcpp-sources),$(src))
stdcpp-cflags = $(fast) $(cflags)
jni-sources = $(classpath)/java/lang/System.cpp
jni-objects = $(call cpp-objects,$(jni-sources),$(classpath))
jni-cflags = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \
$(slow) $(cflags)
jni-cflags = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(cflags)
jni-library = $(bld)/libnatives.so
generated-code = \
@ -91,7 +100,6 @@ interpreter-asm-objects = \
interpreter-objects = \
$(interpreter-cpp-objects) \
$(interpreter-asm-objects)
interpreter-cflags = $(slow) $(cflags)
generator-headers = \
$(src)/input.h \
@ -100,53 +108,31 @@ generator-sources = \
$(src)/type-generator.cpp
generator-objects = $(call cpp-objects,$(generator-sources),$(src))
generator-executable = $(bld)/generator
generator-cflags = $(slow) $(cflags)
executable = $(bld)/vm
test-cpp-objects = \
$(patsubst $(bld)/%,$(bld)/test-%,$(interpreter-cpp-objects))
test-asm-objects = \
$(patsubst $(bld)/%,$(bld)/test-%,$(interpreter-asm-objects))
test-objects = \
$(test-cpp-objects) \
$(test-asm-objects)
test-executable = $(bld)/test-vm
stress-cpp-objects = \
$(patsubst $(bld)/%,$(bld)/stress-%,$(interpreter-cpp-objects))
stress-asm-objects = \
$(patsubst $(bld)/%,$(bld)/stress-%,$(interpreter-asm-objects))
stress-objects = \
$(stress-cpp-objects) \
$(stress-asm-objects)
stress-executable = $(bld)/stress-vm
fast-cpp-objects = \
$(patsubst $(bld)/%,$(bld)/fast-%,$(interpreter-cpp-objects))
fast-asm-objects = \
$(patsubst $(bld)/%,$(bld)/fast-%,$(interpreter-asm-objects))
fast-objects = \
$(fast-cpp-objects) \
$(fast-asm-objects)
fast-executable = $(bld)/fast-vm
fast-cflags = $(fast) $(cflags)
classpath-sources = $(shell find $(classpath)/java -name '*.java')
classpath-sources = $(shell find $(classpath) -name '*.java')
classpath-classes = $(call java-classes,$(classpath-sources),$(classpath))
input = $(bld)/classes/TestExceptions.class
input-depends = \
$(classpath-classes) \
$(jni-library)
classpath-objects = $(classpath-classes) $(jni-library)
gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input))
test-sources = $(shell find $(test) -name '*.java')
test-classes = $(call java-classes,$(test-sources),$(test))
input = $(cls)/Hello.class
classpath-objects = $(classpath-classes) $(jni-library)
class-name = $(patsubst $(cls)/%.class,%,$(1))
class-names = $(foreach x,$(1),$(call class-name,$(x)))
flags = -cp $(cls) -hs 67108864
args = $(flags) $(call class-name,$(input))
.PHONY: build
build: $(executable)
$(input): $(input-depends)
$(input): $(classpath-objects)
.PHONY: run
run: $(executable) $(input)
@ -156,37 +142,14 @@ run: $(executable) $(input)
debug: $(executable) $(input)
LD_LIBRARY_PATH=$(bld) gdb --args $(<) $(args)
.PHONY: fast
fast: $(fast-executable)
ls -lh $(<)
.PHONY: vg
vg: $(executable) $(input)
LD_LIBRARY_PATH=$(bld) $(vg) $(<) $(args)
.PHONY: test
test: $(test-executable) $(input)
LD_LIBRARY_PATH=$(bld) $(vg) $(<) $(args)
.PHONY: stress
stress: $(stress-executable) $(input)
LD_LIBRARY_PATH=$(bld) $(vg) $(<) $(args)
.PHONY: run-all
run-all: $(executable)
set -e; for x in $(all-input); do echo "$$x:"; $(<) $$x; echo; done
.PHONY: vg-all
vg-all: $(executable)
set -e; for x in $(all-input); do echo "$$x:"; $(vg) -q $(<) $$x; done
.PHONY: test-all
test-all: $(test-executable)
set -e; for x in $(all-input); do echo "$$x:"; $(vg) -q $(<) $$x; done
.PHONY: stress-all
stress-all: $(stress-executable)
set -e; for x in $(all-input); do echo "$$x:"; $(vg) -q $(<) $$x; done
test: $(executable) $(classpath-objects) $(test-classes)
LD_LIBRARY_PATH=$(bld) /bin/bash $(test)/test.sh \
$(<) "$(flags)" $(call class-names,$(test-classes))
.PHONY: clean
clean:
@ -201,61 +164,35 @@ $(generated-code): %.cpp: $(src)/types.def $(generator-executable)
$(bld)/type-generator.o: \
$(generator-headers)
$(bld)/classes/%.class: $(classpath)/%.java
define compile-class
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(javac) -bootclasspath $(classpath) -classpath $(classpath) \
-d $(bld)/classes $(<)
$(javac) -bootclasspath $(classpath) -classpath $(classpath) -d $(cls) $(<)
endef
$(cls)/%.class: $(classpath)/%.java
$(compile-class)
$(cls)/%.class: $(test)/%.java
$(compile-class)
define compile-object
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(cflags) -c $(<) -o $(@)
endef
$(stdcpp-objects): $(bld)/%.o: $(src)/%.cpp
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(stdcpp-cflags) -c $(<) -o $(@)
$(compile-object)
$(interpreter-cpp-objects): $(bld)/%.o: $(src)/%.cpp $(interpreter-depends)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) -c $(<) -o $(@)
$(compile-object)
$(interpreter-asm-objects): $(bld)/%.o: $(src)/%.S
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) -c $(<) -o $(@)
$(test-cpp-objects): $(bld)/test-%.o: $(src)/%.cpp $(interpreter-depends)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) $(test-cflags) -c $(<) -o $(@)
$(test-asm-objects): $(bld)/test-%.o: $(src)/%.S
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) $(test-cflags) -c $(<) -o $(@)
$(stress-cpp-objects): $(bld)/stress-%.o: $(src)/%.cpp $(interpreter-depends)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) $(stress-cflags) -c $(<) -o $(@)
$(stress-asm-objects): $(bld)/stress-%.o: $(src)/%.S
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(interpreter-cflags) $(stress-cflags) -c $(<) -o $(@)
$(compile-object)
$(generator-objects): $(bld)/%.o: $(src)/%.cpp
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(generator-cflags) -c $(<) -o $(@)
$(fast-cpp-objects): $(bld)/fast-%.o: $(src)/%.cpp $(interpreter-depends)
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(fast-cflags) -c $(<) -o $(@)
$(fast-asm-objects): $(bld)/fast-%.o: $(src)/%.S
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(fast-cflags) -c $(<) -o $(@)
$(compile-object)
$(jni-objects): $(bld)/%.o: $(classpath)/%.cpp
@echo "compiling $(@)"
@ -270,19 +207,6 @@ $(executable): $(interpreter-objects) $(stdcpp-objects)
@echo "linking $(@)"
$(cc) $(lflags) $(^) -o $(@)
$(test-executable): $(test-objects) $(stdcpp-objects)
@echo "linking $(@)"
$(cc) $(lflags) $(^) -o $(@)
$(stress-executable): $(stress-objects) $(stdcpp-objects)
@echo "linking $(@)"
$(cc) $(lflags) $(^) -o $(@)
$(fast-executable): $(fast-objects) $(stdcpp-objects)
@echo "linking $(@)"
$(cc) $(lflags) $(^) -o $(@)
strip --strip-all $(@)
.PHONY: generator
generator: $(generator-executable)

View File

@ -281,155 +281,6 @@ postCollect(Thread* t)
}
}
void
collect(Thread* t, Heap::CollectionType type)
{
Machine* m = t->vm;
class Client: public Heap::Client {
public:
Client(Machine* m): m(m) { }
virtual void visitRoots(Heap::Visitor* v) {
v->visit(&(m->classMap));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->builtinMap));
v->visit(&(m->monitorMap));
v->visit(&(m->types));
for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v);
}
postVisit(m->rootThread, v);
}
virtual unsigned sizeInWords(object o) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
return extendedSize
(t, o, baseSize(t, o, m->heap->follow(objectClass(t, o))));
}
virtual unsigned copiedSizeInWords(object o) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o)));
if (objectExtended(t, o) or hashTaken(t, o)) {
++ n;
}
return n;
}
virtual void copy(object o, object dst) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
object class_ = m->heap->follow(objectClass(t, o));
unsigned base = baseSize(t, o, class_);
unsigned n = extendedSize(t, o, base);
memcpy(dst, o, n * BytesPerWord);
if (hashTaken(t, o)) {
cast<uintptr_t>(dst, 0) &= PointerMask;
cast<uintptr_t>(dst, 0) |= ExtendedMark;
extendedWord(t, dst, base) = takeHash(t, o);
}
}
virtual void walk(void* p, Heap::Walker* w) {
Thread* t = m->rootThread;
p = m->heap->follow(mask(p));
object class_ = m->heap->follow(objectClass(t, p));
object objectMask = m->heap->follow(classObjectMask(t, class_));
if (objectMask) {
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
// p, class_, objectMask, intArrayLength(t, objectMask));
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(p, fixedSize - BytesPerWord) : 0);
int mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
// fprintf
// (stderr,
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
// fixedSize, arrayLength, arrayElementSize, mask[0]);
unsigned fixedSizeInWords = divide(fixedSize, BytesPerWord);
unsigned arrayElementSizeInWords
= divide(arrayElementSize, BytesPerWord);
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
if (mask[wordOf(i)] & (static_cast<uintptr_t>(1) << bitOf(i))) {
if (not w->visit(i)) {
return;
}
}
}
bool arrayObjectElements = false;
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
arrayObjectElements = true;
break;
}
}
if (arrayObjectElements) {
for (unsigned i = 0; i < arrayLength; ++i) {
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
if (not w->visit
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
{
return;
}
}
}
}
}
} else {
w->visit(0);
}
}
private:
Machine* m;
} it(m);
m->unsafe = true;
m->heap->collect(type, &it);
m->unsafe = false;
postCollect(m->rootThread);
for (object f = m->finalizeQueue; f; f = finalizerNext(t, f)) {
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
(t, finalizerTarget(t, f));
}
m->finalizeQueue = 0;
killZombies(t, m->rootThread);
}
object
makeByteArray(Thread* t, const char* format, va_list a)
{
@ -1467,6 +1318,9 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread,
peer((parent ? parent->child : 0)),
child(0),
state(NoState),
#ifdef VM_STRESS
stress(false),
#endif // VM_STRESS
systemThread(0),
javaThread(javaThread),
code(0),
@ -1585,6 +1439,8 @@ exit(Thread* t)
void
enter(Thread* t, Thread::State s)
{
stress(t);
if (s == t->state) return;
ACQUIRE_RAW(t, t->vm->stateLock);
@ -2198,6 +2054,155 @@ objectMonitor(Thread* t, object o)
}
}
void
collect(Thread* t, Heap::CollectionType type)
{
Machine* m = t->vm;
class Client: public Heap::Client {
public:
Client(Machine* m): m(m) { }
virtual void visitRoots(Heap::Visitor* v) {
v->visit(&(m->classMap));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->builtinMap));
v->visit(&(m->monitorMap));
v->visit(&(m->types));
for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v);
}
postVisit(m->rootThread, v);
}
virtual unsigned sizeInWords(object o) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
return extendedSize
(t, o, baseSize(t, o, m->heap->follow(objectClass(t, o))));
}
virtual unsigned copiedSizeInWords(object o) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o)));
if (objectExtended(t, o) or hashTaken(t, o)) {
++ n;
}
return n;
}
virtual void copy(object o, object dst) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
object class_ = m->heap->follow(objectClass(t, o));
unsigned base = baseSize(t, o, class_);
unsigned n = extendedSize(t, o, base);
memcpy(dst, o, n * BytesPerWord);
if (hashTaken(t, o)) {
cast<uintptr_t>(dst, 0) &= PointerMask;
cast<uintptr_t>(dst, 0) |= ExtendedMark;
extendedWord(t, dst, base) = takeHash(t, o);
}
}
virtual void walk(void* p, Heap::Walker* w) {
Thread* t = m->rootThread;
p = m->heap->follow(mask(p));
object class_ = m->heap->follow(objectClass(t, p));
object objectMask = m->heap->follow(classObjectMask(t, class_));
if (objectMask) {
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
// p, class_, objectMask, intArrayLength(t, objectMask));
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(p, fixedSize - BytesPerWord) : 0);
int mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
// fprintf
// (stderr,
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
// fixedSize, arrayLength, arrayElementSize, mask[0]);
unsigned fixedSizeInWords = divide(fixedSize, BytesPerWord);
unsigned arrayElementSizeInWords
= divide(arrayElementSize, BytesPerWord);
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
if (mask[wordOf(i)] & (static_cast<uintptr_t>(1) << bitOf(i))) {
if (not w->visit(i)) {
return;
}
}
}
bool arrayObjectElements = false;
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
arrayObjectElements = true;
break;
}
}
if (arrayObjectElements) {
for (unsigned i = 0; i < arrayLength; ++i) {
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
if (not w->visit
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
{
return;
}
}
}
}
}
} else {
w->visit(0);
}
}
private:
Machine* m;
} it(m);
m->unsafe = true;
m->heap->collect(type, &it);
m->unsafe = false;
postCollect(m->rootThread);
for (object f = m->finalizeQueue; f; f = finalizerNext(t, f)) {
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
(t, finalizerTarget(t, f));
}
m->finalizeQueue = 0;
killZombies(t, m->rootThread);
}
void
noop()
{ }

View File

@ -1172,6 +1172,9 @@ class Thread {
Thread* peer;
Thread* child;
State state;
#ifdef VM_STRESS
bool stress;
#endif // VM_STRESS
System::Thread* systemThread;
object javaThread;
object code;
@ -1192,7 +1195,8 @@ objectClass(Thread*, object o)
return mask(cast<object>(o, 0));
}
void enter(Thread* t, Thread::State state);
void
enter(Thread* t, Thread::State state);
class StateResource {
public:
@ -1207,9 +1211,41 @@ class StateResource {
Thread::State oldState;
};
void
collect(Thread* t, Heap::CollectionType type);
#ifdef VM_STRESS
inline void
stress(Thread* t)
{
if ((not t->stress) and t->state != Thread::NoState) {
t->stress = true;
ENTER(t, Thread::ExclusiveState);
# ifdef VM_STRESS_MAJOR
collect(t, Heap::MajorCollection);
# else // not VM_STRESS_MAJOR
collect(t, Heap::MinorCollection);
# endif // not VM_STRESS_MAJOR
t->stress = false;
}
}
#else // not VM_STRESS
inline void
stress(Thread*)
{ }
#endif // not VM_STRESS
class MonitorResource {
public:
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
stress(t);
if (not m->tryAcquire(t)) {
ENTER(t, Thread::IdleState);
m->acquire(t);
@ -1274,6 +1310,8 @@ allocate2(Thread* t, unsigned sizeInBytes);
inline object
allocate(Thread* t, unsigned sizeInBytes)
{
stress(t);
if (UNLIKELY(t->heapIndex + divide(sizeInBytes, BytesPerWord)
>= Thread::HeapSizeInWords
or t->vm->exclusive))
@ -1883,6 +1921,8 @@ objectMonitor(Thread* t, object o);
inline void
acquire(Thread* t, object o)
{
stress(t);
System::Monitor* m = objectMonitor(t, o);
if (DebugMonitors) {
@ -1912,6 +1952,8 @@ release(Thread* t, object o)
inline void
wait(Thread* t, object o, int64_t milliseconds)
{
stress(t);
System::Monitor* m = objectMonitor(t, o);
if (DebugMonitors) {

View File

@ -524,7 +524,7 @@ parsePath(vm::System* s, const char* path)
return v;
}
void
int
run(unsigned heapSize, const char* path, const char* class_, int argc,
const char** argv)
{
@ -535,7 +535,7 @@ run(unsigned heapSize, const char* path, const char* class_, int argc,
Heap* heap = makeHeap(&s);
run(&s, heap, &cf, class_, argc, argv);
int exitCode = run(&s, heap, &cf, class_, argc, argv);
heap->dispose();
@ -544,6 +544,8 @@ run(unsigned heapSize, const char* path, const char* class_, int argc,
}
s.free(pathv);
return exitCode;
}
void
@ -584,7 +586,5 @@ main(int ac, const char** av)
usageAndExit(av[0]);
}
run(heapSize, path, class_, argc, argv);
return 0;
return run(heapSize, path, class_, argc, argv);
}

View File

@ -2339,7 +2339,7 @@ run(Thread* t, const char* className, const char* methodName,
return ::run(t);
}
void
int
run(System* system, Heap* heap, ClassFinder* classFinder,
const char* className, int argc, const char** argv)
{
@ -2350,7 +2350,12 @@ run(System* system, Heap* heap, ClassFinder* classFinder,
::run(&t, className, argc, argv);
int exitCode = 0;
if (t.exception) exitCode = -1;
exit(&t);
return exitCode;
}
}

View File

@ -12,7 +12,7 @@ object
run(Thread* t, const char* className, const char* methodName,
const char* methodSpec, ...);
void
int
run(System* sys, Heap* heap, ClassFinder* classFinder,
const char* className, int argc, const char** argv);

View File

@ -1,4 +1,4 @@
public class TestExceptions {
public class Exceptions {
private static void evenMoreDangerous() {
throw new RuntimeException("chaos! panic! overwhelming anxiety!");

View File

@ -1,4 +1,4 @@
public class TestGC {
public class GC {
private static void small() {
for (int i = 0; i < 1024; ++i) {

View File

@ -1,7 +1,6 @@
public class TestThreads implements Runnable {
public class Threads implements Runnable {
public static void main(String[] args) {
TestThreads test = new TestThreads();
Threads test = new Threads();
Thread thread = new Thread(test);
try {

26
test/test.sh Normal file
View File

@ -0,0 +1,26 @@
#!/bin/bash
log=build/log.txt
vm=${1}; shift
flags=${1}; shift
tests=${@}
echo -n "" >${log}
for test in ${tests}; do
printf "${test}: "
${vm} ${flags} ${test} >>${log} 2>&1
if (( ${?} == 0 )); then
echo "success"
else
echo "fail"
trouble=1
fi
done
if [ -n "${trouble}" ]; then
printf "\nsee ${log} for output\n"
fi