PageRenderTime 42ms CodeModel.GetById 19ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2-build190607/src/edu/vub/at/actors/eventloops/EventLoop.java

http://ambienttalk.googlecode.com/
Java | 253 lines | 84 code | 31 blank | 138 comment | 2 complexity | 99f771f8d304da3f6c9f304ec50489f9 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	protected volatile 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	/**
 88	 * Attempts to cast a {@link Thread} to an {@link EventLoop}. This code performs error checking and should
 89	 * therefore be used whenever a Thread (typically the current thread) needs to be cast into
 90	 * an EventLoop
 91	 * @param t a Java Thread to be cast into an event loop
 92	 * @return t as an EventLoop
 93	 * @throws IllegalStateException when the cast failed.
 94	 */
 95	public static EventLoop toEventLoop(Thread t) throws IllegalStateException {
 96		try {
 97		  EventProcessor processor = (EventProcessor) t;
 98	      return processor.serving();
 99		} catch (ClassCastException e) {
100			e.printStackTrace();
101			throw new IllegalStateException("Asked to transform a non-event loop thread to an event loop");
102		}
103	}
104	
105	/**
106	 * Allows access to the currently running event loop.
107	 * @return the currently serving event loop
108	 * @throws IllegalStateException if the current thread is not the thread of an event loop
109	 */
110	public static EventLoop currentEventLoop() throws IllegalStateException {
111		Thread current = Thread.currentThread();
112		try {
113		  EventProcessor processor = (EventProcessor) current;
114	      return processor.serving();
115		} catch (ClassCastException e) {
116			throw new IllegalStateException("Asked for current event loop when none was active");
117		}
118	}
119	
120	/**
121	 * Method to interrupt the EventLoop before it starts processing its next event. Note that
122	 * this method consequently does not help when en event loop is stuck in an endless loop
123	 * while evaluating a single event.
124	 */
125	public final void stopProcessing() {
126		askedToStop_ = true;
127		// explicitly interrupt my event processor because it
128		// may be blocked waiting on other events
129		processor_.interrupt();
130	}
131	
132	/**
133	 * When an event loop receives an asynchronously emitted event, this message is
134	 * immediately placed into its incoming event queue and will be processed later.
135	 * 
136	 * This method is declared protected such that subclasses can provide a cleaner
137	 * interface as to what kind of events can be received by this event loop.
138	 * The convention is that a subclass provides a number of methods prefixed with
139	 * event_ which call this protected method to schedule a certain event.
140	 */
141	protected final void receive(Event event) {
142		eventQueue_.enqueue(event);
143	}
144	
145	/**
146	 * Schedules an event in this event loop's queue which will execute the provided
147	 * callable object at a later point in time. Moreover, this method immediately
148	 * makes the calling thread WAIT for the return value or resulting exception
149	 * of the callable.
150	 * 
151	 * Caller must ensure that the thread invoking this method is not this event
152	 * loop its own thread, which inevitably leads to deadlock.
153	 * 
154	 * This method is declared protected such that subclasses can provide a cleaner
155	 * interface as to what kind of tasks may be scheduled in this event loop.
156	 * The convention is that a subclass provides a number of methods prefixed with
157	 * sync_event_ which call this protected method to schedule a certain task.
158	 * 
159	 * @param description a description of the task being scheduled, for debugging purposes
160	 * @param callable the functor object encapsulating the task to be performed inside the event loop
161	 */
162	protected final Object receiveAndWait(String description, final Callable callable) throws Exception {
163		if (Thread.currentThread() == processor_) {
164			throw new RuntimeException("Potential deadlock detected: "
165					+ processor_ + " tried to perform a synchronous operation on itself");
166		}
167		
168		BlockingFuture future = new BlockingFuture();
169		eventQueue_.enqueue(new FutureEvent(description, future) {
170			public Object execute(Object owner) throws Exception {
171				return callable.call(owner);
172			}
173		});
174		return future.get();
175	}
176	
177	/**
178	 * When an event loop receives an asynchronously emitted event, this message is
179	 * immediately placed into its incoming event queue and will be processed later.
180	 * Using this method, events are scheduled first in the queue of upcoming events.
181	 * 
182	 * This method is declared protected such that subclasses can provide a cleaner
183	 * interface as to what kind of events can be received by this event loop.
184	 * The convention is that this method is only used to put back events that could
185	 * not be processed due to problems outside of the influence of the interpreter 
186	 * (e.g. host unreachability). If a subclass provides direct access to this 
187	 * primitive it should do so in methods prefixed with prioritized_event_ which 
188	 * call this protected method to schedule a certain event.
189	 */
190	protected final void receivePrioritized(Event event) {
191		eventQueue_.enqueueFirst(event);
192	}
193	
194	/**
195	 * Subclasses are responsible for defining a meaningful implementation
196	 * strategy to handle events from the event queue.
197	 * 
198	 * @param event the event object which was dequeued and which should be processed
199	 */
200	public abstract void handle(Event event);
201	
202	protected final EventLoop owner() { return this; }
203	
204	/**
205	 * Invoked by the event processor thread continually while
206	 * the event loop is alive.
207	 * 
208	 * The default behaviour is to continually dequeue events
209	 * and make a subclass handle the event.
210	 * 
211	 * Overridable by subclasses to customize event processing.
212	 */
213	protected void execute() {
214		try {
215			Event event = eventQueue_.dequeue();
216
217			Logging.EventLoop_LOG.info(owner() + " is processing " + event);
218
219			handle(event);
220		} catch (InterruptedException e) {
221			// If interrupted, we may be asked to stop
222		}
223	}
224	
225	/**
226	 * EventProcessor is a thread subclass whose primary goal is to keep a reference to the 
227	 * associated event loop, which is used to transform threads into the more manageable 
228	 * event loops
229	 */
230	public final class EventProcessor extends Thread {
231		
232		protected EventProcessor() {
233			setName(toString());
234		}
235		
236        protected EventLoop serving() { return owner(); }
237		
238		public final void run() {
239			while(!askedToStop_) {
240				execute();
241				
242				// give other event loops a chance to process an event
243				Thread.yield();
244			}
245		}
246        
247		public String toString() {
248			return "Event Loop " + serving().toString();
249		}
250		
251	}
252	
253}