PageRenderTime 29ms CodeModel.GetById 13ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
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}