/**
* Copyright 2007-2015, Kaazing Corporation. All rights reserved.
*
* 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 org.kaazing.k3po.driver.internal.netty.bootstrap.agrona;
import static java.lang.Thread.currentThread;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.jboss.netty.channel.Channels.fireChannelConnected;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CountDownLatch;
import org.jboss.netty.channel.ChannelFuture;
import org.kaazing.k3po.driver.internal.netty.channel.agrona.AgronaChannelAddress;
import org.agrona.concurrent.BackoffIdleStrategy;
import org.agrona.concurrent.IdleStrategy;
public final class AgronaClientBoss implements Runnable {
private static final long MAX_PARK_NS = MILLISECONDS.toNanos(100L);
private static final long MIN_PARK_NS = MILLISECONDS.toNanos(1L);
private static final int MAX_YIELDS = 30;
private static final int MAX_SPINS = 20;
private final Deque<Runnable> taskQueue;
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
private volatile boolean shutdown;
AgronaClientBoss() {
this.taskQueue = new ConcurrentLinkedDeque<>();
}
public void connect(
final AgronaClientChannel channel,
final AgronaChannelAddress remoteAddress,
final ChannelFuture future) {
registerTask(new ConnectTask(channel, remoteAddress, future));
}
@Override
public void run() {
final IdleStrategy idleStrategy = new BackoffIdleStrategy(MAX_SPINS, MAX_YIELDS, MIN_PARK_NS, MAX_PARK_NS);
while (!shutdown) {
int workCount = 0;
workCount += executeTasks();
idleStrategy.idle(workCount);
}
shutdownLatch.countDown();
}
public void shutdown() {
shutdown = true;
try {
shutdownLatch.await();
} catch (InterruptedException e) {
currentThread().interrupt();
}
}
private int executeTasks() {
int workCount = 0;
Runnable task;
while ((task = taskQueue.poll()) != null) {
task.run();
workCount++;
}
return workCount;
}
private void registerTask(Runnable task) {
taskQueue.offer(task);
}
private static final class ConnectTask implements Runnable {
private final AgronaClientChannel clientChannel;
private final AgronaChannelAddress remoteAddress;
private final ChannelFuture connectFuture;
public ConnectTask(
AgronaClientChannel clientChannel,
AgronaChannelAddress remoteAddress,
ChannelFuture bindFuture) {
this.clientChannel = clientChannel;
this.connectFuture = bindFuture;
this.remoteAddress = remoteAddress;
}
@Override
public void run() {
clientChannel.setRemoteAddress(remoteAddress);
clientChannel.setConnected();
fireChannelConnected(clientChannel, clientChannel.getRemoteAddress());
connectFuture.setSuccess();
clientChannel.worker.register(clientChannel);
}
}
}