Merge
This commit is contained in:
commit
8b93afb3a2
@ -51,7 +51,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
||||
# Add conditional directories here when needed.
|
||||
ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
|
||||
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/ThreadSignalMask
|
||||
endif
|
||||
|
||||
ifeq ($(TOOLCHAIN_TYPE), solstudio)
|
||||
|
@ -499,11 +499,14 @@ HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() {
|
||||
return _next_offset_threshold;
|
||||
}
|
||||
|
||||
void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top) {
|
||||
void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||
// The first BOT entry should have offset 0.
|
||||
reset_bot();
|
||||
alloc_block(_bottom, obj_top);
|
||||
}
|
||||
if (fill_size > 0) {
|
||||
alloc_block(obj_top, fill_size);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void G1BlockOffsetArrayContigSpace::print_on(outputStream* out) {
|
||||
|
@ -372,7 +372,7 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray {
|
||||
HeapWord* block_start_unsafe(const void* addr);
|
||||
HeapWord* block_start_unsafe_const(const void* addr) const;
|
||||
|
||||
void set_for_starts_humongous(HeapWord* obj_top);
|
||||
void set_for_starts_humongous(HeapWord* obj_top, size_t fill_size);
|
||||
|
||||
virtual void print_on(outputStream* out) PRODUCT_RETURN;
|
||||
};
|
||||
|
@ -339,11 +339,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||
// thread to calculate the object size incorrectly.
|
||||
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
|
||||
|
||||
size_t fill_size = word_size_sum - word_size;
|
||||
if (fill_size >= min_fill_size()) {
|
||||
fill_with_objects(obj_top, fill_size);
|
||||
} else {
|
||||
fill_size = 0;
|
||||
}
|
||||
|
||||
// We will set up the first region as "starts humongous". This
|
||||
// will also update the BOT covering all the regions to reflect
|
||||
// that there is a single object that starts at the bottom of the
|
||||
// first region.
|
||||
first_hr->set_starts_humongous(obj_top);
|
||||
first_hr->set_starts_humongous(obj_top, fill_size);
|
||||
first_hr->set_allocation_context(context);
|
||||
// Then, if there are any, we will set up the "continues
|
||||
// humongous" regions.
|
||||
@ -365,9 +372,9 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||
|
||||
// Now that the BOT and the object header have been initialized,
|
||||
// we can update top of the "starts humongous" region.
|
||||
first_hr->set_top(MIN2(first_hr->end(), obj_top));
|
||||
first_hr->set_top(first_hr->end());
|
||||
if (_hr_printer.is_active()) {
|
||||
_hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->top());
|
||||
_hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->end());
|
||||
}
|
||||
|
||||
// Now, we will update the top fields of the "continues humongous"
|
||||
@ -375,25 +382,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||
hr = NULL;
|
||||
for (uint i = first + 1; i < last; ++i) {
|
||||
hr = region_at(i);
|
||||
if ((i + 1) == last) {
|
||||
// last continues humongous region
|
||||
assert(hr->bottom() < obj_top && obj_top <= hr->end(),
|
||||
"new_top should fall on this region");
|
||||
hr->set_top(obj_top);
|
||||
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, obj_top);
|
||||
} else {
|
||||
// not last one
|
||||
assert(obj_top > hr->end(), "obj_top should be above this region");
|
||||
hr->set_top(hr->end());
|
||||
hr->set_top(hr->end());
|
||||
if (_hr_printer.is_active()) {
|
||||
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
|
||||
}
|
||||
}
|
||||
// If we have continues humongous regions (hr != NULL), its top should
|
||||
// match obj_top.
|
||||
assert(hr == NULL || (hr->top() == obj_top), "sanity");
|
||||
|
||||
assert(hr == NULL || (hr->bottom() < obj_top && obj_top <= hr->end()),
|
||||
"obj_top should be in last region");
|
||||
|
||||
check_bitmaps("Humongous Region Allocation", first_hr);
|
||||
|
||||
increase_used(word_size * HeapWordSize);
|
||||
increase_used(word_size_sum * HeapWordSize);
|
||||
|
||||
for (uint i = first; i < last; ++i) {
|
||||
_humongous_set.add(region_at(i));
|
||||
|
@ -211,14 +211,14 @@ void HeapRegion::calc_gc_efficiency() {
|
||||
_gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
|
||||
}
|
||||
|
||||
void HeapRegion::set_starts_humongous(HeapWord* obj_top) {
|
||||
void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||
assert(!is_humongous(), "sanity / pre-condition");
|
||||
assert(top() == bottom(), "should be empty");
|
||||
|
||||
_type.set_starts_humongous();
|
||||
_humongous_start_region = this;
|
||||
|
||||
_offsets.set_for_starts_humongous(obj_top);
|
||||
_offsets.set_for_starts_humongous(obj_top, fill_size);
|
||||
}
|
||||
|
||||
void HeapRegion::set_continues_humongous(HeapRegion* first_hr) {
|
||||
@ -756,16 +756,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||
size_t obj_size = block_size(p);
|
||||
object_num += 1;
|
||||
|
||||
if (is_region_humongous != g1->is_humongous(obj_size) &&
|
||||
!g1->is_obj_dead(obj, this)) { // Dead objects may have bigger block_size since they span several objects.
|
||||
gclog_or_tty->print_cr("obj " PTR_FORMAT " is of %shumongous size ("
|
||||
SIZE_FORMAT " words) in a %shumongous region",
|
||||
p2i(p), g1->is_humongous(obj_size) ? "" : "non-",
|
||||
obj_size, is_region_humongous ? "" : "non-");
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g1->is_obj_dead_cond(obj, this, vo)) {
|
||||
if (obj->is_oop()) {
|
||||
Klass* klass = obj->klass();
|
||||
@ -876,14 +866,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||
}
|
||||
}
|
||||
|
||||
if (is_region_humongous && object_num > 1) {
|
||||
gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] is humongous "
|
||||
"but has " SIZE_FORMAT ", objects",
|
||||
p2i(bottom()), p2i(end()), object_num);
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
|
||||
verify_strong_code_roots(vo, failures);
|
||||
}
|
||||
|
||||
|
@ -455,9 +455,9 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
||||
// the first region in a series of one or more contiguous regions
|
||||
// that will contain a single "humongous" object.
|
||||
//
|
||||
// obj_top : points to the end of the humongous object that's being
|
||||
// allocated.
|
||||
void set_starts_humongous(HeapWord* obj_top);
|
||||
// obj_top : points to the top of the humongous object.
|
||||
// fill_size : size of the filler object at the end of the region series.
|
||||
void set_starts_humongous(HeapWord* obj_top, size_t fill_size);
|
||||
|
||||
// Makes the current region be a "continues humongous'
|
||||
// region. first_hr is the "start humongous" region of the series
|
||||
|
@ -37,10 +37,10 @@ void Test_log_length() {
|
||||
|
||||
// Write long message to output file
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=develop",
|
||||
LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace",
|
||||
NULL, NULL, NULL);
|
||||
ResourceMark rm;
|
||||
outputStream* logstream = LogHandle(logging)::develop_stream();
|
||||
outputStream* logstream = LogHandle(logging)::trace_stream();
|
||||
logstream->print_cr("01:1234567890-"
|
||||
"02:1234567890-"
|
||||
"03:1234567890-"
|
||||
|
@ -49,11 +49,21 @@
|
||||
#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
||||
#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
||||
#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
||||
|
||||
// Macros for logging that should be excluded in product builds.
|
||||
// Available for levels Info, Debug and Trace. Includes test macro that
|
||||
// evaluates to false in product builds.
|
||||
#ifndef PRODUCT
|
||||
#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Develop>
|
||||
#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
||||
#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
||||
#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
||||
#define develop_log_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__)
|
||||
#else
|
||||
#define DUMMY_ARGUMENT_CONSUMER(...)
|
||||
#define log_develop(...) DUMMY_ARGUMENT_CONSUMER
|
||||
#define log_develop_info(...) DUMMY_ARGUMENT_CONSUMER
|
||||
#define log_develop_debug(...) DUMMY_ARGUMENT_CONSUMER
|
||||
#define log_develop_trace(...) DUMMY_ARGUMENT_CONSUMER
|
||||
#define develop_log_is_enabled(...) false
|
||||
#endif
|
||||
|
||||
// Convenience macro to test if the logging is enabled on the specified level for given tags.
|
||||
@ -88,6 +98,11 @@ class Log VALUE_OBJ_CLASS_SPEC {
|
||||
// is not __NO_TAG, the number of tags given exceeds the maximum allowed.
|
||||
STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported!
|
||||
|
||||
// Empty constructor to avoid warnings on MSVC about unused variables
|
||||
// when the log instance is only used for static functions.
|
||||
Log() {
|
||||
}
|
||||
|
||||
static bool is_level(LogLevelType level) {
|
||||
return LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().is_level(level);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ void LogConfiguration::post_initialize() {
|
||||
LogDiagnosticCommand::registerCommand();
|
||||
LogHandle(logging) log;
|
||||
log.info("Log configuration fully initialized.");
|
||||
log_develop_info(logging)("Develop logging is available.");
|
||||
if (log.is_trace()) {
|
||||
ResourceMark rm;
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
|
@ -29,14 +29,8 @@
|
||||
|
||||
// The list of log levels:
|
||||
//
|
||||
// develop - A non-product level that is finer than trace.
|
||||
// Should be used for really expensive and/or
|
||||
// extensive logging, or logging that shouldn't
|
||||
// or can't be included in a product build.
|
||||
//
|
||||
// trace - Finest level of logging in product builds.
|
||||
// Use for extensive/noisy logging that can
|
||||
// give slow-down when enabled.
|
||||
// trace - Finest level of logging. Use for extensive/noisy
|
||||
// logging that can give slow-down when enabled.
|
||||
//
|
||||
// debug - A finer level of logging. Use for semi-noisy
|
||||
// logging that is does not fit the info level.
|
||||
@ -49,7 +43,6 @@
|
||||
// error - Critical messages caused by errors.
|
||||
//
|
||||
#define LOG_LEVEL_LIST \
|
||||
NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \
|
||||
LOG_LEVEL(Trace, trace) \
|
||||
LOG_LEVEL(Debug, debug) \
|
||||
LOG_LEVEL(Info, info) \
|
||||
|
29
hotspot/test/runtime/ThreadSignalMask/Prog.java
Normal file
29
hotspot/test/runtime/ThreadSignalMask/Prog.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class Prog {
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Java class invoked: " + args[0]);
|
||||
}
|
||||
}
|
118
hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java
Normal file
118
hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.ProcessBuilder.Redirect;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key cte_test
|
||||
* @bug 4345157
|
||||
* @summary JDK 1.3.0 alters thread signal mask
|
||||
* @requires (os.simpleArch == "sparcv9")
|
||||
* @library /testlibrary
|
||||
* @compile Prog.java
|
||||
* @run main/native ThreadSignalMask
|
||||
*/
|
||||
public class ThreadSignalMask {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
String testClasses = getSystemProperty("test.classes");
|
||||
|
||||
String testNativePath = getSystemProperty("test.nativepath");
|
||||
|
||||
String testJdk = getSystemProperty("test.jdk");
|
||||
|
||||
Path currentDirPath = Paths.get(".");
|
||||
|
||||
Path classFilePath = Paths.get(testClasses,
|
||||
Prog.class.getSimpleName() + ".class");
|
||||
|
||||
// copy Prog.class file to be invoked from native
|
||||
Files.copy(classFilePath,
|
||||
currentDirPath.resolve(Prog.class.getSimpleName() + ".class"),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
Path executableFilePath = Paths.get(testNativePath,
|
||||
ThreadSignalMask.class.getSimpleName());
|
||||
|
||||
Path executableFileLocalPath = currentDirPath.resolve(
|
||||
ThreadSignalMask.class.getSimpleName());
|
||||
|
||||
// copy compiled native executable ThreadSignalMask
|
||||
Files.copy(executableFilePath,
|
||||
executableFileLocalPath,
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
executableFileLocalPath.toFile().setExecutable(true);
|
||||
|
||||
long[] intervalsArray = {2000, 5000, 10000, 20000};
|
||||
|
||||
List<String> processArgs = Arrays.asList(
|
||||
executableFileLocalPath.toString(),
|
||||
testJdk);
|
||||
ProcessBuilder pb = new ProcessBuilder(processArgs);
|
||||
pb.redirectOutput(Redirect.INHERIT);
|
||||
pb.redirectError(Redirect.INHERIT);
|
||||
int result = 0;
|
||||
for (long interval : intervalsArray) {
|
||||
Process p = pb.start();
|
||||
|
||||
// sleep for a specified period of time to let native run
|
||||
sleep(interval);
|
||||
p.destroy();
|
||||
|
||||
// wait for process to finish, get exit value and validate it
|
||||
result = p.waitFor();
|
||||
System.out.println("Result = " + result);
|
||||
if (result == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Asserts.assertEquals(result, 0);
|
||||
}
|
||||
|
||||
// Utility method to handle Thread.sleep
|
||||
private static void sleep(long millis) throws InterruptedException {
|
||||
System.out.println("Sleep for " + millis);
|
||||
Thread.sleep(millis);
|
||||
}
|
||||
|
||||
// Utility method to retrieve and validate system properties
|
||||
private static String getSystemProperty(String propertyName) throws Error {
|
||||
String systemProperty = System.getProperty(propertyName, "").trim();
|
||||
System.out.println(propertyName + " = " + systemProperty);
|
||||
if (systemProperty.isEmpty()) {
|
||||
throw new Error("TESTBUG: property " + propertyName + " is empty");
|
||||
}
|
||||
return systemProperty;
|
||||
}
|
||||
}
|
253
hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
Normal file
253
hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#define _POSIX_PTHREAD_SEMANTICS // to enable POSIX semantics for certain common APIs
|
||||
|
||||
#include <jni.h>
|
||||
#include <dlfcn.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void *handle;
|
||||
char *error;
|
||||
char path[PATH_MAX];
|
||||
|
||||
jint(JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL;
|
||||
|
||||
JavaVM *jvm;
|
||||
|
||||
// method to perform dlclose on an open dynamic library handle
|
||||
void closeHandle() {
|
||||
dlclose(handle);
|
||||
if ((error = dlerror()) != NULL) {
|
||||
fputs("Error occurred while closing handle\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
// method to exit with a fail status
|
||||
void fail() {
|
||||
if (handle) {
|
||||
closeHandle();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// method to handle occurred error and fail
|
||||
void handleError(char *messageTitle, char *messageBody) {
|
||||
fprintf(stderr, "%s: %s\n", messageTitle, messageBody);
|
||||
fail();
|
||||
}
|
||||
|
||||
// method to load the dynamic library libjvm
|
||||
void loadJVM() {
|
||||
char lib[PATH_MAX];
|
||||
snprintf(lib, sizeof (lib), "%s/lib/sparcv9/server/libjvm.so", path);
|
||||
handle = dlopen(lib, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
handleError(dlerror(), "2");
|
||||
}
|
||||
fputs("Will load JVM...\n", stdout);
|
||||
|
||||
// find the address of function
|
||||
*(void **) (&jni_create_java_vm) = dlsym(handle, "JNI_CreateJavaVM");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
handleError(error, "3");
|
||||
}
|
||||
|
||||
fputs("JVM loaded okay.\n", stdout);
|
||||
}
|
||||
|
||||
// method to get created jvm environment
|
||||
JNIEnv* initJVM() {
|
||||
JNIEnv *env = NULL;
|
||||
JavaVMInitArgs vm_args;
|
||||
JavaVMOption options[1];
|
||||
jint res;
|
||||
|
||||
options[0].optionString = "-Xrs";
|
||||
|
||||
vm_args.version = JNI_VERSION_1_2;
|
||||
vm_args.nOptions = 1;
|
||||
vm_args.options = options;
|
||||
vm_args.ignoreUnrecognized = JNI_FALSE;
|
||||
|
||||
fputs("Will create JVM...\n", stdout);
|
||||
|
||||
res = (*jni_create_java_vm)(&jvm, &env, &vm_args);
|
||||
if (res < 0) {
|
||||
handleError("Can't create Java VM", strerror(res));
|
||||
}
|
||||
|
||||
fputs("JVM created OK!\n", stdout);
|
||||
return env;
|
||||
}
|
||||
|
||||
// method to invoke java method from java class
|
||||
void callJava(JNIEnv *env) {
|
||||
jclass cls;
|
||||
jmethodID mid;
|
||||
jstring jstr;
|
||||
jobjectArray args;
|
||||
|
||||
cls = (*env)->FindClass(env, "Prog");
|
||||
if (cls == 0) {
|
||||
handleError("FindClass", "Can't find Prog class");
|
||||
}
|
||||
|
||||
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
|
||||
if (mid == 0) {
|
||||
handleError("GetStaticMethodID", "Can't find Prog.main");
|
||||
}
|
||||
|
||||
jstr = (*env)->NewStringUTF(env, "from C!");
|
||||
if (jstr == 0) {
|
||||
handleError("NewStringUTF", "Out of memory");
|
||||
}
|
||||
args = (*env)->NewObjectArray(env, 1,
|
||||
(*env)->FindClass(env, "java/lang/String"), jstr);
|
||||
if (args == 0) {
|
||||
handleError("NewObjectArray", "Out of memory");
|
||||
}
|
||||
(*env)->CallStaticVoidMethod(env, cls, mid, args);
|
||||
|
||||
}
|
||||
|
||||
// method to load, init jvm and then invoke java method
|
||||
void* loadAndCallJava(void* x) {
|
||||
JNIEnv *env;
|
||||
|
||||
fputs("Some thread will create JVM.\n", stdout);
|
||||
loadJVM();
|
||||
env = initJVM();
|
||||
|
||||
fputs("Some thread will call Java.\n", stdout);
|
||||
|
||||
callJava(env);
|
||||
|
||||
if ((*jvm)->DetachCurrentThread(jvm) != 0)
|
||||
fputs("Error: thread not detached!\n", stderr);
|
||||
fputs("Some thread exiting.\n", stdout);
|
||||
return env;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
JNIEnv *env;
|
||||
sigset_t set;
|
||||
pthread_t thr1;
|
||||
pthread_attr_t attr;
|
||||
size_t ss = 0;
|
||||
int sig;
|
||||
int rc; // return code for pthread_* methods
|
||||
|
||||
// verify input
|
||||
if (argc != 2) {
|
||||
handleError("usage", "a.out jdk_path");
|
||||
}
|
||||
// copy input jdk path into a char buffer
|
||||
strncpy(path, argv[1], PATH_MAX);
|
||||
// add null termination character
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
|
||||
fputs("Main thread will set signal mask.\n", stdout);
|
||||
|
||||
// initialize the signal set
|
||||
sigemptyset(&set);
|
||||
// add a number of signals to a signal set
|
||||
sigaddset(&set, SIGPIPE);
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
sigaddset(&set, SIGINT);
|
||||
|
||||
// examine and change mask of blocked signal
|
||||
if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_sigmask() error", strerror(rc));
|
||||
}
|
||||
|
||||
// initializes the thread attributes object with default attribute values
|
||||
if ((rc = pthread_attr_init(&attr))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_attr_init() error", strerror(rc));
|
||||
}
|
||||
|
||||
ss = 1024 * 1024;
|
||||
// set the stack size attribute of the thread attributes object
|
||||
if ((rc = pthread_attr_setstacksize(&attr, ss))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_attr_setstacksize() error", strerror(rc));
|
||||
}
|
||||
// get the stack size attribute of the thread attributes object
|
||||
if ((rc = pthread_attr_getstacksize(&attr, &ss))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_attr_getstacksize() error", strerror(rc));
|
||||
}
|
||||
fprintf(stderr, "Stack size: %zu\n", ss);
|
||||
|
||||
// start a new thread in the calling process,
|
||||
// loadAndCallJava logic is passed as a start_routine argument
|
||||
if ((rc = pthread_create(&thr1, NULL, loadAndCallJava, NULL))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_create() error", strerror(rc));
|
||||
}
|
||||
|
||||
// initialize the signal set
|
||||
sigemptyset(&set);
|
||||
// add a number of signals to a signal set
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
sigaddset(&set, SIGINT);
|
||||
|
||||
fputs("Main thread waiting for signal.\n", stdout);
|
||||
|
||||
do {
|
||||
int err;
|
||||
|
||||
sig = 0;
|
||||
err = sigwait(&set, &sig);
|
||||
if (err != 0) {
|
||||
// print error message if unexpected signal occurred
|
||||
fprintf(stderr, "main: sigwait() error: %s\n", strerror(err));
|
||||
} else {
|
||||
// print success message and exit if expected signal occurred
|
||||
// this branch generally acts when JVM executes destroy()
|
||||
fprintf(stdout, "main: sigwait() got: %d\nSucceed!\n", sig);
|
||||
exit(0);
|
||||
}
|
||||
} while (sig != SIGTERM && sig != SIGINT); // exit the loop condition
|
||||
|
||||
// join with a terminated thread
|
||||
if ((rc = pthread_join(thr1, NULL))) {
|
||||
// handle error if occurred
|
||||
handleError("main: pthread_join() error", strerror(rc));
|
||||
}
|
||||
|
||||
// close an open dynamic library handle
|
||||
closeHandle();
|
||||
fputs("Main thread exiting.\n", stdout);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user