/interpreter/tags/at2-build060407/src/edu/vub/at/actors/eventloops/EventLoop.java
Java | 229 lines | 83 code | 32 blank | 114 comment | 2 complexity | 8f049351b47103dbb1442c194c5087de MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * EventLoop.java created on 27-dec-2006 at 15:14:24 4 * (c) Programming Technology Lab, 2006 - 2007 5 * Authors: Tom Van Cutsem & Stijn Mostinckx 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, 11 * copy, modify, merge, publish, distribute, sublicense, and/or 12 * sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following 14 * conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28package edu.vub.at.actors.eventloops; 29 30import edu.vub.at.util.logging.Logging; 31 32 33 34/** 35 * The EventLoop is the basic concurrency primitive for the AmbientTalk/2 implementation. 36 * An Event Loop consists of an event queue, an event processing thread and an event handler. 37 * The event loop's thread perpetually takes the next event from the event queue and makes 38 * the event loop process it. Hence, the event loop is the event handler in this architecture. 39 * 40 * Event Loops form the reusable core of both actors, remote references and even the virtual machine 41 * itself (i.e. it is the core of both programmer-defined and native actors). 42 * 43 * This is an abstract class. To be usable, subclasses have to provide a meaningful 44 * implemementation strategy for handling events by overriding the handle method. 45 * 46 * @author tvcutsem 47 * @author smostinc 48 */ 49public abstract class EventLoop { 50 51 /** 52 * The event loop's event queue is a synchronized queue of Event objects. 53 * It is the sole communication channel between different event loops. 54 * As such, it is the means by which different actors - and event actors and 55 * their virtual machines - communicate. 56 */ 57 protected final EventQueue eventQueue_; 58 59 /** 60 * Each event loop has an event processor, which is a thread responsible 61 * for perpetually dequeuing events from the event queue and passing them 62 * on to this event loop's handle method. 63 */ 64 protected Thread processor_; 65 66 private boolean askedToStop_; 67 68 private final String name_; 69 70 /** 71 * Constructos a new event loop with the default processing behaviour. 72 * @param name used for debugging purposes 73 */ 74 public EventLoop(String name) { 75 eventQueue_ = new EventQueue(); 76 askedToStop_ = false; 77 name_ = name; 78 79 processor_ = new EventProcessor(); 80 processor_.start(); 81 } 82 83 public String toString() { 84 return name_; 85 } 86 87 public static EventLoop toEventLoop(Thread t) throws IllegalStateException { 88 try { 89 EventProcessor processor = (EventProcessor) t; 90 return processor.serving(); 91 } catch (ClassCastException e) { 92 e.printStackTrace(); 93 throw new IllegalStateException("Asked to transform a non-event loop thread to an event loop"); 94 } 95 } 96 97 /** 98 * Allows access to the currently running event loop. 99 * @return the currently serving event loop 100 * @throws IllegalStateException if the current thread is not the thread of an event loop 101 */ 102 public static EventLoop currentEventLoop() throws IllegalStateException { 103 Thread current = Thread.currentThread(); 104 try { 105 EventProcessor processor = (EventProcessor) current; 106 return processor.serving(); 107 } catch (ClassCastException e) { 108 throw new IllegalStateException("Asked for current event loop when none was active"); 109 } 110 } 111 112 public final void stopProcessing() { 113 askedToStop_ = true; 114 } 115 116 /** 117 * When an event loop receives an asynchronously emitted event, this message is 118 * immediately placed into its incoming event queue and will be processed later. 119 * 120 * This method is declared protected such that subclasses can provide a cleaner 121 * interface as to what kind of events can be received by this event loop. 122 * The convention is that a subclass provides a number of methods prefixed with 123 * event_ which call this protected method to schedule a certain event. 124 */ 125 protected final void receive(Event event) { 126 eventQueue_.enqueue(event); 127 } 128 129 /** 130 * Schedules an event in this event loop's queue which will execute the provided 131 * callable object at a later point in time. Moreover, this method immediately 132 * makes the calling thread WAIT for the return value or resulting exception 133 * of the callable. 134 * 135 * Caller must ensure that the thread invoking this method is not this event 136 * loop its own thread, which inevitably leads to deadlock. 137 * 138 * This method is declared protected such that subclasses can provide a cleaner 139 * interface as to what kind of tasks may be scheduled in this event loop. 140 * The convention is that a subclass provides a number of methods prefixed with 141 * sync_event_ which call this protected method to schedule a certain task. 142 * 143 * @param description a description of the task being scheduled, for debugging purposes 144 * @param callable the functor object encapsulating the task to be performed inside the event loop 145 */ 146 protected final Object receiveAndWait(String description, final Callable callable) throws Exception { 147 if (Thread.currentThread() == processor_) { 148 throw new RuntimeException("Potential deadlock detected: " 149 + processor_ + " tried to perform a synchronous operation on itself"); 150 } 151 152 BlockingFuture future = new BlockingFuture(); 153 eventQueue_.enqueue(new FutureEvent(description, future) { 154 public Object execute(Object owner) throws Exception { 155 return callable.call(owner); 156 } 157 }); 158 return future.get(); 159 } 160 161 /** 162 * When an event loop receives an asynchronously emitted event, this message is 163 * immediately placed into its incoming event queue and will be processed later. 164 * Using this method, events are scheduled first in the queue of upcoming events. 165 * 166 * This method is declared protected such that subclasses can provide a cleaner 167 * interface as to what kind of events can be received by this event loop. 168 * The convention is that this method is only used to put back events that could 169 * not be processed due to problems outside of the influence of the interpreter 170 * (e.g. host unreachability). If a subclass provides direct access to this 171 * primitive it should do so in methods prefixed with prioritized_event_ which 172 * call this protected method to schedule a certain event. 173 */ 174 protected final void receivePrioritized(Event event) { 175 eventQueue_.enqueueFirst(event); 176 } 177 178 /** 179 * Subclasses are responsible for defining a meaningful implementation 180 * strategy to handle events from the event queue. 181 * 182 * @param event the event object which was dequeued and which should be processed 183 */ 184 public abstract void handle(Event event); 185 186 protected final EventLoop owner() { return this; } 187 188 public void execute() { 189 try { 190 Event event = eventQueue_.dequeue(); 191 192 Logging.EventLoop_LOG.info(owner() + " is processing " + event); 193 194 handle(event); 195 } catch (InterruptedException e) { 196 // If interrupted, we may be asked to stop 197 } 198 } 199 200 201 /** 202 * EventProcessor is a thread subclass whose primary goal is to keep a reference to the 203 * associated event loop, which is used to transform threads into the more manageable 204 * event loops 205 */ 206 public final class EventProcessor extends Thread { 207 208 public EventProcessor() { 209 setName(toString()); 210 } 211 212 protected EventLoop serving() { return owner(); } 213 214 public final void run() { 215 while(!askedToStop_) { 216 execute(); 217 218 // give other event loops a chance to process an event 219 Thread.yield(); 220 } 221 } 222 223 public String toString() { 224 return "Event Loop " + serving().toString(); 225 } 226 227 } 228 229}