diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index ab24db83d126..2077b2ef985f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -84,7 +84,6 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.oio.OioEventLoopGroup; import io.netty.handler.codec.protobuf.ProtobufDecoder; import io.netty.handler.codec.protobuf.ProtobufEncoder; @@ -120,6 +119,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.intellij.util.io.NettyKt.MultiThreadEventLoopGroup; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; /** @@ -1397,7 +1397,7 @@ public class BuildManager implements Disposable { BuiltInServer mainServer = StartupUtil.getServer(); boolean isOwnEventLoopGroup = !Registry.is("compiler.shared.event.group", true) || mainServer == null || mainServer.getEventLoopGroup() instanceof OioEventLoopGroup; EventLoopGroup group = isOwnEventLoopGroup - ? new NioEventLoopGroup(1, ConcurrencyUtil.newNamedThreadFactory("External compiler")) + ? MultiThreadEventLoopGroup(1, ConcurrencyUtil.newNamedThreadFactory("External compiler")) : mainServer.getEventLoopGroup(); final ServerBootstrap bootstrap = NettyKt.serverBootstrap(group); bootstrap.childHandler(new ChannelInitializer() { diff --git a/platform/platform-impl/src/com/intellij/util/io/netty.kt b/platform/platform-impl/src/com/intellij/util/io/netty.kt index cb2c080c0f60..f53b3bb8688b 100644 --- a/platform/platform-impl/src/com/intellij/util/io/netty.kt +++ b/platform/platform-impl/src/com/intellij/util/io/netty.kt @@ -16,8 +16,11 @@ package com.intellij.util.io import com.google.common.net.InetAddresses +import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Conditions +import com.intellij.openapi.util.SystemInfo +import com.intellij.util.SystemProperties import com.intellij.util.Url import com.intellij.util.Urls import com.intellij.util.net.NetUtils @@ -26,6 +29,7 @@ import io.netty.bootstrap.BootstrapUtil import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBuf import io.netty.channel.* +import io.netty.channel.kqueue.KQueueEventLoopGroup import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.oio.OioEventLoopGroup import io.netty.channel.socket.nio.NioServerSocketChannel @@ -40,12 +44,14 @@ import io.netty.util.concurrent.GenericFutureListener import org.jetbrains.concurrency.AsyncPromise import org.jetbrains.concurrency.Promise import org.jetbrains.ide.PooledThreadExecutor +import org.jetbrains.io.BuiltInServer import org.jetbrains.io.NettyUtil import java.io.IOException import java.net.InetAddress import java.net.InetSocketAddress import java.net.NetworkInterface import java.net.Socket +import java.util.concurrent.ThreadFactory import java.util.concurrent.TimeUnit // used in Go @@ -304,4 +310,31 @@ fun HttpRequest.isWriteFromBrowserWithoutOrigin(): Boolean { fun ByteBuf.readUtf8() = toString(Charsets.UTF_8) -fun ByteBuf.writeUtf8(data: CharSequence) = writeCharSequence(data, Charsets.UTF_8) \ No newline at end of file +fun ByteBuf.writeUtf8(data: CharSequence) = writeCharSequence(data, Charsets.UTF_8) + +fun MultiThreadEventLoopGroup(workerCount: Int, threadFactory: ThreadFactory): MultithreadEventLoopGroup { + if (SystemInfo.isMacOSSierra && SystemProperties.getBooleanProperty("native.net.io", false)) { + try { + return KQueueEventLoopGroup(workerCount, threadFactory) + } + catch (e: Throwable) { + logger().warn("Cannot use native event loop group", e); + } + } + + return NioEventLoopGroup(workerCount, threadFactory) +} + +fun MultiThreadEventLoopGroup(workerCount: Int): MultithreadEventLoopGroup { + if (SystemInfo.isMacOSSierra && SystemProperties.getBooleanProperty("native.net.io", false)) { + try { + return KQueueEventLoopGroup(workerCount, PooledThreadExecutor.INSTANCE) + } + catch (e: Throwable) { + // error instead of warn to easy spot it + logger().error("Cannot use native event loop group", e); + } + } + + return NioEventLoopGroup(workerCount, PooledThreadExecutor.INSTANCE) +} \ No newline at end of file diff --git a/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java b/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java index 42687305ac43..f75ba8c9459d 100644 --- a/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java +++ b/platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java @@ -23,7 +23,6 @@ import com.intellij.util.NotNullProducer; import com.intellij.util.SystemProperties; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.oio.OioEventLoopGroup; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,6 +33,7 @@ import java.util.Random; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import static com.intellij.util.io.NettyKt.MultiThreadEventLoopGroup; import static com.intellij.util.io.NettyKt.serverBootstrap; public class BuiltInServer implements Disposable { @@ -84,7 +84,7 @@ public class BuiltInServer implements Disposable { int portsCount, boolean tryAnyPort, @Nullable NotNullProducer handler) throws Exception { - return start(new NioEventLoopGroup(workerCount, new BuiltInServerThreadFactory()), true, firstPort, portsCount, tryAnyPort, handler); + return start(MultiThreadEventLoopGroup(workerCount, new BuiltInServerThreadFactory()), true, firstPort, portsCount, tryAnyPort, handler); } @NotNull @@ -96,7 +96,7 @@ public class BuiltInServer implements Disposable { BuiltInServerThreadFactory threadFactory = new BuiltInServerThreadFactory(); EventLoopGroup loopGroup; try { - loopGroup = new NioEventLoopGroup(workerCount, threadFactory); + loopGroup = MultiThreadEventLoopGroup(workerCount, threadFactory); } catch (IllegalStateException e) { Logger.getInstance(BuiltInServer.class).warn(e); diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index 38a90eaeb9a8..9780eeace5df 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -16,9 +16,9 @@ package org.jetbrains.io; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.io.NettyKt; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObjectAggregator; @@ -31,7 +31,6 @@ import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; -import org.jetbrains.ide.PooledThreadExecutor; import java.io.IOException; import java.net.BindException; @@ -82,10 +81,12 @@ public final class NettyUtil { (message.startsWith("Connection reset") || message.equals("Operation timed out") || message.equals("Connection timed out")); } + @NotNull public static Bootstrap nioClientBootstrap() { - return nioClientBootstrap(new NioEventLoopGroup(1, PooledThreadExecutor.INSTANCE)); + return nioClientBootstrap(NettyKt.MultiThreadEventLoopGroup(2)); } + @NotNull public static Bootstrap nioClientBootstrap(@NotNull EventLoopGroup eventLoopGroup) { Bootstrap bootstrap = new Bootstrap().group(eventLoopGroup).channel(NioSocketChannel.class); bootstrap.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true);