com.firenio.component.NioEventLoop Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of firenio-all Show documentation
Show all versions of firenio-all Show documentation
The all in one project of firenio
/*
* Copyright 2015 The FireNio Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.firenio.component;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import com.firenio.Develop;
import com.firenio.Options;
import com.firenio.buffer.ByteBuf;
import com.firenio.buffer.ByteBufAllocator;
import com.firenio.collection.ArrayListStack;
import com.firenio.collection.DelayedQueue;
import com.firenio.collection.IntArray;
import com.firenio.collection.IntMap;
import com.firenio.collection.LinkedBQStack;
import com.firenio.collection.Stack;
import com.firenio.common.ByteUtil;
import com.firenio.common.Unsafe;
import com.firenio.common.Util;
import com.firenio.component.Channel.EpollChannel;
import com.firenio.component.Channel.JavaChannel;
import com.firenio.component.ChannelConnector.EpollConnectorUnsafe;
import com.firenio.component.ChannelConnector.JavaConnectorUnsafe;
import com.firenio.concurrent.AtomicArray;
import com.firenio.concurrent.EventLoop;
import com.firenio.log.Logger;
import com.firenio.log.LoggerFactory;
import static com.firenio.Develop.debugException;
/**
* @author wangkai
*/
public abstract class NioEventLoop extends EventLoop {
static final boolean CHANNEL_READ_FIRST = Options.isChannelReadFirst();
static final Logger logger = NEW_LOGGER();
static final IOException NOT_FINISH_CONNECT = NOT_FINISH_CONNECT();
static final IOException OVER_CH_SIZE_LIMIT = OVER_CH_SIZE_LIMIT();
static final AtomicInteger ATTRIBUTE_KEYS = new AtomicInteger();
// NOTICE USE_HAS_TASK can make a memory barrier for io thread,
// please do not change this value to false unless you are really need.
// I am not sure if the select()/select(n) has memory barrier,
// it can be set USE_HAS_TASK to false if there is a memory barrier.
static final boolean USE_HAS_TASK = true;
final ByteBufAllocator alloc;
final ByteBuf buf;
final IntMap channels = new IntMap<>(4096);
final IntArray close_channels = new IntArray();
final int ch_size_limit;
final DelayedQueue delayed_queue = new DelayedQueue();
final BlockingQueue events = new LinkedBlockingQueue<>();
final AtomicArray attributes = new AtomicArray();
final NioEventLoopGroup group;
final int index;
final AtomicInteger selecting = new AtomicInteger();
final boolean sharable;
final long buf_address;
final boolean acceptor;
volatile boolean has_task = false;
NioEventLoop(NioEventLoopGroup group, int index, String threadName) {
super(threadName);
this.index = index;
this.group = group;
this.sharable = group.isSharable();
this.acceptor = group.isAcceptor();
this.alloc = group.getByteBufAllocator(index);
this.ch_size_limit = group.getChannelSizeLimit();
int channelReadBuffer = group.getChannelReadBuffer();
if (channelReadBuffer > 0) {
this.buf = ByteBuf.buffer(channelReadBuffer);
this.buf_address = buf.address();
} else {
this.buf = null;
this.buf_address = -1;
}
}
private static void channel_idle(ChannelIdleListener l, Channel ch, long lastIdleTime) {
try {
l.channelIdled(ch, lastIdleTime);
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
private static void channel_idle(ChannelContext context, IntMap channels, long last_idle_time) {
List ls = context.getChannelIdleEventListeners();
for (int i = 0; i < ls.size(); i++) {
ChannelIdleListener l = ls.get(i);
for (channels.scan(); channels.hasNext(); ) {
Channel ch = channels.value();
channel_idle(l, ch, last_idle_time);
}
}
}
private static void channel_idle_share(IntMap channels, long last_idle_time) {
for (channels.scan(); channels.hasNext(); ) {
Channel ch = channels.value();
ChannelContext context = ch.getContext();
List ls = context.getChannelIdleEventListeners();
if (ls.size() == 1) {
channel_idle(ls.get(0), ch, last_idle_time);
} else {
for (int i = 0; i < ls.size(); i++) {
channel_idle(ls.get(i), ch, last_idle_time);
}
}
}
}
static void register_ch(ChannelContext ctx, int fd, IntMap channels, Channel ch) {
channels.put(fd, ch);
if (ch.isEnableSsl()) {
// fire open event later
if (ctx.getSslContext().isClient()) {
ch.writeAndFlush(ByteBuf.empty());
}
} else {
// fire open event immediately when plain ch
ch.fire_opened();
ctx.channelEstablish(ch, null);
}
}
private static Logger NEW_LOGGER() {
return LoggerFactory.getLogger(NioEventLoop.class);
}
static IOException NOT_FINISH_CONNECT() {
return Util.unknownStackTrace(new IOException("not finish connect"), SocketChannel.class, "finishConnect(...)");
}
static IOException OVER_CH_SIZE_LIMIT() {
return Util.unknownStackTrace(new IOException("over channel size writeIndex"), NioEventLoop.class, "register_channel(...)");
}
static void read_exception_caught(Channel ch, Throwable ex) {
ch.close();
if (!ch.isSslHandshakeFinished()) {
ch.getContext().channelEstablish(ch, ex);
}
logger.error(ex);
}
public static int nextAttributeKey() {
return ATTRIBUTE_KEYS.getAndIncrement();
}
public ByteBufAllocator alloc() {
return alloc;
}
//FIXME ..optimize sharable group
private void channel_idle(long last_idle_time) {
IntMap channels = this.channels;
if (channels.isEmpty()) {
return;
}
if (sharable) {
channel_idle_share(channels, last_idle_time);
} else {
channel_idle(group.getContext(), channels, last_idle_time);
}
}
private void close_channels() {
IntMap channels = this.channels;
for (channels.scan(); channels.hasNext(); ) {
Util.close(channels.value());
}
}
protected long getBufAddress() {
return buf_address;
}
public Channel getChannel(int channelId) {
return channels.get(channelId);
}
private Stack