OpenJDK / valhalla / valhalla
changeset 55554:1ed25a6f90db lworld
Merge to last conflict
author | dsimms |
---|---|
date | Thu, 23 May 2019 14:13:01 +0200 |
parents | 711cb57fdbc8 845f5a35241b |
children | 6ebaf606e2a9 |
files | src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp src/hotspot/cpu/x86/stubGenerator_x86_64.cpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/oops/cpCache.cpp src/hotspot/share/oops/cpCache.hpp src/hotspot/share/runtime/sharedRuntime.cpp test/hotspot/gtest/oops/test_markOop.cpp |
diffstat | 17 files changed, 540 insertions(+), 882 deletions(-) [+] |
line wrap: on
line diff
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Thu May 23 14:13:01 2019 +0200 @@ -1788,7 +1788,7 @@ } #endif //ASSERT - DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST; + DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT; bool is_oop = true; if (dest_uninitialized) { decorators |= IS_DEST_UNINITIALIZED;
--- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp Thu May 23 14:13:01 2019 +0200 @@ -36,12 +36,14 @@ if (type == T_OBJECT || type == T_ARRAY) { #ifdef _LP64 - if (!checkcast && !obj_int) { - // Save count for barrier - __ movptr(r11, count); - } else if (disjoint && obj_int) { - // Save dst in r11 in the disjoint case - __ movq(r11, dst); + if (!checkcast) { + if (!obj_int) { + // Save count for barrier + __ movptr(r11, count); + } else if (disjoint) { + // Save dst in r11 in the disjoint case + __ movq(r11, dst); + } } #else if (disjoint) { @@ -61,13 +63,15 @@ if (type == T_OBJECT || type == T_ARRAY) { #ifdef _LP64 - if (!checkcast && !obj_int) { - // Save count for barrier - count = r11; - } else if (disjoint && obj_int) { - // Use the saved dst in the disjoint case - dst = r11; - } else if (checkcast) { + if (!checkcast) { + if (!obj_int) { + // Save count for barrier + count = r11; + } else if (disjoint) { + // Use the saved dst in the disjoint case + dst = r11; + } + } else { tmp = rscratch1; } #else
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Thu May 23 14:13:01 2019 +0200 @@ -53,12 +53,14 @@ if (type == T_OBJECT || type == T_ARRAY) { #ifdef _LP64 - if (!checkcast && !obj_int) { - // Save count for barrier - __ movptr(r11, count); - } else if (disjoint && obj_int) { - // Save dst in r11 in the disjoint case - __ movq(r11, dst); + if (!checkcast) { + if (!obj_int) { + // Save count for barrier + __ movptr(r11, count); + } else if (disjoint) { + // Save dst in r11 in the disjoint case + __ movq(r11, dst); + } } #else if (disjoint) { @@ -123,13 +125,15 @@ if (type == T_OBJECT || type == T_ARRAY) { #ifdef _LP64 - if (!checkcast && !obj_int) { - // Save count for barrier - count = r11; - } else if (disjoint && obj_int) { - // Use the saved dst in the disjoint case - dst = r11; - } else if (checkcast) { + if (!checkcast) { + if (!obj_int) { + // Save count for barrier + count = r11; + } else if (disjoint && obj_int) { + // Use the saved dst in the disjoint case + dst = r11; + } + } else { tmp = rscratch1; } #else
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Thu May 23 14:13:01 2019 +0200 @@ -2198,7 +2198,7 @@ // r9 is used to save r15_thread // 'from', 'to' and 'qword_count' are now valid - DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; + DecoratorSet decorators = IN_HEAP | IS_ARRAY; if (dest_uninitialized) { decorators |= IS_DEST_UNINITIALIZED; } @@ -2392,7 +2392,7 @@ Address from_element_addr(end_from, count, TIMES_OOP, 0); Address to_element_addr(end_to, count, TIMES_OOP, 0); - DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST; + DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT; if (dest_uninitialized) { decorators |= IS_DEST_UNINITIALIZED; }
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp Thu May 23 14:13:01 2019 +0200 @@ -48,6 +48,7 @@ volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0; void ClassLoaderDataGraph::clear_claimed_marks() { + assert_locked_or_safepoint_weak(ClassLoaderDataGraph_lock); for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->clear_claim(); }
--- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp Thu May 23 14:13:01 2019 +0200 @@ -268,6 +268,7 @@ { G1ConcPhase p(G1ConcurrentPhase::CLEAR_CLAIMED_MARKS, this); + MutexLocker ml(ClassLoaderDataGraph_lock); ClassLoaderDataGraph::clear_claimed_marks(); }
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Thu May 23 14:13:01 2019 +0200 @@ -1142,23 +1142,19 @@ info.call_kind() == CallInfo::vtable_call, ""); } #endif + // Get sender or sender's unsafe_anonymous_host, and only set cpCache entry to resolved if + // it is not an interface. The receiver for invokespecial calls within interface + // methods must be checked for every call. + InstanceKlass* sender = pool->pool_holder(); + sender = sender->is_unsafe_anonymous() ? sender->unsafe_anonymous_host() : sender; switch (info.call_kind()) { - case CallInfo::direct_call: { - // Get sender or sender's unsafe_anonymous_host, and only set cpCache entry to resolved if - // it is not an interface. The receiver for invokespecial calls within interface - // methods must be checked for every call. - InstanceKlass* pool_holder = pool->pool_holder(); - InstanceKlass* sender = pool_holder->is_unsafe_anonymous() ? - pool_holder->unsafe_anonymous_host() : pool_holder; - + case CallInfo::direct_call: cp_cache_entry->set_direct_call( bytecode, info.resolved_method(), - sender->is_interface(), - pool_holder); + sender->is_interface()); break; - } case CallInfo::vtable_call: cp_cache_entry->set_vtable_call( bytecode,
--- a/src/hotspot/share/oops/cpCache.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/oops/cpCache.cpp Thu May 23 14:13:01 2019 +0200 @@ -173,8 +173,7 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code, const methodHandle& method, int vtable_index, - bool sender_is_interface, - InstanceKlass* pool_holder) { + bool sender_is_interface) { bool is_vtable_call = (vtable_index >= 0); // FIXME: split this method on this boolean assert(method->interpreter_entry() != NULL, "should have been set at this point"); assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache"); @@ -269,17 +268,9 @@ } // Don't mark invokestatic to method as resolved if the holder class has not yet completed // initialization. An invokestatic must only proceed if the class is initialized, but if - // we resolve it before then that class initialization check is skipped. However if the call - // is from the same class we can resolve as we must be executing with <clinit> on our call stack. - if (invoke_code == Bytecodes::_invokestatic) { - if (!method->method_holder()->is_initialized() && - method->method_holder() != pool_holder) { - do_resolve = false; - } else { - assert(method->method_holder()->is_initialized() || - method->method_holder()->is_reentrant_initialization(Thread::current()), - "invalid class initialization state for invoke_static"); - } + // we resolve it before then that class initialization check is skipped. + if (invoke_code == Bytecodes::_invokestatic && !method->method_holder()->is_initialized()) { + do_resolve = false; } if (do_resolve) { set_bytecode_1(invoke_code); @@ -325,17 +316,17 @@ } void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, const methodHandle& method, - bool sender_is_interface, InstanceKlass* pool_holder) { + bool sender_is_interface) { int index = Method::nonvirtual_vtable_index; // index < 0; FIXME: inline and customize set_direct_or_vtable_call - set_direct_or_vtable_call(invoke_code, method, index, sender_is_interface, pool_holder); + set_direct_or_vtable_call(invoke_code, method, index, sender_is_interface); } void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, const methodHandle& method, int index) { // either the method is a miranda or its holder should accept the given index assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), ""); // index >= 0; FIXME: inline and customize set_direct_or_vtable_call - set_direct_or_vtable_call(invoke_code, method, index, false, NULL /* not used */); + set_direct_or_vtable_call(invoke_code, method, index, false); } void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code,
--- a/src/hotspot/share/oops/cpCache.hpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/oops/cpCache.hpp Thu May 23 14:13:01 2019 +0200 @@ -236,16 +236,14 @@ Bytecodes::Code invoke_code, // the bytecode used for invoking the method const methodHandle& method, // the method/prototype if any (NULL, otherwise) int vtable_index, // the vtable index if any, else negative - bool sender_is_interface, // 'logical' sender (may be host of VMAC) - InstanceKlass* pool_holder // class from which the call is made + bool sender_is_interface ); public: void set_direct_call( // sets entry to exact concrete method entry Bytecodes::Code invoke_code, // the bytecode used for invoking the method const methodHandle& method, // the method to call - bool sender_is_interface, // 'logical' sender (may be host of VMAC) - InstanceKlass* pool_holder // class from which the call is made + bool sender_is_interface ); void set_vtable_call( // sets entry to vtable index
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Thu May 23 14:12:43 2019 +0200 +++ b/src/hotspot/share/runtime/sharedRuntime.cpp Thu May 23 14:13:01 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -1425,18 +1425,12 @@ } #endif - // Do not patch call site for static call to another class - // when the class is not fully initialized. - if (invoke_code == Bytecodes::_invokestatic) { - if (!callee_method->method_holder()->is_initialized() && - callee_method->method_holder() != caller_nm->method()->method_holder()) { - assert(callee_method->method_holder()->is_linked(), "must be"); - return callee_method; - } else { - assert(callee_method->method_holder()->is_initialized() || - callee_method->method_holder()->is_reentrant_initialization(thread), - "invalid class initialization state for invoke_static"); - } + // Do not patch call site for static call when the class is not + // fully initialized. + if (invoke_code == Bytecodes::_invokestatic && + !callee_method->method_holder()->is_initialized()) { + assert(callee_method->method_holder()->is_linked(), "must be"); + return callee_method; } // JSR 292 key invariant:
--- a/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java Thu May 23 14:13:01 2019 +0200 @@ -30,7 +30,6 @@ import java.nio.channels.Channel; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.InterruptibleChannel; -import java.util.concurrent.locks.ReentrantLock; import jdk.internal.access.SharedSecrets; import sun.nio.ch.Interruptible; @@ -86,7 +85,7 @@ public abstract class AbstractInterruptibleChannel implements Channel, InterruptibleChannel { - private final ReentrantLock closeLock = new ReentrantLock(); + private final Object closeLock = new Object(); private volatile boolean closed; /** @@ -106,14 +105,11 @@ * If an I/O error occurs */ public final void close() throws IOException { - closeLock.lock(); - try { + synchronized (closeLock) { if (closed) return; closed = true; implCloseChannel(); - } finally { - closeLock.unlock(); } } @@ -157,8 +153,7 @@ if (interruptor == null) { interruptor = new Interruptible() { public void interrupt(Thread target) { - closeLock.lock(); - try { + synchronized (closeLock) { if (closed) return; closed = true; @@ -166,8 +161,6 @@ try { AbstractInterruptibleChannel.this.implCloseChannel(); } catch (IOException x) { } - } finally { - closeLock.unlock(); } }}; }
--- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu May 23 14:13:01 2019 +0200 @@ -53,7 +53,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import sun.net.ResourceManager; @@ -90,8 +89,7 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final ReentrantLock stateLock = new ReentrantLock(); - private final Condition stateCondition = stateLock.newCondition(); + private final Object stateLock = new Object(); // -- The following fields are protected by stateLock @@ -99,8 +97,7 @@ private static final int ST_UNCONNECTED = 0; private static final int ST_CONNECTED = 1; private static final int ST_CLOSING = 2; - private static final int ST_KILLPENDING = 3; - private static final int ST_KILLED = 4; + private static final int ST_CLOSED = 3; private int state; // IDs of native threads doing reads and writes, for signalling @@ -181,11 +178,8 @@ : StandardProtocolFamily.INET; this.fd = fd; this.fdVal = IOUtil.fdVal(fd); - stateLock.lock(); - try { + synchronized (stateLock) { this.localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } } @@ -197,36 +191,27 @@ @Override public DatagramSocket socket() { - stateLock.lock(); - try { + synchronized (stateLock) { if (socket == null) socket = DatagramSocketAdaptor.create(this); return socket; - } finally { - stateLock.unlock(); } } @Override public SocketAddress getLocalAddress() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); // Perform security check before returning address return Net.getRevealedLocalAddress(localAddress); - } finally { - stateLock.unlock(); } } @Override public SocketAddress getRemoteAddress() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); return remoteAddress; - } finally { - stateLock.unlock(); } } @@ -238,8 +223,7 @@ if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.IP_TOS || @@ -279,8 +263,6 @@ // remaining options don't need any special handling Net.setSocketOption(fd, Net.UNSPEC, name, value); return this; - } finally { - stateLock.unlock(); } } @@ -293,8 +275,7 @@ if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.IP_TOS || @@ -333,8 +314,6 @@ // no special handling return (T) Net.getSocketOption(fd, Net.UNSPEC, name); - } finally { - stateLock.unlock(); } } @@ -382,8 +361,7 @@ begin(); } SocketAddress remote; - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); remote = remoteAddress; if ((remote == null) && mustBeConnected) @@ -392,8 +370,6 @@ bindInternal(null); if (blocking) readerThread = NativeThread.current(); - } finally { - stateLock.unlock(); } return remote; } @@ -407,15 +383,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { readerThread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed); @@ -708,8 +680,7 @@ begin(); } SocketAddress remote; - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); remote = remoteAddress; if ((remote == null) && mustBeConnected) @@ -718,8 +689,6 @@ bindInternal(null); if (blocking) writerThread = NativeThread.current(); - } finally { - stateLock.unlock(); } return remote; } @@ -733,15 +702,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { writerThread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed); @@ -810,12 +775,9 @@ try { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); IOUtil.configureBlocking(fd, block); - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -826,20 +788,14 @@ } InetSocketAddress localAddress() { - stateLock.lock(); - try { + synchronized (stateLock) { return localAddress; - } finally { - stateLock.unlock(); } } InetSocketAddress remoteAddress() { - stateLock.lock(); - try { + synchronized (stateLock) { return remoteAddress; - } finally { - stateLock.unlock(); } } @@ -849,14 +805,11 @@ try { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (localAddress != null) throw new AlreadyBoundException(); bindInternal(local); - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -868,7 +821,7 @@ } private void bindInternal(SocketAddress local) throws IOException { - assert stateLock.isHeldByCurrentThread() && (localAddress == null); + assert Thread.holdsLock(stateLock )&& (localAddress == null); InetSocketAddress isa; if (local == null) { @@ -891,11 +844,8 @@ @Override public boolean isConnected() { - stateLock.lock(); - try { + synchronized (stateLock) { return (state == ST_CONNECTED); - } finally { - stateLock.unlock(); } } @@ -917,8 +867,7 @@ try { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (state == ST_CONNECTED) throw new AlreadyConnectedException(); @@ -952,9 +901,6 @@ IOUtil.configureBlocking(fd, true); } } - - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -971,8 +917,7 @@ try { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { if (!isOpen() || (state != ST_CONNECTED)) return this; @@ -986,8 +931,6 @@ // refresh local address localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -1035,8 +978,7 @@ if (sm != null) sm.checkMulticast(group); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); // check the registry to see if we are already a member of the group @@ -1091,8 +1033,6 @@ registry.add(key); return key; - } finally { - stateLock.unlock(); } } @@ -1118,8 +1058,7 @@ void drop(MembershipKeyImpl key) { assert key.channel() == this; - stateLock.lock(); - try { + synchronized (stateLock) { if (!key.isValid()) return; @@ -1140,8 +1079,6 @@ key.invalidate(); registry.remove(key); - } finally { - stateLock.unlock(); } } @@ -1155,8 +1092,7 @@ assert key.channel() == this; assert key.sourceAddress() == null; - stateLock.lock(); - try { + synchronized (stateLock) { if (!key.isValid()) throw new IllegalStateException("key is no longer valid"); if (source.isAnyLocalAddress()) @@ -1182,8 +1118,6 @@ // ancient kernel throw new UnsupportedOperationException(); } - } finally { - stateLock.unlock(); } } @@ -1194,8 +1128,7 @@ assert key.channel() == this; assert key.sourceAddress() == null; - stateLock.lock(); - try { + synchronized (stateLock) { if (!key.isValid()) throw new IllegalStateException("key is no longer valid"); @@ -1215,116 +1148,117 @@ // should not happen throw new AssertionError(ioe); } - } finally { - stateLock.unlock(); } } /** - * Invoked by implCloseChannel to close the channel. - * - * This method waits for outstanding I/O operations to complete. When in - * blocking mode, the socket is pre-closed and the threads in blocking I/O - * operations are signalled to ensure that the outstanding I/O operations - * complete quickly. - * - * The socket is closed by this method when it is not registered with a - * Selector. Note that a channel configured blocking may be registered with - * a Selector. This arises when a key is canceled and the channel configured - * to blocking mode before the key is flushed from the Selector. + * Closes the socket if there are no I/O operations in progress and the + * channel is not registered with a Selector. */ - @Override - protected void implCloseSelectableChannel() throws IOException { - assert !isOpen(); + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if ((readerThread == 0) && (writerThread == 0) && !isRegistered()) { + state = ST_CLOSED; + try { + nd.close(fd); + } finally { + // notify resource manager + ResourceManager.afterUdpClose(); + } + return true; + } else { + return false; + } + } - boolean blocking; - boolean interrupted = false; + /** + * Invokes tryClose to attempt to close the socket. + * + * This method is used for deferred closing by I/O and Selector operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } - // set state to ST_CLOSING and invalid membership keys - stateLock.lock(); - try { + /** + * Closes this channel when configured in blocking mode. + * + * If there is an I/O operation in progress then the socket is pre-closed + * and the I/O threads signalled, in which case the final close is deferred + * until all I/O operations complete. + */ + private void implCloseBlockingMode() throws IOException { + synchronized (stateLock) { assert state < ST_CLOSING; - blocking = isBlocking(); state = ST_CLOSING; // if member of any multicast groups then invalidate the keys if (registry != null) registry.invalidateAll(); - } finally { - stateLock.unlock(); - } - // wait for any outstanding I/O operations to complete - if (blocking) { - stateLock.lock(); - try { - assert state == ST_CLOSING; + if (!tryClose()) { long reader = readerThread; long writer = writerThread; if (reader != 0 || writer != 0) { nd.preClose(fd); - if (reader != 0) NativeThread.signal(reader); if (writer != 0) NativeThread.signal(writer); - - // wait for blocking I/O operations to end - while (readerThread != 0 || writerThread != 0) { - try { - stateCondition.await(); - } catch (InterruptedException e) { - interrupted = true; - } - } } - } finally { - stateLock.unlock(); - } - } else { - // non-blocking mode: wait for read/write to complete - readLock.lock(); - try { - writeLock.lock(); - writeLock.unlock(); - } finally { - readLock.unlock(); } } + } - // set state to ST_KILLPENDING - stateLock.lock(); - try { - assert state == ST_CLOSING; - state = ST_KILLPENDING; - } finally { - stateLock.unlock(); + /** + * Closes this channel when configured in non-blocking mode. + * + * If the channel is registered with a Selector then the close is deferred + * until the channel is flushed from all Selectors. + */ + private void implCloseNonBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + + // if member of any multicast groups then invalidate the keys + if (registry != null) + registry.invalidateAll(); } - // close socket if not registered with Selector - if (!isRegistered()) - kill(); + // wait for any read/write operations to complete before trying to close + readLock.lock(); + readLock.unlock(); + writeLock.lock(); + writeLock.unlock(); + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryClose(); + } + } + } - // restore interrupt status - if (interrupted) - Thread.currentThread().interrupt(); + /** + * Invoked by implCloseChannel to close the channel. + */ + @Override + protected void implCloseSelectableChannel() throws IOException { + assert !isOpen(); + if (isBlocking()) { + implCloseBlockingMode(); + } else { + implCloseNonBlockingMode(); + } } @Override - public void kill() throws IOException { - stateLock.lock(); - try { - if (state == ST_KILLPENDING) { - state = ST_KILLED; - try { - nd.close(fd); - } finally { - // notify resource manager - ResourceManager.afterUdpClose(); - } + public void kill() { + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryFinishClose(); } - } finally { - stateLock.unlock(); } }
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu May 23 14:13:01 2019 +0200 @@ -46,7 +46,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import sun.net.NetHooks; @@ -72,16 +71,14 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final ReentrantLock stateLock = new ReentrantLock(); - private final Condition stateCondition = stateLock.newCondition(); + private final Object stateLock = new Object(); // -- The following fields are protected by stateLock // Channel state, increases monotonically private static final int ST_INUSE = 0; private static final int ST_CLOSING = 1; - private static final int ST_KILLPENDING = 2; - private static final int ST_KILLED = 3; + private static final int ST_CLOSED = 2; private int state; // ID of native thread currently blocked in this channel, for signalling @@ -112,11 +109,8 @@ this.fd = fd; this.fdVal = IOUtil.fdVal(fd); if (bound) { - stateLock.lock(); - try { + synchronized (stateLock) { localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } } } @@ -129,26 +123,20 @@ @Override public ServerSocket socket() { - stateLock.lock(); - try { + synchronized (stateLock) { if (socket == null) socket = ServerSocketAdaptor.create(this); return socket; - } finally { - stateLock.unlock(); } } @Override public SocketAddress getLocalAddress() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); return (localAddress == null) ? null : Net.getRevealedLocalAddress(localAddress); - } finally { - stateLock.unlock(); } } @@ -159,8 +147,7 @@ Objects.requireNonNull(name); if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { @@ -171,8 +158,6 @@ Net.setSocketOption(fd, Net.UNSPEC, name, value); } return this; - } finally { - stateLock.unlock(); } } @@ -185,8 +170,7 @@ if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { // SO_REUSEADDR emulated when using exclusive bind @@ -194,8 +178,6 @@ } // no options that require special handling return (T) Net.getSocketOption(fd, Net.UNSPEC, name); - } finally { - stateLock.unlock(); } } @@ -221,8 +203,7 @@ @Override public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (localAddress != null) throw new AlreadyBoundException(); @@ -236,8 +217,6 @@ Net.bind(fd, isa.getAddress(), isa.getPort()); Net.listen(fd, backlog < 1 ? 50 : backlog); localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } return this; } @@ -251,15 +230,12 @@ private void begin(boolean blocking) throws ClosedChannelException { if (blocking) begin(); // set blocker to close channel if interrupted - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (localAddress == null) throw new NotYetBoundException(); if (blocking) thread = NativeThread.current(); - } finally { - stateLock.unlock(); } } @@ -273,15 +249,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { thread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } end(completed); } @@ -405,101 +377,99 @@ */ private void lockedConfigureBlocking(boolean block) throws IOException { assert acceptLock.isHeldByCurrentThread(); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); IOUtil.configureBlocking(fd, block); - } finally { - stateLock.unlock(); + } + } + + /** + * Closes the socket if there are no accept in progress and the channel is + * not registered with a Selector. + */ + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if ((thread == 0) && !isRegistered()) { + state = ST_CLOSED; + nd.close(fd); + return true; + } else { + return false; + } + } + + /** + * Invokes tryClose to attempt to close the socket. + * + * This method is used for deferred closing by I/O and Selector operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } + + /** + * Closes this channel when configured in blocking mode. + * + * If there is an accept in progress then the socket is pre-closed and the + * accept thread is signalled, in which case the final close is deferred + * until the accept aborts. + */ + private void implCloseBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + if (!tryClose()) { + long th = thread; + if (th != 0) { + nd.preClose(fd); + NativeThread.signal(th); + } + } + } + } + + /** + * Closes this channel when configured in non-blocking mode. + * + * If the channel is registered with a Selector then the close is deferred + * until the channel is flushed from all Selectors. + */ + private void implCloseNonBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + } + // wait for any accept to complete before trying to close + acceptLock.lock(); + acceptLock.unlock(); + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryClose(); + } } } /** * Invoked by implCloseChannel to close the channel. - * - * This method waits for outstanding I/O operations to complete. When in - * blocking mode, the socket is pre-closed and the threads in blocking I/O - * operations are signalled to ensure that the outstanding I/O operations - * complete quickly. - * - * The socket is closed by this method when it is not registered with a - * Selector. Note that a channel configured blocking may be registered with - * a Selector. This arises when a key is canceled and the channel configured - * to blocking mode before the key is flushed from the Selector. */ @Override protected void implCloseSelectableChannel() throws IOException { assert !isOpen(); - - boolean interrupted = false; - boolean blocking; - - // set state to ST_CLOSING - stateLock.lock(); - try { - assert state < ST_CLOSING; - state = ST_CLOSING; - blocking = isBlocking(); - } finally { - stateLock.unlock(); + if (isBlocking()) { + implCloseBlockingMode(); + } else { + implCloseNonBlockingMode(); } - - // wait for any outstanding accept to complete - if (blocking) { - stateLock.lock(); - try { - assert state == ST_CLOSING; - long th = thread; - if (th != 0) { - nd.preClose(fd); - NativeThread.signal(th); - - // wait for accept operation to end - while (thread != 0) { - try { - stateCondition.await(); - } catch (InterruptedException e) { - interrupted = true; - } - } - } - } finally { - stateLock.unlock(); - } - } else { - // non-blocking mode: wait for accept to complete - acceptLock.lock(); - acceptLock.unlock(); - } - - // set state to ST_KILLPENDING - stateLock.lock(); - try { - assert state == ST_CLOSING; - state = ST_KILLPENDING; - } finally { - stateLock.unlock(); - } - - // close socket if not registered with Selector - if (!isRegistered()) - kill(); - - // restore interrupt status - if (interrupted) - Thread.currentThread().interrupt(); } @Override - public void kill() throws IOException { - stateLock.lock(); - try { - if (state == ST_KILLPENDING) { - state = ST_KILLED; - nd.close(fd); + public void kill() { + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryFinishClose(); } - } finally { - stateLock.unlock(); } } @@ -507,11 +477,8 @@ * Returns true if channel's socket is bound */ boolean isBound() { - stateLock.lock(); - try { + synchronized (stateLock) { return localAddress != null; - } finally { - stateLock.unlock(); } } @@ -519,11 +486,8 @@ * Returns the local address, or null if not bound */ InetSocketAddress localAddress() { - stateLock.lock(); - try { + synchronized (stateLock) { return localAddress; - } finally { - stateLock.unlock(); } } @@ -589,16 +553,13 @@ if (!isOpen()) { sb.append("closed"); } else { - stateLock.lock(); - try { + synchronized (stateLock) { InetSocketAddress addr = localAddress; if (addr == null) { sb.append("unbound"); } else { sb.append(Net.getRevealedLocalAddressAsString(addr)); } - } finally { - stateLock.unlock(); } } sb.append(']');
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Thu May 23 14:13:01 2019 +0200 @@ -53,7 +53,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import sun.net.ConnectionResetException; @@ -84,8 +83,7 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final ReentrantLock stateLock = new ReentrantLock(); - private final Condition stateCondition = stateLock.newCondition(); + private final Object stateLock = new Object(); // Input/Output closed private volatile boolean isInputClosed; @@ -104,8 +102,7 @@ private static final int ST_CONNECTIONPENDING = 1; private static final int ST_CONNECTED = 2; private static final int ST_CLOSING = 3; - private static final int ST_KILLPENDING = 4; - private static final int ST_KILLED = 5; + private static final int ST_CLOSED = 4; private volatile int state; // need stateLock to change // IDs of native threads doing reads and writes, for signalling @@ -137,11 +134,8 @@ this.fd = fd; this.fdVal = IOUtil.fdVal(fd); if (bound) { - stateLock.lock(); - try { + synchronized (stateLock) { this.localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } } } @@ -154,13 +148,10 @@ super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); - stateLock.lock(); - try { + synchronized (stateLock) { this.localAddress = Net.localAddress(fd); this.remoteAddress = isa; this.state = ST_CONNECTED; - } finally { - stateLock.unlock(); } } @@ -197,35 +188,26 @@ @Override public Socket socket() { - stateLock.lock(); - try { + synchronized (stateLock) { if (socket == null) socket = SocketAdaptor.create(this); return socket; - } finally { - stateLock.unlock(); } } @Override public SocketAddress getLocalAddress() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); return Net.getRevealedLocalAddress(localAddress); - } finally { - stateLock.unlock(); } } @Override public SocketAddress getRemoteAddress() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); return remoteAddress; - } finally { - stateLock.unlock(); } } @@ -237,8 +219,7 @@ if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.IP_TOS) { @@ -257,8 +238,6 @@ // no options that require special handling Net.setSocketOption(fd, name, value); return this; - } finally { - stateLock.unlock(); } } @@ -271,8 +250,7 @@ if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { @@ -289,8 +267,6 @@ // no options that require special handling return (T) Net.getSocketOption(fd, name); - } finally { - stateLock.unlock(); } } @@ -332,13 +308,10 @@ // set hook for Thread.interrupt begin(); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpenAndConnected(); // record thread so it can be signalled if needed readerThread = NativeThread.current(); - } finally { - stateLock.unlock(); } } else { ensureOpenAndConnected(); @@ -355,15 +328,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { readerThread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed); @@ -467,15 +436,12 @@ // set hook for Thread.interrupt begin(); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpenAndConnected(); if (isOutputClosed) throw new ClosedChannelException(); // record thread so it can be signalled if needed writerThread = NativeThread.current(); - } finally { - stateLock.unlock(); } } else { ensureOpenAndConnected(); @@ -492,15 +458,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { writerThread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed); @@ -613,12 +575,9 @@ */ private void lockedConfigureBlocking(boolean block) throws IOException { assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); IOUtil.configureBlocking(fd, block); - } finally { - stateLock.unlock(); } } @@ -626,11 +585,8 @@ * Returns the local address, or null if not bound */ InetSocketAddress localAddress() { - stateLock.lock(); - try { + synchronized (stateLock) { return localAddress; - } finally { - stateLock.unlock(); } } @@ -638,11 +594,8 @@ * Returns the remote address, or null if not connected */ InetSocketAddress remoteAddress() { - stateLock.lock(); - try { + synchronized (stateLock) { return remoteAddress; - } finally { - stateLock.unlock(); } } @@ -652,8 +605,7 @@ try { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (state == ST_CONNECTIONPENDING) throw new ConnectionPendingException(); @@ -668,8 +620,6 @@ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -706,8 +656,7 @@ // set hook for Thread.interrupt begin(); } - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); int state = this.state; if (state == ST_CONNECTED) @@ -725,8 +674,6 @@ // record thread so it can be signalled if needed readerThread = NativeThread.current(); } - } finally { - stateLock.unlock(); } } @@ -743,14 +690,11 @@ endRead(blocking, completed); if (completed) { - stateLock.lock(); - try { + synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { localAddress = Net.localAddress(fd); state = ST_CONNECTED; } - } finally { - stateLock.unlock(); } } } @@ -823,8 +767,7 @@ // set hook for Thread.interrupt begin(); } - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (state != ST_CONNECTIONPENDING) throw new NoConnectionPendingException(); @@ -832,8 +775,6 @@ // record thread so it can be signalled if needed readerThread = NativeThread.current(); } - } finally { - stateLock.unlock(); } } @@ -850,14 +791,11 @@ endRead(blocking, completed); if (completed) { - stateLock.lock(); - try { + synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { localAddress = Net.localAddress(fd); state = ST_CONNECTED; } - } finally { - stateLock.unlock(); } } } @@ -904,90 +842,89 @@ } /** - * Invoked by implCloseChannel to close the channel. - * - * This method waits for outstanding I/O operations to complete. When in - * blocking mode, the socket is pre-closed and the threads in blocking I/O - * operations are signalled to ensure that the outstanding I/O operations - * complete quickly. - * - * If the socket is connected then it is shutdown by this method. The - * shutdown ensures that the peer reads EOF for the case that the socket is - * not pre-closed or closed by this method. - * - * The socket is closed by this method when it is not registered with a - * Selector. Note that a channel configured blocking may be registered with - * a Selector. This arises when a key is canceled and the channel configured - * to blocking mode before the key is flushed from the Selector. + * Closes the socket if there are no I/O operations in progress and the + * channel is not registered with a Selector. */ - @Override - protected void implCloseSelectableChannel() throws IOException { - assert !isOpen(); + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if ((readerThread == 0) && (writerThread == 0) && !isRegistered()) { + state = ST_CLOSED; + nd.close(fd); + return true; + } else { + return false; + } + } - boolean blocking; - boolean connected; - boolean interrupted = false; + /** + * Invokes tryClose to attempt to close the socket. + * + * This method is used for deferred closing by I/O and Selector operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } - // set state to ST_CLOSING - stateLock.lock(); - try { + /** + * Closes this channel when configured in blocking mode. + * + * If there is an I/O operation in progress then the socket is pre-closed + * and the I/O threads signalled, in which case the final close is deferred + * until all I/O operations complete. + * + * Note that a channel configured blocking may be registered with a Selector + * This arises when a key is canceled and the channel configured to blocking + * mode before the key is flushed from the Selector. + */ + private void implCloseBlockingMode() throws IOException { + synchronized (stateLock) { assert state < ST_CLOSING; - blocking = isBlocking(); - connected = (state == ST_CONNECTED); state = ST_CLOSING; - } finally { - stateLock.unlock(); - } - - // wait for any outstanding I/O operations to complete - if (blocking) { - stateLock.lock(); - try { - assert state == ST_CLOSING; + if (!tryClose()) { long reader = readerThread; long writer = writerThread; if (reader != 0 || writer != 0) { nd.preClose(fd); - connected = false; // fd is no longer connected socket - if (reader != 0) NativeThread.signal(reader); if (writer != 0) NativeThread.signal(writer); - - // wait for blocking I/O operations to end - while (readerThread != 0 || writerThread != 0) { - try { - stateCondition.await(); - } catch (InterruptedException e) { - interrupted = true; - } - } } - } finally { - stateLock.unlock(); - } - } else { - // non-blocking mode: wait for read/write to complete - readLock.lock(); - try { - writeLock.lock(); - writeLock.unlock(); - } finally { - readLock.unlock(); } } + } - // set state to ST_KILLPENDING - stateLock.lock(); - try { - assert state == ST_CLOSING; - // if connected and the channel is registered with a Selector then - // shutdown the output if possible so that the peer reads EOF. If - // SO_LINGER is enabled and set to a non-zero value then it needs to - // be disabled so that the Selector does not wait when it closes - // the socket. - if (connected && isRegistered()) { + /** + * Closes this channel when configured in non-blocking mode. + * + * If the channel is registered with a Selector then the close is deferred + * until the channel is flushed from all Selectors. + * + * If the socket is connected and the channel is registered with a Selector + * then the socket is shutdown for writing so that the peer reads EOF. In + * addition, if SO_LINGER is set to a non-zero value then it is disabled so + * that the deferred close does not wait. + */ + private void implCloseNonBlockingMode() throws IOException { + boolean connected; + synchronized (stateLock) { + assert state < ST_CLOSING; + connected = (state == ST_CONNECTED); + state = ST_CLOSING; + } + + // wait for any read/write operations to complete + readLock.lock(); + readLock.unlock(); + writeLock.lock(); + writeLock.unlock(); + + // if the socket cannot be closed because it's registered with a Selector + // then shutdown the socket for writing. + synchronized (stateLock) { + if (state == ST_CLOSING && !tryClose() && connected && isRegistered()) { try { SocketOption<Integer> opt = StandardSocketOptions.SO_LINGER; int interval = (int) Net.getSocketOption(fd, Net.UNSPEC, opt); @@ -1000,37 +937,34 @@ } } catch (IOException ignore) { } } - state = ST_KILLPENDING; - } finally { - stateLock.unlock(); } + } - // close socket if not registered with Selector - if (!isRegistered()) - kill(); - - // restore interrupt status - if (interrupted) - Thread.currentThread().interrupt(); + /** + * Invoked by implCloseChannel to close the channel. + */ + @Override + protected void implCloseSelectableChannel() throws IOException { + assert !isOpen(); + if (isBlocking()) { + implCloseBlockingMode(); + } else { + implCloseNonBlockingMode(); + } } @Override - public void kill() throws IOException { - stateLock.lock(); - try { - if (state == ST_KILLPENDING) { - state = ST_KILLED; - nd.close(fd); + public void kill() { + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryFinishClose(); } - } finally { - stateLock.unlock(); } } @Override public SocketChannel shutdownInput() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (!isConnected()) throw new NotYetConnectedException(); @@ -1042,15 +976,12 @@ isInputClosed = true; } return this; - } finally { - stateLock.unlock(); } } @Override public SocketChannel shutdownOutput() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpen(); if (!isConnected()) throw new NotYetConnectedException(); @@ -1062,8 +993,6 @@ isOutputClosed = true; } return this; - } finally { - stateLock.unlock(); } } @@ -1300,16 +1229,13 @@ * Return the number of bytes in the socket input buffer. */ int available() throws IOException { - stateLock.lock(); - try { + synchronized (stateLock) { ensureOpenAndConnected(); if (isInputClosed) { return 0; } else { return Net.available(fd); } - } finally { - stateLock.unlock(); } } @@ -1389,8 +1315,7 @@ if (!isOpen()) sb.append("closed"); else { - stateLock.lock(); - try { + synchronized (stateLock) { switch (state) { case ST_UNCONNECTED: sb.append("unconnected"); @@ -1415,8 +1340,6 @@ sb.append(" remote="); sb.append(remoteAddress().toString()); } - } finally { - stateLock.unlock(); } } sb.append(']');
--- a/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java Thu May 23 14:13:01 2019 +0200 @@ -35,7 +35,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.spi.SelectorProvider; import java.util.Objects; -import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; class SinkChannelImpl @@ -54,16 +53,14 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final ReentrantLock stateLock = new ReentrantLock(); - private final Condition stateCondition = stateLock.newCondition(); + private final Object stateLock = new Object(); // -- The following fields are protected by stateLock // Channel state private static final int ST_INUSE = 0; private static final int ST_CLOSING = 1; - private static final int ST_KILLPENDING = 2; - private static final int ST_KILLED = 3; + private static final int ST_CLOSED = 2; private int state; // ID of native thread doing write, for signalling @@ -87,82 +84,92 @@ } /** + * Closes the write end of the pipe if there are no write operation in + * progress and the channel is not registered with a Selector. + */ + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if (thread == 0 && !isRegistered()) { + state = ST_CLOSED; + nd.close(fd); + return true; + } else { + return false; + } + } + + /** + * Invokes tryClose to attempt to close the write end of the pipe. + * + * This method is used for deferred closing by I/O and Selector operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } + + /** + * Closes this channel when configured in blocking mode. + * + * If there is a write operation in progress then the write-end of the pipe + * is pre-closed and the writer is signalled, in which case the final close + * is deferred until the writer aborts. + */ + private void implCloseBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + if (!tryClose()) { + long th = thread; + if (th != 0) { + nd.preClose(fd); + NativeThread.signal(th); + } + } + } + } + + /** + * Closes this channel when configured in non-blocking mode. + * + * If the channel is registered with a Selector then the close is deferred + * until the channel is flushed from all Selectors. + */ + private void implCloseNonBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + } + // wait for any write operation to complete before trying to close + writeLock.lock(); + writeLock.unlock(); + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryClose(); + } + } + } + + /** * Invoked by implCloseChannel to close the channel. */ @Override protected void implCloseSelectableChannel() throws IOException { assert !isOpen(); - - boolean interrupted = false; - boolean blocking; - - // set state to ST_CLOSING - stateLock.lock(); - try { - assert state < ST_CLOSING; - state = ST_CLOSING; - blocking = isBlocking(); - } finally { - stateLock.unlock(); + if (isBlocking()) { + implCloseBlockingMode(); + } else { + implCloseNonBlockingMode(); } - - // wait for any outstanding write to complete - if (blocking) { - stateLock.lock(); - try { - assert state == ST_CLOSING; - long th = thread; - if (th != 0) { - nd.preClose(fd); - NativeThread.signal(th); - - // wait for write operation to end - while (thread != 0) { - try { - stateCondition.await(); - } catch (InterruptedException e) { - interrupted = true; - } - } - } - } finally { - stateLock.unlock(); - } - } else { - // non-blocking mode: wait for write to complete - writeLock.lock(); - writeLock.unlock(); - } - - // set state to ST_KILLPENDING - stateLock.lock(); - try { - assert state == ST_CLOSING; - state = ST_KILLPENDING; - } finally { - stateLock.unlock(); - } - - // close socket if not registered with Selector - if (!isRegistered()) - kill(); - - // restore interrupt status - if (interrupted) - Thread.currentThread().interrupt(); } @Override - public void kill() throws IOException { - stateLock.lock(); - try { - assert thread == 0; - if (state == ST_KILLPENDING) { - state = ST_KILLED; - nd.close(fd); + public void kill() { + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryFinishClose(); } - } finally { - stateLock.unlock(); } } @@ -170,11 +177,10 @@ protected void implConfigureBlocking(boolean block) throws IOException { writeLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); IOUtil.configureBlocking(fd, block); - } finally { - stateLock.unlock(); } } finally { writeLock.unlock(); @@ -229,14 +235,11 @@ // set hook for Thread.interrupt begin(); } - stateLock.lock(); - try { + synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); if (blocking) thread = NativeThread.current(); - } finally { - stateLock.unlock(); } } @@ -250,15 +253,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { thread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed);
--- a/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java Thu May 23 14:12:43 2019 +0200 +++ b/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java Thu May 23 14:13:01 2019 +0200 @@ -35,7 +35,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.spi.SelectorProvider; import java.util.Objects; -import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; class SourceChannelImpl @@ -54,16 +53,14 @@ // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final ReentrantLock stateLock = new ReentrantLock(); - private final Condition stateCondition = stateLock.newCondition(); + private final Object stateLock = new Object(); // -- The following fields are protected by stateLock // Channel state private static final int ST_INUSE = 0; private static final int ST_CLOSING = 1; - private static final int ST_KILLPENDING = 2; - private static final int ST_KILLED = 3; + private static final int ST_CLOSED = 2; private int state; // ID of native thread doing read, for signalling @@ -87,82 +84,92 @@ } /** + * Closes the read end of the pipe if there are no read operation in + * progress and the channel is not registered with a Selector. + */ + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if (thread == 0 && !isRegistered()) { + state = ST_CLOSED; + nd.close(fd); + return true; + } else { + return false; + } + } + + /** + * Invokes tryClose to attempt to close the read end of the pipe. + * + * This method is used for deferred closing by I/O and Selector operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } + + /** + * Closes this channel when configured in blocking mode. + * + * If there is a read operation in progress then the read-end of the pipe + * is pre-closed and the reader is signalled, in which case the final close + * is deferred until the reader aborts. + */ + private void implCloseBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + if (!tryClose()) { + long th = thread; + if (th != 0) { + nd.preClose(fd); + NativeThread.signal(th); + } + } + } + } + + /** + * Closes this channel when configured in non-blocking mode. + * + * If the channel is registered with a Selector then the close is deferred + * until the channel is flushed from all Selectors. + */ + private void implCloseNonBlockingMode() throws IOException { + synchronized (stateLock) { + assert state < ST_CLOSING; + state = ST_CLOSING; + } + // wait for any read operation to complete before trying to close + readLock.lock(); + readLock.unlock(); + synchronized (stateLock) { + if (state == ST_CLOSING) { + tryClose(); + } + } + } + + /** * Invoked by implCloseChannel to close the channel. */ @Override protected void implCloseSelectableChannel() throws IOException { assert !isOpen(); - - boolean interrupted = false; - boolean blocking; - - // set state to ST_CLOSING - stateLock.lock(); - try { - assert state < ST_CLOSING; - state = ST_CLOSING; - blocking = isBlocking(); - } finally { - stateLock.unlock(); + if (isBlocking()) { + implCloseBlockingMode(); + } else { + implCloseNonBlockingMode(); } - - // wait for any outstanding read to complete - if (blocking) { - stateLock.lock(); - try { - assert state == ST_CLOSING; - long th = thread; - if (th != 0) { - nd.preClose(fd); - NativeThread.signal(th); - - // wait for read operation to end - while (thread != 0) { - try { - stateCondition.await(); - } catch (InterruptedException e) { - interrupted = true; - } - } - } - } finally { - stateLock.unlock(); + } + @Override + public void kill() { + synchronized (stateLock) { + assert !isOpen(); + if (state == ST_CLOSING) { + tryFinishClose(); } - } else { - // non-blocking mode: wait for read to complete - readLock.lock(); - readLock.unlock(); - } - - // set state to ST_KILLPENDING - stateLock.lock(); - try { - assert state == ST_CLOSING; - state = ST_KILLPENDING; - } finally { - stateLock.unlock(); - } - - // close socket if not registered with Selector - if (!isRegistered()) - kill(); - - // restore interrupt status - if (interrupted) - Thread.currentThread().interrupt(); - } - - @Override - public void kill() throws IOException { - stateLock.lock(); - try { - assert thread == 0; - if (state == ST_KILLPENDING) { - state = ST_KILLED; - nd.close(fd); - } - } finally { - stateLock.unlock(); } } @@ -170,11 +177,10 @@ protected void implConfigureBlocking(boolean block) throws IOException { readLock.lock(); try { - stateLock.lock(); - try { + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); IOUtil.configureBlocking(fd, block); - } finally { - stateLock.unlock(); } } finally { readLock.unlock(); @@ -229,14 +235,11 @@ // set hook for Thread.interrupt begin(); } - stateLock.lock(); - try { + synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); if (blocking) thread = NativeThread.current(); - } finally { - stateLock.unlock(); } } @@ -250,15 +253,11 @@ throws AsynchronousCloseException { if (blocking) { - stateLock.lock(); - try { + synchronized (stateLock) { thread = 0; - // notify any thread waiting in implCloseSelectableChannel if (state == ST_CLOSING) { - stateCondition.signalAll(); + tryFinishClose(); } - } finally { - stateLock.unlock(); } // remove hook for Thread.interrupt end(completed);
--- a/test/hotspot/gtest/oops/test_markOop.cpp Thu May 23 14:12:43 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -#include "precompiled.hpp" -#include "classfile/systemDictionary.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/atomic.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/orderAccess.hpp" -#include "runtime/os.hpp" -#include "runtime/synchronizer.hpp" -#include "threadHelper.inline.hpp" -#include "unittest.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/ostream.hpp" - -// The test doesn't work for PRODUCT because it needs WizardMode -#ifndef PRODUCT -static bool test_pattern(stringStream* st, const char* pattern) { - return (strstr(st->as_string(), pattern) != NULL); -} - -static void assert_test_pattern(Handle object, const char* pattern) { - stringStream st; - object->print_on(&st); - ASSERT_TRUE(test_pattern(&st, pattern)) << pattern << " not in " << st.as_string(); -} - -static void assert_not_test_pattern(Handle object, const char* pattern) { - stringStream st; - object->print_on(&st); - ASSERT_FALSE(test_pattern(&st, pattern)) << pattern << " found in " << st.as_string(); -} - -class LockerThread : public JavaTestThread { - oop _obj; - public: - LockerThread(Semaphore* post, oop obj) : JavaTestThread(post), _obj(obj) {} - virtual ~LockerThread() {} - - void main_run() { - Thread* THREAD = Thread::current(); - HandleMark hm(THREAD); - Handle h_obj(THREAD, _obj); - ResourceMark rm(THREAD); - - // Wait gets the lock inflated. - // The object will stay locked for the context of 'ol' so the lock will - // still be inflated after the notify_all() call. Deflation can't happen - // while an ObjectMonitor is "busy" and being locked is the most "busy" - // state we have... - ObjectLocker ol(h_obj, THREAD); - ol.notify_all(THREAD); - assert_test_pattern(h_obj, "monitor"); - } -}; - - -TEST_VM(markOopDesc, printing) { - JavaThread* THREAD = JavaThread::current(); - ThreadInVMfromNative invm(THREAD); - ResourceMark rm(THREAD); - - oop obj = SystemDictionary::Byte_klass()->allocate_instance(THREAD); - - FlagSetting fs(WizardMode, true); - FlagSetting bf(UseBiasedLocking, true); - - HandleMark hm(THREAD); - Handle h_obj(THREAD, obj); - - // Biased locking is initially enabled for this java.lang.Byte object. - assert_test_pattern(h_obj, "is_biased"); - - // Lock using biased locking. - BasicObjectLock lock; - lock.set_obj(obj); - markOop mark = obj->mark()->incr_bias_epoch(); - obj->set_mark(mark); - ObjectSynchronizer::fast_enter(h_obj, lock.lock(), true, THREAD); -#ifdef _LP64 - // Look for the biased_locker in markOop, not prototype_header. - assert_not_test_pattern(h_obj, "mark(is_biased biased_locker=0x0000000000000000"); -#endif - - // Same thread tries to lock it again. - { - ObjectLocker ol(h_obj, THREAD); - assert_test_pattern(h_obj, "locked"); - } - - // This is no longer biased, because ObjectLocker revokes the bias. - assert_test_pattern(h_obj, "is_neutral no_hash"); - - // Wait gets the lock inflated. - { - ObjectLocker ol(h_obj, THREAD); - - Semaphore done(0); - LockerThread* st; - st = new LockerThread(&done, h_obj()); - st->doit(); - - ol.wait(THREAD); - assert_test_pattern(h_obj, "monitor"); - } - - // Make the object older. Not all GCs use this field. - Universe::heap()->collect(GCCause::_java_lang_system_gc); - if (UseParallelGC) { - assert_test_pattern(h_obj, "is_neutral no_hash age 1"); - } - - // Hash the object then print it. - intx hash = h_obj->identity_hash(); - assert_test_pattern(h_obj, "is_neutral hash=0x"); -} -#endif // PRODUCT