diff --git a/.idea/libraries/Netty.xml b/.idea/libraries/Netty.xml index 9d24dbe72c71..3ae05ffb9deb 100644 --- a/.idea/libraries/Netty.xml +++ b/.idea/libraries/Netty.xml @@ -4,11 +4,11 @@ - + - + \ No newline at end of file diff --git a/lib/annotations/netty/io/netty/channel/annotations.xml b/lib/annotations/netty/io/netty/channel/annotations.xml index 2c53e34a7c43..13f5c446cf4a 100644 --- a/lib/annotations/netty/io/netty/channel/annotations.xml +++ b/lib/annotations/netty/io/netty/channel/annotations.xml @@ -1,4 +1,7 @@ + + + diff --git a/lib/netty-all-4.1.0.Beta7.jar b/lib/netty-all-4.1.0.Beta7.jar deleted file mode 100644 index 5b707f12ced3..000000000000 Binary files a/lib/netty-all-4.1.0.Beta7.jar and /dev/null differ diff --git a/lib/netty-all-4.1.0.Beta8.jar b/lib/netty-all-4.1.0.Beta8.jar new file mode 100644 index 000000000000..f587b1326f7a Binary files /dev/null and b/lib/netty-all-4.1.0.Beta8.jar differ diff --git a/lib/required_for_dist.txt b/lib/required_for_dist.txt index cec5732200c2..e435b7b06c2b 100644 --- a/lib/required_for_dist.txt +++ b/lib/required_for_dist.txt @@ -54,7 +54,7 @@ microba.jar miglayout-swing.jar nanoxml-2.2.3.jar nekohtml-1.9.14.jar -netty-all-4.1.0.Beta7.jar +netty-all-4.1.0.Beta8.jar oromatcher.jar picocontainer.jar protobuf-2.5.0.jar diff --git a/lib/src/netty-all-4.1.0.Beta7-sources.jar b/lib/src/netty-all-4.1.0.Beta8-sources.jar similarity index 82% rename from lib/src/netty-all-4.1.0.Beta7-sources.jar rename to lib/src/netty-all-4.1.0.Beta8-sources.jar index 3e3d54758a7a..30a39394c5ae 100644 Binary files a/lib/src/netty-all-4.1.0.Beta7-sources.jar and b/lib/src/netty-all-4.1.0.Beta8-sources.jar differ diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index ffd38062e8c8..0deecd140970 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -97,45 +97,16 @@ public final class NettyUtil { int maxAttemptCount, @NotNull Condition stopCondition) throws Throwable { int attemptCount = 0; - if (bootstrap.group() instanceof NioEventLoopGroup) { - while (true) { - ChannelFuture future = bootstrap.connect(remoteAddress).awaitUninterruptibly(); - if (future.isSuccess()) { - return future.channel(); - } - else if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) { - return null; - } - else if (maxAttemptCount == -1) { - //noinspection BusyWait - Thread.sleep(300); - attemptCount++; - } - else if (++attemptCount < maxAttemptCount) { - //noinspection BusyWait - Thread.sleep(attemptCount * MIN_START_TIME); - } - else { - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - Throwable cause = future.cause(); - if (promise != null) { - if (cause == null) { - promise.setError("Cannot connect: unknown error"); - } - else { - promise.setError(cause); - } - } - return null; - } - } + return connectNio(bootstrap, remoteAddress, promise, maxAttemptCount, stopCondition, attemptCount); } + bootstrap.validate(); + Socket socket; while (true) { try { - //noinspection SocketOpenedButNotSafelyClosed + //noinspection IOResourceOpenedButNotSafelyClosed,SocketOpenedButNotSafelyClosed socket = new Socket(remoteAddress.getAddress(), remoteAddress.getPort()); break; } @@ -144,13 +115,15 @@ public final class NettyUtil { return null; } else if (maxAttemptCount == -1) { - //noinspection BusyWait - Thread.sleep(300); + if (sleep(promise, 300)) { + return null; + } attemptCount++; } else if (++attemptCount < maxAttemptCount) { - //noinspection BusyWait - Thread.sleep(attemptCount * MIN_START_TIME); + if (sleep(promise, attemptCount * MIN_START_TIME)) { + return null; + } } else { if (promise != null) { @@ -160,11 +133,71 @@ public final class NettyUtil { } } } + OioSocketChannel channel = new OioSocketChannel(socket); BootstrapUtil.initAndRegister(channel, bootstrap).sync(); return channel; } + @Nullable + private static Channel connectNio(@NotNull Bootstrap bootstrap, + @NotNull InetSocketAddress remoteAddress, + @Nullable AsyncPromise promise, + int maxAttemptCount, + @NotNull Condition stopCondition, + int attemptCount) { + while (true) { + ChannelFuture future = bootstrap.connect(remoteAddress).awaitUninterruptibly(); + if (future.isSuccess()) { + if (!future.channel().isOpen()) { + continue; + } + return future.channel(); + } + else if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) { + return null; + } + else if (maxAttemptCount == -1) { + if (sleep(promise, 300)) { + return null; + } + attemptCount++; + } + else if (++attemptCount < maxAttemptCount) { + if (sleep(promise, attemptCount * MIN_START_TIME)) { + return null; + } + } + else { + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + Throwable cause = future.cause(); + if (promise != null) { + if (cause == null) { + promise.setError("Cannot connect: unknown error"); + } + else { + promise.setError(cause); + } + } + return null; + } + } + } + + private static boolean sleep(@Nullable AsyncPromise promise, int time) { + try { + //noinspection BusyWait + Thread.sleep(time); + } + catch (InterruptedException ignored) { + if (promise != null) { + promise.setError("Interrupted"); + } + return true; + } + return false; + } + private static boolean isAsWarning(@NotNull Throwable throwable) { String message = throwable.getMessage(); if (message == null) { diff --git a/platform/script-debugger/backend/src/util.kt b/platform/script-debugger/backend/src/util.kt index 7feee87e8513..7fe57aa2c8e0 100644 --- a/platform/script-debugger/backend/src/util.kt +++ b/platform/script-debugger/backend/src/util.kt @@ -20,8 +20,10 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.CharsetToolkit import io.netty.buffer.ByteBuf +import io.netty.channel.Channel import org.jetbrains.annotations.PropertyKey import org.jetbrains.io.JsonReaderEx +import org.jetbrains.io.addListener import java.io.File import java.io.FileOutputStream import java.nio.CharBuffer @@ -33,6 +35,8 @@ internal class LogEntry(val message: Any, val marker: String) { } class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQueue) { + internal @Volatile var closed = false + fun add(inMessage: CharSequence, marker: String = "IN") { queue.add(LogEntry(inMessage, marker)) } @@ -40,9 +44,24 @@ class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQu fun add(outMessage: ByteBuf, marker: String = "OUT") { queue.add(LogEntry(outMessage.copy(), marker)) } + + fun close() { + closed = true + } + + fun closeOnChannelClose(channel: Channel) { + channel.closeFuture().addListener { + try { + add("\"Closed\"", "Channel") + } + finally { + close() + } + } + } } -fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) key: String, vm: AttachStateManager): MessagingLogger? { +fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) key: String): MessagingLogger? { val debugFile = Registry.stringValue(key) if (debugFile.isNullOrEmpty()) { return null @@ -60,42 +79,44 @@ fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) ke val dateFormatter = SimpleDateFormat("HH.mm.ss,SSS") - o@ do { - while (true) { - val entry = queue.poll() ?: continue@o + while (true) { + val entry = queue.poll() ?: if (logger.closed) { + break + } + else { + continue + } - writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """) - val message = entry.message - when (message) { - is CharSequence -> { - writer.write("\"${entry.marker}\": ") - writer.flush() + writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """) + val message = entry.message + when (message) { + is CharSequence -> { + writer.write("\"${entry.marker}\": ") + writer.flush() - if (message is JsonReaderEx.CharSequenceBackedByChars) { - fileChannel.write(message.byteBuffer) - } - else { - fileChannel.write(CharsetToolkit.UTF8_CHARSET.encode(CharBuffer.wrap(message))) - } - - writer.write("},\n") - writer.flush() + if (message is JsonReaderEx.CharSequenceBackedByChars) { + fileChannel.write(message.byteBuffer) } - is ByteBuf -> { - writer.write("\"${entry.marker}\": ") - writer.flush() - - message.getBytes(message.readerIndex(), out, message.readableBytes()) - message.release() - - writer.write("},\n") - writer.flush() + else { + fileChannel.write(CharsetToolkit.UTF8_CHARSET.encode(CharBuffer.wrap(message))) } - else -> throw RuntimeException("Unknown message type") + + writer.write("},\n") + writer.flush() } + is ByteBuf -> { + writer.write("\"${entry.marker}\": ") + writer.flush() + + message.getBytes(message.readerIndex(), out, message.readableBytes()) + message.release() + + writer.write("},\n") + writer.flush() + } + else -> throw RuntimeException("Unknown message type") } } - while (vm.isAttached) writer.write("]") out.close() } diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt index b8dd49b3e64d..1a3fb4226ae0 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ScopeVariablesGroup.kt @@ -43,8 +43,12 @@ class ScopeVariablesGroup(val scope: Scope, parentContext: VariableContext, call promise .done(node) { callFrame.receiverVariable - .done(node) { node.addChildren(if (it == null) XValueChildrenList.EMPTY else XValueChildrenList.singleton(VariableView(it, context)), true) } - .rejected(node) { node.addChildren(XValueChildrenList.EMPTY, true) } + .done(node) { + node.addChildren(if (it == null) XValueChildrenList.EMPTY else XValueChildrenList.singleton(VariableView(it, context)), true) + } + .rejected(node) { + node.addChildren(XValueChildrenList.EMPTY, true) + } } } } diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt index 62eac1928be2..55464c82ff98 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.kt @@ -47,7 +47,14 @@ fun processScopeVariables(scope: Scope, context: VariableContext, isLast: Boolean) = processVariables(context, scope.variablesHost.get(), node, { memberFilter, variables -> val additionalVariables = memberFilter.additionalVariables - val properties = ArrayList(variables.size + additionalVariables.size) + + val exceptionValue = context.viewSupport.vm?.suspendContextManager?.context?.exceptionData?.exceptionValue + val properties = ArrayList(variables.size + additionalVariables.size + (if (exceptionValue == null) 0 else 1)) + + exceptionValue?.let { + properties.add(VariableImpl("Exception", it)) + } + val functions = SmartList() for (variable in variables) { if (memberFilter.isMemberVisible(variable)) {