--- a/hotspot/make/test/JtregNative.gmk Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/make/test/JtregNative.gmk Mon Nov 23 14:38:20 2015 -0500
@@ -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/classfile/compactHashtable.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -137,7 +137,7 @@
if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
base_address = uintx(MetaspaceShared::shared_rs()->base());
max_delta = uintx(MetaspaceShared::shared_rs()->size());
- assert(max_delta <= 0x7fffffff, "range check");
+ assert(max_delta <= MAX_SHARED_DELTA, "range check");
} else {
assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
assert(UseCompressedOops, "UseCompressedOops is required");
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -499,11 +499,14 @@
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) {
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -372,7 +372,7 @@
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;
};
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -339,11 +339,18 @@
// 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 @@
// 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 @@
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));
@@ -1202,9 +1202,8 @@
heap_region_iterate(&cl);
}
-bool G1CollectedHeap::do_collection(bool explicit_gc,
- bool clear_all_soft_refs,
- size_t word_size) {
+bool G1CollectedHeap::do_full_collection(bool explicit_gc,
+ bool clear_all_soft_refs) {
assert_at_safepoint(true /* should_be_vm_thread */);
if (GC_locker::check_active_before_gc()) {
@@ -1362,8 +1361,7 @@
clear_rsets_post_compaction();
check_gc_time_stamps();
- // Resize the heap if necessary.
- resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size);
+ resize_if_necessary_after_full_collection();
if (_hr_printer.is_active()) {
// We should do this after we potentially resize the heap so
@@ -1471,22 +1469,15 @@
}
void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) {
- // do_collection() will return whether it succeeded in performing
- // the GC. Currently, there is no facility on the
- // do_full_collection() API to notify the caller than the collection
- // did not succeed (e.g., because it was locked out by the GC
- // locker). So, right now, we'll ignore the return value.
- bool dummy = do_collection(true, /* explicit_gc */
- clear_all_soft_refs,
- 0 /* word_size */);
-}
-
-// This code is mostly copied from TenuredGeneration.
-void
-G1CollectedHeap::
-resize_if_necessary_after_full_collection(size_t word_size) {
- // Include the current allocation, if any, and bytes that will be
- // pre-allocated to support collections, as "used".
+ // Currently, there is no facility in the do_full_collection(bool) API to notify
+ // the caller that the collection did not succeed (e.g., because it was locked
+ // out by the GC locker). So, right now, we'll ignore the return value.
+ bool dummy = do_full_collection(true, /* explicit_gc */
+ clear_all_soft_refs);
+}
+
+void G1CollectedHeap::resize_if_necessary_after_full_collection() {
+ // Include bytes that will be pre-allocated to support collections, as "used".
const size_t used_after_gc = used();
const size_t capacity_after_gc = capacity();
const size_t free_after_gc = capacity_after_gc - used_after_gc;
@@ -1598,9 +1589,8 @@
if (do_gc) {
// Expansion didn't work, we'll try to do a Full GC.
- *gc_succeeded = do_collection(false, /* explicit_gc */
- clear_all_soft_refs,
- word_size);
+ *gc_succeeded = do_full_collection(false, /* explicit_gc */
+ clear_all_soft_refs);
}
return NULL;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -471,26 +471,20 @@
void retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes, InCSetState dest);
- // - if explicit_gc is true, the GC is for a System.gc() or a heap
- // inspection request and should collect the entire heap
+ // - if explicit_gc is true, the GC is for a System.gc() etc,
+ // otherwise it's for a failed allocation.
// - if clear_all_soft_refs is true, all soft references should be
- // cleared during the GC
- // - if explicit_gc is false, word_size describes the allocation that
- // the GC should attempt (at least) to satisfy
+ // cleared during the GC.
// - it returns false if it is unable to do the collection due to the
- // GC locker being active, true otherwise
- bool do_collection(bool explicit_gc,
- bool clear_all_soft_refs,
- size_t word_size);
+ // GC locker being active, true otherwise.
+ bool do_full_collection(bool explicit_gc,
+ bool clear_all_soft_refs);
- // Callback from VM_G1CollectFull operation.
- // Perform a full collection.
+ // Callback from VM_G1CollectFull operation, or collect_as_vm_thread.
virtual void do_full_collection(bool clear_all_soft_refs);
- // Resize the heap if necessary after a full collection. If this is
- // after a collect-for allocation, "word_size" is the allocation size,
- // and will be considered part of the used portion of the heap.
- void resize_if_necessary_after_full_collection(size_t word_size);
+ // Resize the heap if necessary after a full collection.
+ void resize_if_necessary_after_full_collection();
// Callback from VM_G1CollectForAllocation operation.
// This function does everything necessary/possible to satisfy a
@@ -1150,9 +1144,6 @@
// "CollectedHeap" supports.
virtual void collect(GCCause::Cause cause);
- // The same as above but assume that the caller holds the Heap_lock.
- void collect_locked(GCCause::Cause cause);
-
virtual bool copy_allocation_context_stats(const jint* contexts,
jlong* totals,
jbyte* accuracy,
@@ -1352,14 +1343,6 @@
return (region_size / 2);
}
- // Update mod union table with the set of dirty cards.
- void updateModUnion();
-
- // Set the mod union bits corresponding to the given memRegion. Note
- // that this is always a safe operation, since it doesn't clear any
- // bits.
- void markModUnionRange(MemRegion mr);
-
// Print the maximum heap capacity.
virtual size_t max_capacity() const;
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -123,16 +123,13 @@
template <G1Barrier barrier, G1Mark do_mark_object>
class G1ParCopyClosure : public G1ParCopyHelper {
-private:
- template <class T> void do_oop_work(T* p);
-
public:
G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
G1ParCopyHelper(g1, par_scan_state) {
assert(ref_processor() == NULL, "sanity");
}
- template <class T> void do_oop_nv(T* p) { do_oop_work(p); }
+ template <class T> void do_oop_nv(T* p);
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -251,7 +251,7 @@
template <G1Barrier barrier, G1Mark do_mark_object>
template <class T>
-void G1ParCopyClosure<barrier, do_mark_object>::do_oop_work(T* p) {
+void G1ParCopyClosure<barrier, do_mark_object>::do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (oopDesc::is_null(heap_oop)) {
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -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 Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -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;
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -211,14 +211,14 @@
_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 @@
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 @@
}
}
- 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);
}
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -455,9 +455,9 @@
// 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
--- a/hotspot/src/share/vm/logging/log.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/logging/log.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -37,10 +37,10 @@
// 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-"
--- a/hotspot/src/share/vm/logging/log.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/logging/log.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -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 @@
// 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);
}
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -44,6 +44,7 @@
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);
--- a/hotspot/src/share/vm/logging/logLevel.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/logging/logLevel.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -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) \
--- a/hotspot/src/share/vm/memory/metaspace.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -3230,36 +3230,6 @@
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment);
- // make sure SharedReadOnlySize and SharedReadWriteSize are not less than
- // the minimum values.
- if (SharedReadOnlySize < MetaspaceShared::min_ro_size){
- report_out_of_shared_space(SharedReadOnly);
- }
-
- if (SharedReadWriteSize < MetaspaceShared::min_rw_size){
- report_out_of_shared_space(SharedReadWrite);
- }
-
- // the min_misc_data_size and min_misc_code_size estimates are based on
- // MetaspaceShared::generate_vtable_methods().
- // The minimum size only accounts for the vtable methods. Any size less than the
- // minimum required size would cause vm crash when allocating the vtable methods.
- uint min_misc_data_size = align_size_up(
- MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
-
- if (SharedMiscDataSize < min_misc_data_size) {
- report_out_of_shared_space(SharedMiscData);
- }
-
- uintx min_misc_code_size = align_size_up(
- (MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) *
- (sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size,
- max_alignment);
-
- if (SharedMiscCodeSize < min_misc_code_size) {
- report_out_of_shared_space(SharedMiscCode);
- }
-
// Initialize with the sum of the shared space sizes. The read-only
// and read write metaspace chunks will be allocated out of this and the
// remainder is the misc code and data chunks.
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -32,14 +32,55 @@
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
-#define LargeSharedArchiveSize (300*M)
-#define HugeSharedArchiveSize (800*M)
-#define ReadOnlyRegionPercentage 0.4
-#define ReadWriteRegionPercentage 0.55
-#define MiscDataRegionPercentage 0.03
-#define MiscCodeRegionPercentage 0.02
-#define LargeThresholdClassCount 5000
-#define HugeThresholdClassCount 40000
+#define DEFAULT_VTBL_LIST_SIZE (17) // number of entries in the shared space vtable list.
+#define DEFAULT_VTBL_VIRTUALS_COUNT (200) // maximum number of virtual functions
+// If virtual functions are added to Metadata,
+// this number needs to be increased. Also,
+// SharedMiscCodeSize will need to be increased.
+// The following 2 sizes were based on
+// MetaspaceShared::generate_vtable_methods()
+#define DEFAULT_VTBL_METHOD_SIZE (16) // conservative size of the mov1 and jmp instructions
+// for the x64 platform
+#define DEFAULT_VTBL_COMMON_CODE_SIZE (1*K) // conservative size of the "common_code" for the x64 platform
+
+#define DEFAULT_SHARED_READ_WRITE_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M))
+#define MIN_SHARED_READ_WRITE_SIZE (NOT_LP64(7*M) LP64_ONLY(12*M))
+
+#define DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M))
+#define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(9*M))
+
+// the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on
+// MetaspaceShared::generate_vtable_methods().
+// The minimum size only accounts for the vtable methods. Any size less than the
+// minimum required size would cause vm crash when allocating the vtable methods.
+#define SHARED_MISC_SIZE_FOR(size) (DEFAULT_VTBL_VIRTUALS_COUNT*DEFAULT_VTBL_LIST_SIZE*size)
+
+#define DEFAULT_SHARED_MISC_DATA_SIZE (NOT_LP64(2*M) LP64_ONLY(4*M))
+#define MIN_SHARED_MISC_DATA_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*)))
+
+#define DEFAULT_SHARED_MISC_CODE_SIZE (120*K)
+#define MIN_SHARED_MISC_CODE_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))+SHARED_MISC_SIZE_FOR(DEFAULT_VTBL_METHOD_SIZE)+DEFAULT_VTBL_COMMON_CODE_SIZE)
+
+#define DEFAULT_COMBINED_SIZE (DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)
+
+// the max size is the MAX size (ie. 0x7FFFFFFF) - the total size of
+// the other 3 sections - page size (to avoid overflow in case the final
+// size will get aligned up on page size)
+#define SHARED_PAGE ((size_t)os::vm_page_size())
+#define MAX_SHARED_DELTA (0x7FFFFFFF)
+#define MAX_SHARED_READ_WRITE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_READ_ONLY_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_MISC_DATA_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_MISC_CODE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE)-SHARED_PAGE)
+
+#define LargeSharedArchiveSize (300*M)
+#define HugeSharedArchiveSize (800*M)
+#define ReadOnlyRegionPercentage 0.4
+#define ReadWriteRegionPercentage 0.55
+#define MiscDataRegionPercentage 0.03
+#define MiscCodeRegionPercentage 0.02
+#define LargeThresholdClassCount 5000
+#define HugeThresholdClassCount 40000
#define SET_ESTIMATED_SIZE(type, region) \
Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
@@ -69,21 +110,10 @@
static bool _archive_loading_failed;
public:
enum {
- vtbl_list_size = 17, // number of entries in the shared space vtable list.
- num_virtuals = 200, // maximum number of virtual functions
- // If virtual functions are added to Metadata,
- // this number needs to be increased. Also,
- // SharedMiscCodeSize will need to be increased.
- // The following 2 sizes were based on
- // MetaspaceShared::generate_vtable_methods()
- vtbl_method_size = 16, // conservative size of the mov1 and jmp instructions
- // for the x64 platform
- vtbl_common_code_size = (1*K) // conservative size of the "common_code" for the x64 platform
- };
-
- enum {
- min_ro_size = NOT_LP64(8*M) LP64_ONLY(9*M), // minimum ro and rw regions sizes based on dumping
- min_rw_size = NOT_LP64(7*M) LP64_ONLY(12*M) // of a shared archive using the default classlist
+ vtbl_list_size = DEFAULT_VTBL_LIST_SIZE,
+ num_virtuals = DEFAULT_VTBL_VIRTUALS_COUNT,
+ vtbl_method_size = DEFAULT_VTBL_METHOD_SIZE,
+ vtbl_common_code_size = DEFAULT_VTBL_COMMON_CODE_SIZE
};
enum {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -223,7 +223,7 @@
#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type
// the "name" argument must be a string literal
-#define INITIAL_CONSTRAINTS_SIZE 45
+#define INITIAL_CONSTRAINTS_SIZE 69
GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Mon Nov 23 14:38:20 2015 -0500
@@ -279,7 +279,7 @@
// Generate func argument to pass into emit_range_xxx functions
#define EMIT_RANGE_CHECK(a, b) , a, b
-#define INITIAL_RANGES_SIZE 205
+#define INITIAL_RANGES_SIZE 320
GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
// Check the ranges of all flags that have them
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
+#include "memory/metaspaceShared.hpp"
#include "runtime/globals.hpp"
#include "utilities/growableArray.hpp"
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/src/share/vm/runtime/globals.hpp Mon Nov 23 14:38:20 2015 -0500
@@ -4110,21 +4110,26 @@
"If PrintSharedArchiveAndExit is true, also print the shared " \
"dictionary") \
\
- product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \
+ product(size_t, SharedReadWriteSize, DEFAULT_SHARED_READ_WRITE_SIZE, \
"Size of read-write space for metadata (in bytes)") \
- \
- product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \
+ range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE) \
+ \
+ product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE, \
"Size of read-only space for metadata (in bytes)") \
- \
- product(uintx, SharedMiscDataSize, NOT_LP64(2*M) LP64_ONLY(4*M), \
+ range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE) \
+ \
+ product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE, \
"Size of the shared miscellaneous data area (in bytes)") \
- \
- product(uintx, SharedMiscCodeSize, 120*K, \
+ range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE) \
+ \
+ product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE, \
"Size of the shared miscellaneous code area (in bytes)") \
- \
- product(uintx, SharedBaseAddress, LP64_ONLY(32*G) \
+ range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE) \
+ \
+ product(size_t, SharedBaseAddress, LP64_ONLY(32*G) \
NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \
"Address to allocate shared memory region for class data") \
+ range(0, SIZE_MAX) \
\
product(uintx, SharedSymbolTableBucketSize, 4, \
"Average number of symbols per bucket in shared table") \
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Mon Nov 23 14:38:20 2015 -0500
@@ -55,10 +55,29 @@
* JDK-8136766
* Temporarily remove ThreadStackSize from testing because Windows can set it to 0
* (for default OS size) but other platforms insist it must be greater than 0
- */
+ */
allOptionsAsMap.remove("ThreadStackSize");
/*
+ * JDK-8141650
+ * Temporarily exclude SharedMiscDataSize as it will exit the VM with exit code 2 and
+ * "The shared miscellaneous data space is not large enough to preload requested classes."
+ * message at min value.
+ */
+ allOptionsAsMap.remove("SharedMiscDataSize");
+
+ /*
+ * JDK-8142874
+ * Temporarily exclude Shared* flagse as they will exit the VM with exit code 2 and
+ * "The shared miscellaneous data space is not large enough to preload requested classes."
+ * message at max values.
+ */
+ allOptionsAsMap.remove("SharedReadWriteSize");
+ allOptionsAsMap.remove("SharedReadOnlySize");
+ allOptionsAsMap.remove("SharedMiscDataSize");
+ allOptionsAsMap.remove("SharedMiscCodeSize");
+
+ /*
* Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0)
*/
allOptionsAsMap.remove("MallocMaxTestWords");
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java Mon Nov 23 14:38:20 2015 -0500
@@ -223,7 +223,7 @@
validValues.add("1");
}
- if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) {
+ if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) {
/*
* Check for overflow when flag is assigned to the
* 4 byte int variable
@@ -231,7 +231,7 @@
validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
}
- if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) {
+ if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) {
/*
* Check for overflow when flag is assigned to the
* 4 byte unsigned int variable
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Mon Nov 23 14:38:20 2015 -0500
@@ -27,6 +27,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -49,6 +50,8 @@
/* Used to start the JVM with the same type as current */
static String VMType;
+ private static Map<String, JVMOption> optionsAsMap;
+
static {
if (Platform.isServer()) {
VMType = "-server";
@@ -63,6 +66,84 @@
}
}
+ public static boolean fitsRange(String optionName, BigDecimal number) throws Exception {
+ JVMOption option;
+ String minRangeString = null;
+ String maxRangeString = null;
+ boolean fits = true;
+
+ if (optionsAsMap == null) {
+ optionsAsMap = getOptionsWithRangeAsMap();
+ }
+
+ option = optionsAsMap.get(optionName);
+ if (option != null) {
+ minRangeString = option.getMin();
+ if (minRangeString != null) {
+ fits = (number.compareTo(new BigDecimal(minRangeString)) >= 0);
+ }
+ maxRangeString = option.getMax();
+ if (maxRangeString != null) {
+ fits &= (number.compareTo(new BigDecimal(maxRangeString)) <= 0);
+ }
+ }
+
+ return fits;
+ }
+
+ public static boolean fitsRange(String optionName, String number) throws Exception {
+ String lowerCase = number.toLowerCase();
+ String multiplier = "1";
+ if (lowerCase.endsWith("k")) {
+ multiplier = "1024";
+ lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+ } else if (lowerCase.endsWith("m")) {
+ multiplier = "1048576"; //1024*1024
+ lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+ } else if (lowerCase.endsWith("g")) {
+ multiplier = "1073741824"; //1024*1024*1024
+ lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+ } else if (lowerCase.endsWith("t")) {
+ multiplier = "1099511627776"; //1024*1024*1024*1024
+ lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+ }
+ BigDecimal valueBig = new BigDecimal(lowerCase);
+ BigDecimal multiplierBig = new BigDecimal(multiplier);
+ return fitsRange(optionName, valueBig.multiply(multiplierBig));
+ }
+
+ public static String getMinOptionRange(String optionName) throws Exception {
+ JVMOption option;
+ String minRange = null;
+
+ if (optionsAsMap == null) {
+ optionsAsMap = getOptionsWithRangeAsMap();
+ }
+
+ option = optionsAsMap.get(optionName);
+ if (option != null) {
+ minRange = option.getMin();
+ }
+
+ return minRange;
+ }
+
+ public static String getMaxOptionRange(String optionName) throws Exception {
+ JVMOption option;
+ String maxRange = null;
+
+ if (optionsAsMap == null) {
+ optionsAsMap = getOptionsWithRangeAsMap();
+ }
+
+ option = optionsAsMap.get(optionName);
+ if (option != null) {
+ maxRange = option.getMax();
+ }
+
+ return maxRange;
+ }
+
/**
* Add dependency for option depending on it's name. E.g. enable G1 GC for
* G1 options or add prepend options to not hit constraints.
@@ -80,6 +161,13 @@
option.addPrepend("-XX:+UseConcMarkSweepGC");
}
+ if (name.startsWith("Shared")) {
+ option.addPrepend("-XX:+UnlockDiagnosticVMOptions");
+ String fileName = "Test" + name + ".jsa";
+ option.addPrepend("-XX:SharedArchiveFile=" + fileName);
+ option.addPrepend("-Xshare:dump");
+ }
+
switch (name) {
case "MinHeapFreeRatio":
option.addPrepend("-XX:MaxHeapFreeRatio=100");
@@ -112,7 +200,6 @@
/* Do nothing */
break;
}
-
}
/**
--- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Thu Nov 19 19:26:51 2015 -0500
+++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Mon Nov 23 14:38:20 2015 -0500
@@ -23,50 +23,72 @@
/* @test LimitSharedSizes
* @summary Test handling of limits on shared space size
- * @library /testlibrary
+ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common
* @modules java.base/sun.misc
* java.management
* @run main LimitSharedSizes
*/
import jdk.test.lib.*;
+import optionsvalidation.JVMOptionsUtils;
public class LimitSharedSizes {
+ static enum Result {
+ OUT_OF_RANGE,
+ TOO_SMALL,
+ VALID,
+ VALID_ARCHIVE
+ }
+
static enum Region {
RO, RW, MD, MC
}
+ private static final boolean fitsRange(String name, String value) throws RuntimeException {
+ boolean fits = true;
+ try {
+ fits = JVMOptionsUtils.fitsRange(name, value);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ return fits;
+ }
+
private static class SharedSizeTestData {
public String optionName;
public String optionValue;
- public String expectedErrorMsg;
+ public Result optionResult;
- public SharedSizeTestData(Region region, String value, String msg) {
- optionName = getName(region);
+ public SharedSizeTestData(Region region, String value) {
+ optionName = "-XX:"+getName(region);
optionValue = value;
- expectedErrorMsg = msg;
+ if (fitsRange(getName(region), value) == false) {
+ optionResult = Result.OUT_OF_RANGE;
+ } else {
+ optionResult = Result.TOO_SMALL;
+ }
}
- public SharedSizeTestData(Region region, String msg) {
- optionName = getName(region);
- optionValue = getValue(region);
- expectedErrorMsg = msg;
+ public SharedSizeTestData(Region region, String value, Result result) {
+ optionName = "-XX:"+getName(region);
+ optionValue = value;
+ optionResult = result;
}
private String getName(Region region) {
String name;
switch (region) {
case RO:
- name = "-XX:SharedReadOnlySize";
+ name = "SharedReadOnlySize";
break;
case RW:
- name = "-XX:SharedReadWriteSize";
+ name = "SharedReadWriteSize";
break;
case MD:
- name = "-XX:SharedMiscDataSize";
+ name = "SharedMiscDataSize";
break;
case MC:
- name = "-XX:SharedMiscCodeSize";
+ name = "SharedMiscCodeSize";
break;
default:
name = "Unknown";
@@ -75,53 +97,37 @@
return name;
}
- private String getValue(Region region) {
- String value;
- switch (region) {
- case RO:
- value = Platform.is64bit() ? "9M" : "8M";
- break;
- case RW:
- value = Platform.is64bit() ? "12M" : "7M";
- break;
- case MD:
- value = Platform.is64bit() ? "4M" : "2M";
- break;
- case MC:
- value = "120k";
- break;
- default:
- value = "0M";
- break;
- }
- return value;
+ public Result getResult() {
+ return optionResult;
}
}
private static final SharedSizeTestData[] testTable = {
// Too small of a region size should not cause a vm crash.
- // It should result in an error message like the following:
+ // It should result in an error message either like the following #1:
// The shared miscellaneous code space is not large enough
// to preload requested classes. Use -XX:SharedMiscCodeSize=
// to increase the initial size of shared miscellaneous code space.
- new SharedSizeTestData(Region.RO, "4M", "read only"),
- new SharedSizeTestData(Region.RW, "4M", "read write"),
- new SharedSizeTestData(Region.MD, "50k", "miscellaneous data"),
- new SharedSizeTestData(Region.MC, "20k", "miscellaneous code"),
+ // or #2:
+ // The shared miscellaneous code space is outside the allowed range
+ new SharedSizeTestData(Region.RO, "4M"),
+ new SharedSizeTestData(Region.RW, "4M"),
+ new SharedSizeTestData(Region.MD, "50k"),
+ new SharedSizeTestData(Region.MC, "20k"),
- // these values are larger than default ones, but should
+ // these values are larger than default ones, and should
// be acceptable and not cause failure
- new SharedSizeTestData(Region.RO, "20M", null),
- new SharedSizeTestData(Region.RW, "20M", null),
- new SharedSizeTestData(Region.MD, "20M", null),
- new SharedSizeTestData(Region.MC, "20M", null),
+ new SharedSizeTestData(Region.RO, "20M", Result.VALID),
+ new SharedSizeTestData(Region.RW, "20M", Result.VALID),
+ new SharedSizeTestData(Region.MD, "20M", Result.VALID),
+ new SharedSizeTestData(Region.MC, "20M", Result.VALID),
// test with sizes which just meet the minimum required sizes
// the following tests also attempt to use the shared archive
- new SharedSizeTestData(Region.RO, "UseArchive"),
- new SharedSizeTestData(Region.RW, "UseArchive"),
- new SharedSizeTestData(Region.MD, "UseArchive"),
- new SharedSizeTestData(Region.MC, "UseArchive")
+ new SharedSizeTestData(Region.RO, Platform.is64bit() ? "9M":"8M", Result.VALID_ARCHIVE),
+ new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
+ new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
+ new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
};
public static void main(String[] args) throws Exception {
@@ -131,6 +137,7 @@
counter++;
String option = td.optionName + "=" + td.optionValue;
+ System.out.println("testing option number <" + counter + ">");
System.out.println("testing option <" + option + ">");
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
@@ -141,43 +148,52 @@
OutputAnalyzer output = new OutputAnalyzer(pb.start());
- if (td.expectedErrorMsg != null) {
- if (!td.expectedErrorMsg.equals("UseArchive")) {
- output.shouldContain("The shared " + td.expectedErrorMsg
- + " space is not large enough");
+ switch (td.getResult()) {
+ case VALID:
+ case VALID_ARCHIVE:
+ {
+ output.shouldNotContain("space is not large enough");
+ output.shouldHaveExitValue(0);
- output.shouldHaveExitValue(2);
- } else {
- output.shouldNotContain("space is not large enough");
- output.shouldHaveExitValue(0);
-
- // try to use the archive
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+UnlockDiagnosticVMOptions",
- "-XX:SharedArchiveFile=./" + fileName,
- "-XX:+PrintSharedArchiveAndExit",
- "-version");
+ if (td.getResult() == Result.VALID_ARCHIVE) {
+ // try to use the archive
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=./" + fileName,
+ "-XX:+PrintSharedArchiveAndExit",
+ "-version");
- try {
- output = new OutputAnalyzer(pb.start());
- output.shouldContain("archive is valid");
- } catch (RuntimeException e) {
- // if sharing failed due to ASLR or similar reasons,
- // check whether sharing was attempted at all (UseSharedSpaces)
- if ((output.getOutput().contains("Unable to use shared archive") ||
- output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
- output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
- output.getOutput().contains("Unable to reserve shared space at required address")) &&
- output.getExitValue() == 1) {
- System.out.println("Unable to use shared archive: test not executed; assumed passed");
- return;
- }
- }
- output.shouldHaveExitValue(0);
+ try {
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is valid");
+ } catch (RuntimeException e) {
+ // if sharing failed due to ASLR or similar reasons,
+ // check whether sharing was attempted at all (UseSharedSpaces)
+ if ((output.getOutput().contains("Unable to use shared archive") ||
+ output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
+ output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
+ output.getOutput().contains("Unable to reserve shared space at required address")) &&
+ output.getExitValue() == 1) {
+ System.out.println("Unable to use shared archive: test not executed; assumed passed");
+ return;
+ }
+ }
+ output.shouldHaveExitValue(0);
+ }
}
- } else {
- output.shouldNotContain("space is not large enough");
- output.shouldHaveExitValue(0);
+ break;
+ case TOO_SMALL:
+ {
+ output.shouldContain("space is not large enough");
+ output.shouldHaveExitValue(2);
+ }
+ break;
+ case OUT_OF_RANGE:
+ {
+ output.shouldContain("outside the allowed range");
+ output.shouldHaveExitValue(1);
+ }
+ break;
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ThreadSignalMask/Prog.java Mon Nov 23 14:38:20 2015 -0500
@@ -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 Mon Nov 23 14:38:20 2015 -0500
@@ -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 Mon Nov 23 14:38:20 2015 -0500
@@ -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;
+}