1 module hunt.event.selector.Selector; 2 3 import hunt.Exceptions; 4 import hunt.Functions; 5 import hunt.io.channel.AbstractChannel; 6 import hunt.io.channel.Common; 7 import hunt.logging.ConsoleLogger; 8 9 import core.atomic; 10 import core.thread; 11 12 13 /** 14 http://tutorials.jenkov.com/java-nio/selectors.html 15 */ 16 abstract class Selector { 17 18 private shared bool _running = false; 19 private shared bool _isStopping = false; 20 private bool _isReady; 21 protected size_t number; 22 protected size_t divider; 23 protected AbstractChannel[] channels; 24 protected long idleTime = -1; // in millisecond 25 protected int fd; 26 27 private long timeout = -1; // in millisecond 28 private Thread _thread; 29 30 private SimpleEventHandler _startedHandler; 31 private SimpleEventHandler _stoppeddHandler; 32 33 this(size_t number, size_t divider, size_t maxChannels = 1500) { 34 this.number = number; 35 this.divider = divider; 36 channels = new AbstractChannel[maxChannels]; 37 } 38 39 size_t getId() { 40 return number; 41 } 42 43 bool isReady() { 44 return _isReady; 45 } 46 47 48 /** 49 * Tells whether or not this selector is running. 50 * 51 * @return <tt>true</tt> if, and only if, this selector is running 52 */ 53 bool isRuning() { 54 return _running; 55 } 56 57 alias isOpen = isRuning; 58 59 bool isStopping() { 60 return _isStopping; 61 } 62 63 64 abstract bool register(AbstractChannel channel); 65 66 abstract bool deregister(AbstractChannel channel); 67 68 bool update(AbstractChannel channel) { return true; } 69 70 protected abstract int doSelect(long timeout); 71 72 /** 73 timeout: in millisecond 74 */ 75 void run(long timeout = -1) { 76 this.timeout = timeout; 77 doRun(); 78 } 79 80 /** 81 timeout: in millisecond 82 */ 83 void runAsync(long timeout = -1, SimpleEventHandler handler = null) { 84 if(_running) { 85 version (HUNT_IO_DEBUG) warningf("The current selector %d has being running already!", number); 86 return; 87 } 88 this.timeout = timeout; 89 version (HUNT_IO_DEBUG) trace("runAsync ..."); 90 Thread th = new Thread(() { 91 try { 92 doRun(handler); 93 } catch (Throwable t) { 94 warning(t.msg); 95 version(HUNT_DEBUG) warning(t.toString()); 96 } 97 }); 98 // th.isDaemon = true; // unstable 99 th.start(); 100 } 101 102 private void doRun(SimpleEventHandler handler=null) { 103 if(cas(&_running, false, true)) { 104 version (HUNT_IO_DEBUG) trace("running selector..."); 105 _thread = Thread.getThis(); 106 if(handler !is null) { 107 handler(); 108 } 109 onLoop(timeout); 110 } else { 111 version (HUNT_DEBUG) warningf("The current selector %d has being running already!", number); 112 } 113 } 114 115 void stop() { 116 version (HUNT_IO_DEBUG) 117 tracef("Stopping selector %d. _running=%s, _isStopping=%s", number, _running, _isStopping); 118 if(cas(&_isStopping, false, true)) { 119 try { 120 onStop(); 121 } catch(Throwable t) { 122 warning(t.msg); 123 version(HUNT_DEBUG) warning(t); 124 } 125 } 126 } 127 128 protected void onStop() { 129 version (HUNT_IO_DEBUG) 130 tracef("stopping."); 131 } 132 133 /** 134 timeout: in millisecond 135 */ 136 protected void onLoop(long timeout = -1) { 137 _isReady = true; 138 idleTime = timeout; 139 140 do { 141 // version(HUNT_THREAD_DEBUG) warningf("Threads: %d", Thread.getAll().length); 142 doSelect(timeout); 143 // infof("Selector rolled once. isRuning: %s", isRuning); 144 } while (!_isStopping); 145 146 _isReady = false; 147 _running = false; 148 version(HUNT_DEBUG_MORE) infof("Selector %d exited.", number); 149 dispose(); 150 } 151 152 /** 153 timeout: in millisecond 154 */ 155 int select(long timeout) { 156 if (timeout < 0) 157 throw new IllegalArgumentException("Negative timeout"); 158 return doSelect((timeout == 0) ? -1 : timeout); 159 } 160 161 int select() { 162 return doSelect(0); 163 } 164 165 int selectNow() { 166 return doSelect(0); 167 } 168 169 void dispose() { 170 _thread = null; 171 _startedHandler = null; 172 _stoppeddHandler = null; 173 } 174 175 bool isSelfThread() { 176 return _thread is Thread.getThis(); 177 } 178 }