Package erjang.driver

Source Code of erjang.driver.NIOSelector$SelectMsg

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang.driver;

import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import erjang.driver.NIOChannelInfo.Interest;

/**
*
*/
public class NIOSelector extends Thread {
  static Logger log = Logger.getLogger("erjang.driver");

  static final NIOSelector INSTANCE = new NIOSelector();
  private Selector selector;

  public NIOSelector() {
    setDaemon(true);
    try {
      selector = Selector.open();
    } catch (IOException e) {
      e.printStackTrace();
    }
    start();
  }

  static public SelectionKey interest(SelectableChannel ch) {
    return ch.keyFor(INSTANCE.selector);
  }
 
  static enum SetOrClear {
    SET, CLEAR;
  }
 
  static class SelectMsg {
    SetOrClear set;
    NIOChannelInfo.Interest interest;   
  }
 
  ArrayBlockingQueue<SelectMsg> mbox = new ArrayBlockingQueue<SelectMsg>(2);

  @Override
  public void run() {
    try {
      run0();
    } catch (Throwable e) {
      System.err.println("Exception in select loop");
      System.err.println("Exception in select loop: " + e.getClass());
      System.err.println("Exception in select loop: " + e);
      log.severe("unhandled exception in Select loop: " +e);
      log.severe("unhandled exception in Select loop: " +e.getMessage());
      e.printStackTrace(System.err);
      log.log(Level.FINE, "details: ", e);
    }
  }

  public void run0() {
    // List<NIOChannelInfo> cancellations = new ArrayList<NIOChannelInfo>();

    select_loop: while (true) {

      SelectMsg msg;
      msg_loop: while ((msg = mbox.poll()) != null) {
       
        // System.err.println("SELECT_MSG: "+msg.set+" >> "+msg.interest);
       
        if (msg.set == SetOrClear.SET) {
          process_add_interest_request(msg.interest);
        } else {
          process_clear_interest_request(msg.interest);
         
          try {
            selector.selectNow();
          } catch (IOException e) {
            e.printStackTrace();
            // xx //
          }
        }
       
      }
     
     
      int num;

        if (false) {
          log.fine("select loop");
         
          for (SelectionKey key : selector.keys()) {
            if (key.isValid()) {
             
              SelectableChannel ch = key.channel();
              int interst = key.interestOps();
              if (log.isLoggable(Level.FINE)) log.fine(Integer.toBinaryString(interst) + ":"  + ch);
             
            }
          }
        }
       
       
        try {
          num = selector.select(10000);
        } catch (CancelledKeyException e) {
          // ignore this, as per
          // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4729342

        } catch (ClosedSelectorException e) {
          e.printStackTrace();
          return;
        } catch (IOException e) {
          e.printStackTrace();
        }


      // now, process the readyset

      Set<SelectionKey> ready = selector.selectedKeys();

      for (SelectionKey key : ready) {
        // System.err.println("READY: "+key.channel()+":"+Integer.toBinaryString(key.readyOps()));
       
        NIOChannelInfo req = (NIOChannelInfo) key.attachment();
        if (req == null) {
          log.severe("Internal error, SelectionKey's attachement is null");
        } else {
          req.ready(key);
        }
      }

    }

  }

  /**
   * @param remove
   * @param cancellations
   */
  private void process_clear_interest_request(Interest interest) {

    SelectableChannel ch = interest.ch;
    SelectionKey key = ch.keyFor(selector);
    NIOHandler handler = interest.handler;

    if (key == null || !key.isValid()) {
     
      // TODO: maybe this should be considered an error?
      if (handler != null && interest.releaseNotify) {
        handler.released(ch);
      }
     
    } else {
     
      // get channel info
      NIOChannelInfo info = (NIOChannelInfo) key.attachment();
     
      if (info == null) {
        // error!
        throw new InternalError();
      }
     
      // tell info that we're note interested in this
      info.clear_interest(interest);
     
      // does that add up to, that we are not interested at all?
      if (info.updateInterestOpsFor(key) == 0) {
       
        // cancel the key
        key.cancel();
       
      }
    }
   
  }

  /**
   * @param remove
   * @param active2
   */
  private void process_add_interest_request(Interest interest) {
    SelectableChannel ch = interest.ch;
    SelectionKey key = ch.keyFor(selector);
    NIOChannelInfo info = null;
   
    if (key != null && !key.isValid()) {
      try {
        selector.selectNow();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      key = null;
    }
    if (key == null || !key.isValid()) {
      try {
        key = ch.register(selector, interest.ops,
            info = new NIOChannelInfo(interest));
      } catch (ClosedChannelException e) {
        interest.handler.exception(ch, e);
      }
    } else {
      info = (NIOChannelInfo) key.attachment();
      info.add(interest);
      info.updateInterestOpsFor(key);
    }
   
  }
 
  static public void setInterest(SelectableChannel ch, int op,
      NIOHandler handler) {
    INSTANCE._addInterest(ch, op, handler);
  }

  void _addInterest(SelectableChannel ch, int op,
      NIOHandler handler) {
    SelectMsg msg = new SelectMsg();
    msg.set = SetOrClear.SET;
    msg.interest = new NIOChannelInfo.Interest(ch, handler, op, false);
    try {
      // System.err.println("SELECT_MSG: "+msg.set+" ++>> "+msg.interest);

      mbox.put(msg);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    selector.wakeup();
  }
 
  static public void clearInterest(SelectableChannel ch, int op, boolean releaseNotify,
      NIOHandler handler) {
    INSTANCE._removeInterest(ch, op, releaseNotify, handler);
  }

  void _removeInterest(SelectableChannel ch, int op, boolean releaseNotify,
      NIOHandler handler) {
    SelectMsg msg = new SelectMsg();
    msg.set = SetOrClear.CLEAR;
    msg.interest = new NIOChannelInfo.Interest(ch, handler, op, releaseNotify);
    try {
      // System.err.println("SELECT_MSG: "+msg.set+" ++>> "+msg.interest);

      mbox.put(msg);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    selector.wakeup();
  }

}
TOP

Related Classes of erjang.driver.NIOSelector$SelectMsg

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.