--- a/hotspot/make/test/JtregNative.gmk Fri Nov 20 17:32:02 2015 +0100
+++ b/hotspot/make/test/JtregNative.gmk Fri Nov 20 19:17:57 2015 +0000
@@ -51,7 +51,8 @@
# 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)
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Fri Nov 20 17:32:02 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Fri Nov 20 19:17:57 2015 +0000
@@ -73,138 +73,111 @@
FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl);
}
-class ScanRSClosure : public HeapRegionClosure {
- size_t _cards_done, _cards;
- G1CollectedHeap* _g1h;
-
- G1ParPushHeapRSClosure* _oc;
- CodeBlobClosure* _code_root_cl;
-
- G1BlockOffsetSharedArray* _bot_shared;
- G1SATBCardTableModRefBS *_ct_bs;
-
- double _strong_code_root_scan_time_sec;
- uint _worker_i;
- size_t _block_size;
- bool _try_claimed;
-
-public:
- ScanRSClosure(G1ParPushHeapRSClosure* oc,
- CodeBlobClosure* code_root_cl,
- uint worker_i) :
+ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc,
+ CodeBlobClosure* code_root_cl,
+ uint worker_i) :
_oc(oc),
_code_root_cl(code_root_cl),
_strong_code_root_scan_time_sec(0.0),
_cards(0),
_cards_done(0),
_worker_i(worker_i),
- _try_claimed(false)
- {
- _g1h = G1CollectedHeap::heap();
- _bot_shared = _g1h->bot_shared();
- _ct_bs = _g1h->g1_barrier_set();
- _block_size = MAX2<size_t>(G1RSetScanBlockSize, 1);
+ _try_claimed(false) {
+ _g1h = G1CollectedHeap::heap();
+ _bot_shared = _g1h->bot_shared();
+ _ct_bs = _g1h->g1_barrier_set();
+ _block_size = MAX2<size_t>(G1RSetScanBlockSize, 1);
+}
+
+void ScanRSClosure::scanCard(size_t index, HeapRegion *r) {
+ // Stack allocate the DirtyCardToOopClosure instance
+ HeapRegionDCTOC cl(_g1h, r, _oc,
+ CardTableModRefBS::Precise);
+
+ // Set the "from" region in the closure.
+ _oc->set_region(r);
+ MemRegion card_region(_bot_shared->address_for_index(index), G1BlockOffsetSharedArray::N_words);
+ MemRegion pre_gc_allocated(r->bottom(), r->scan_top());
+ MemRegion mr = pre_gc_allocated.intersection(card_region);
+ if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) {
+ // We make the card as "claimed" lazily (so races are possible
+ // but they're benign), which reduces the number of duplicate
+ // scans (the rsets of the regions in the cset can intersect).
+ _ct_bs->set_card_claimed(index);
+ _cards_done++;
+ cl.do_MemRegion(mr);
}
+}
- void set_try_claimed() { _try_claimed = true; }
+void ScanRSClosure::printCard(HeapRegion* card_region, size_t card_index,
+ HeapWord* card_start) {
+ gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") "
+ "RS names card " SIZE_FORMAT_HEX ": "
+ "[" PTR_FORMAT ", " PTR_FORMAT ")",
+ _worker_i,
+ p2i(card_region->bottom()), p2i(card_region->end()),
+ card_index,
+ p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words));
+}
- void scanCard(size_t index, HeapRegion *r) {
- // Stack allocate the DirtyCardToOopClosure instance
- HeapRegionDCTOC cl(_g1h, r, _oc,
- CardTableModRefBS::Precise);
+void ScanRSClosure::scan_strong_code_roots(HeapRegion* r) {
+ double scan_start = os::elapsedTime();
+ r->strong_code_roots_do(_code_root_cl);
+ _strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start);
+}
+
+bool ScanRSClosure::doHeapRegion(HeapRegion* r) {
+ assert(r->in_collection_set(), "should only be called on elements of CS.");
+ HeapRegionRemSet* hrrs = r->rem_set();
+ if (hrrs->iter_is_complete()) return false; // All done.
+ if (!_try_claimed && !hrrs->claim_iter()) return false;
+ // If we ever free the collection set concurrently, we should also
+ // clear the card table concurrently therefore we won't need to
+ // add regions of the collection set to the dirty cards region.
+ _g1h->push_dirty_cards_region(r);
+ // If we didn't return above, then
+ // _try_claimed || r->claim_iter()
+ // is true: either we're supposed to work on claimed-but-not-complete
+ // regions, or we successfully claimed the region.
+
+ HeapRegionRemSetIterator iter(hrrs);
+ size_t card_index;
- // Set the "from" region in the closure.
- _oc->set_region(r);
- MemRegion card_region(_bot_shared->address_for_index(index), G1BlockOffsetSharedArray::N_words);
- MemRegion pre_gc_allocated(r->bottom(), r->scan_top());
- MemRegion mr = pre_gc_allocated.intersection(card_region);
- if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) {
- // We make the card as "claimed" lazily (so races are possible
- // but they're benign), which reduces the number of duplicate
- // scans (the rsets of the regions in the cset can intersect).
- _ct_bs->set_card_claimed(index);
- _cards_done++;
- cl.do_MemRegion(mr);
+ // We claim cards in block so as to reduce the contention. The block size is determined by
+ // the G1RSetScanBlockSize parameter.
+ size_t jump_to_card = hrrs->iter_claimed_next(_block_size);
+ for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
+ if (current_card >= jump_to_card + _block_size) {
+ jump_to_card = hrrs->iter_claimed_next(_block_size);
+ }
+ if (current_card < jump_to_card) continue;
+ HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index);
+#if 0
+ gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n",
+ card_start, card_start + CardTableModRefBS::card_size_in_words);
+#endif
+
+ HeapRegion* card_region = _g1h->heap_region_containing(card_start);
+ _cards++;
+
+ if (!card_region->is_on_dirty_cards_region_list()) {
+ _g1h->push_dirty_cards_region(card_region);
+ }
+
+ // If the card is dirty, then we will scan it during updateRS.
+ if (!card_region->in_collection_set() &&
+ !_ct_bs->is_card_dirty(card_index)) {
+ scanCard(card_index, card_region);
}
}
-
- void printCard(HeapRegion* card_region, size_t card_index,
- HeapWord* card_start) {
- gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") "
- "RS names card " SIZE_FORMAT_HEX ": "
- "[" PTR_FORMAT ", " PTR_FORMAT ")",
- _worker_i,
- p2i(card_region->bottom()), p2i(card_region->end()),
- card_index,
- p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words));
- }
-
- void scan_strong_code_roots(HeapRegion* r) {
- double scan_start = os::elapsedTime();
- r->strong_code_roots_do(_code_root_cl);
- _strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start);
- }
-
- bool doHeapRegion(HeapRegion* r) {
- assert(r->in_collection_set(), "should only be called on elements of CS.");
- HeapRegionRemSet* hrrs = r->rem_set();
- if (hrrs->iter_is_complete()) return false; // All done.
- if (!_try_claimed && !hrrs->claim_iter()) return false;
- // If we ever free the collection set concurrently, we should also
- // clear the card table concurrently therefore we won't need to
- // add regions of the collection set to the dirty cards region.
- _g1h->push_dirty_cards_region(r);
- // If we didn't return above, then
- // _try_claimed || r->claim_iter()
- // is true: either we're supposed to work on claimed-but-not-complete
- // regions, or we successfully claimed the region.
-
- HeapRegionRemSetIterator iter(hrrs);
- size_t card_index;
+ if (!_try_claimed) {
+ // Scan the strong code root list attached to the current region
+ scan_strong_code_roots(r);
- // We claim cards in block so as to reduce the contention. The block size is determined by
- // the G1RSetScanBlockSize parameter.
- size_t jump_to_card = hrrs->iter_claimed_next(_block_size);
- for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
- if (current_card >= jump_to_card + _block_size) {
- jump_to_card = hrrs->iter_claimed_next(_block_size);
- }
- if (current_card < jump_to_card) continue;
- HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index);
-#if 0
- gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n",
- card_start, card_start + CardTableModRefBS::card_size_in_words);
-#endif
-
- HeapRegion* card_region = _g1h->heap_region_containing(card_start);
- _cards++;
-
- if (!card_region->is_on_dirty_cards_region_list()) {
- _g1h->push_dirty_cards_region(card_region);
- }
-
- // If the card is dirty, then we will scan it during updateRS.
- if (!card_region->in_collection_set() &&
- !_ct_bs->is_card_dirty(card_index)) {
- scanCard(card_index, card_region);
- }
- }
- if (!_try_claimed) {
- // Scan the strong code root list attached to the current region
- scan_strong_code_roots(r);
-
- hrrs->set_iter_complete();
- }
- return false;
+ hrrs->set_iter_complete();
}
-
- double strong_code_root_scan_time_sec() {
- return _strong_code_root_scan_time_sec;
- }
-
- size_t cards_done() { return _cards_done;}
- size_t cards_looked_up() { return _cards;}
-};
+ return false;
+}
size_t G1RemSet::scanRS(G1ParPushHeapRSClosure* oc,
CodeBlobClosure* heap_region_codeblobs,
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp Fri Nov 20 17:32:02 2015 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp Fri Nov 20 19:17:57 2015 +0000
@@ -156,6 +156,41 @@
}
};
+class ScanRSClosure : public HeapRegionClosure {
+ size_t _cards_done, _cards;
+ G1CollectedHeap* _g1h;
+
+ G1ParPushHeapRSClosure* _oc;
+ CodeBlobClosure* _code_root_cl;
+
+ G1BlockOffsetSharedArray* _bot_shared;
+ G1SATBCardTableModRefBS *_ct_bs;
+
+ double _strong_code_root_scan_time_sec;
+ uint _worker_i;
+ size_t _block_size;
+ bool _try_claimed;
+
+public:
+ ScanRSClosure(G1ParPushHeapRSClosure* oc,
+ CodeBlobClosure* code_root_cl,
+ uint worker_i);
+
+ bool doHeapRegion(HeapRegion* r);
+
+ double strong_code_root_scan_time_sec() {
+ return _strong_code_root_scan_time_sec;
+ }
+ size_t cards_done() { return _cards_done;}
+ size_t cards_looked_up() { return _cards;}
+ void set_try_claimed() { _try_claimed = true; }
+private:
+ void scanCard(size_t index, HeapRegion *r);
+ void printCard(HeapRegion* card_region, size_t card_index,
+ HeapWord* card_start);
+ void scan_strong_code_roots(HeapRegion* r);
+};
+
class UpdateRSOopClosure: public ExtendedOopClosure {
HeapRegion* _from;
G1RemSet* _rs;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ThreadSignalMask/Prog.java Fri Nov 20 19:17:57 2015 +0000
@@ -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]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java Fri Nov 20 19:17:57 2015 +0000
@@ -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;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c Fri Nov 20 19:17:57 2015 +0000
@@ -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;
+}