/interpreter/tags/at2dist041108/src/edu/vub/at/actors/eventloops/EventLoop.java

http://ambienttalk.googlecode.com/ · Java · 273 lines · 89 code · 33 blank · 151 comment · 2 complexity · 6cbdd3755fde013ad916cbcebff0b729 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. */
  28. package edu.vub.at.actors.eventloops;
  29. import edu.vub.at.util.logging.Logging;
  30. /**
  31. * The EventLoop is the basic concurrency primitive for the AmbientTalk/2 implementation.
  32. * An Event Loop consists of an event queue, an event processing thread and an event handler.
  33. * The event loop's thread perpetually takes the next event from the event queue and makes
  34. * the event loop process it. Hence, the event loop is the event handler in this architecture.
  35. *
  36. * Event Loops form the reusable core of both actors, remote references and even the virtual machine
  37. * itself (i.e. it is the core of both programmer-defined and native actors).
  38. *
  39. * This is an abstract class. To be usable, subclasses have to provide a meaningful
  40. * implemementation strategy for handling events by overriding the handle method.
  41. *
  42. * @author tvcutsem
  43. * @author smostinc
  44. */
  45. public abstract class EventLoop {
  46. /**
  47. * The event loop's event queue is a synchronized queue of Event objects.
  48. * It is the sole communication channel between different event loops.
  49. * As such, it is the means by which different actors - and event actors and
  50. * their virtual machines - communicate.
  51. */
  52. protected final EventQueue eventQueue_;
  53. /**
  54. * Each event loop has an event processor, which is a thread responsible
  55. * for perpetually dequeuing events from the event queue and passing them
  56. * on to this event loop's handle method.
  57. */
  58. protected Thread processor_;
  59. protected volatile boolean askedToStop_;
  60. private final String name_;
  61. /**
  62. * Constructs a new event loop with the default processing behaviour.
  63. * @param name used for debugging purposes
  64. */
  65. public EventLoop(String name) {
  66. eventQueue_ = new EventQueue();
  67. askedToStop_ = false;
  68. name_ = name;
  69. processor_ = new EventProcessor();
  70. processor_.start();
  71. }
  72. public String toString() {
  73. return name_;
  74. }
  75. /**
  76. * Attempts to cast a {@link Thread} to an {@link EventLoop}. This code performs error checking and should
  77. * therefore be used whenever a Thread (typically the current thread) needs to be cast into
  78. * an EventLoop
  79. * @param t a Java Thread to be cast into an event loop
  80. * @return t as an EventLoop
  81. * @throws IllegalStateException when the cast failed.
  82. */
  83. public static EventLoop toEventLoop(Thread t) throws IllegalStateException {
  84. try {
  85. EventProcessor processor = (EventProcessor) t;
  86. return processor.serving();
  87. } catch (ClassCastException e) {
  88. e.printStackTrace();
  89. throw new IllegalStateException("Asked to transform a non-event loop thread to an event loop");
  90. }
  91. }
  92. /**
  93. * Allows access to the currently running event loop.
  94. * @return the currently serving event loop
  95. * @throws IllegalStateException if the current thread is not the thread of an event loop
  96. */
  97. public static EventLoop currentEventLoop() throws IllegalStateException {
  98. Thread current = Thread.currentThread();
  99. try {
  100. EventProcessor processor = (EventProcessor) current;
  101. return processor.serving();
  102. } catch (ClassCastException e) {
  103. throw new IllegalStateException("Asked for current event loop when none was active");
  104. }
  105. }
  106. /**
  107. * Method to interrupt the EventLoop before it starts processing its next event. Note that
  108. * this method consequently does not help when en event loop is stuck in an endless loop
  109. * while evaluating a single event.
  110. */
  111. public final void stopProcessing() {
  112. askedToStop_ = true;
  113. // explicitly interrupt my event processor because it
  114. // may be blocked waiting on other events
  115. processor_.interrupt();
  116. }
  117. /**
  118. * When an event loop receives an asynchronously emitted event, this message is
  119. * immediately placed into its incoming event queue and will be processed later.
  120. *
  121. * This method is declared protected such that subclasses can provide a cleaner
  122. * interface as to what kind of events can be received by this event loop.
  123. * The convention is that a subclass provides a number of methods prefixed with
  124. * event_ which call this protected method to schedule a certain event.
  125. */
  126. protected final void receive(Event event) {
  127. eventQueue_.enqueue(event);
  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. BlockingFuture future = new BlockingFuture();
  152. eventQueue_.enqueue(new FutureEvent(description, future) {
  153. private static final long serialVersionUID = 1672724382106164388L;
  154. public Object execute(Object owner) throws Exception {
  155. return callable.call(owner);
  156. }
  157. });*/
  158. BlockingFuture future = receiveAndReturnFuture(description, callable);
  159. return future.get();
  160. }
  161. protected final BlockingFuture receiveAndReturnFuture(String description, final Callable callable) throws Exception {
  162. if (Thread.currentThread() == processor_) {
  163. throw new RuntimeException("Potential deadlock detected: "
  164. + processor_ + " tried to perform a synchronous operation on itself");
  165. }
  166. BlockingFuture future = new BlockingFuture();
  167. eventQueue_.enqueue(new FutureEvent(description, future) {
  168. private static final long serialVersionUID = 1672724382106164388L;
  169. public Object execute(Object owner) throws Exception {
  170. return callable.call(owner);
  171. }
  172. });
  173. return future;
  174. }
  175. /**
  176. * When an event loop receives an asynchronously emitted event, this message is
  177. * immediately placed into its incoming event queue and will be processed later.
  178. * Using this method, events are scheduled first in the queue of upcoming events.
  179. *
  180. * This method is declared protected such that subclasses can provide a cleaner
  181. * interface as to what kind of events can be received by this event loop.
  182. * The convention is that this method is only used to put back events that could
  183. * not be processed due to problems outside of the influence of the interpreter
  184. * (e.g. host unreachability). If a subclass provides direct access to this
  185. * primitive it should do so in methods prefixed with prioritized_event_ which
  186. * call this protected method to schedule a certain event.
  187. */
  188. protected final void receivePrioritized(Event event) {
  189. eventQueue_.enqueueFirst(event);
  190. }
  191. /**
  192. * Subclasses are responsible for defining a meaningful implementation
  193. * strategy to handle events from the event queue.
  194. *
  195. * @param event the event object which was dequeued and which should be processed
  196. */
  197. public abstract void handle(Event event);
  198. protected final EventLoop owner() { return this; }
  199. /**
  200. * Invoked by the event processor thread continually while
  201. * the event loop is alive.
  202. *
  203. * The default behaviour is to continually dequeue events
  204. * and make a subclass handle the event.
  205. *
  206. * Overridable by subclasses to customize event processing.
  207. */
  208. protected void execute() {
  209. try {
  210. Event event = eventQueue_.dequeue();
  211. Logging.EventLoop_LOG.debug(owner() + " is processing " + event);
  212. handle(event);
  213. } catch (InterruptedException e) {
  214. // If interrupted, we may be asked to stop
  215. }
  216. }
  217. /**
  218. * EventProcessor is a thread subclass whose primary goal is to keep a reference to the
  219. * associated event loop, which is used to transform threads into the more manageable
  220. * event loops
  221. */
  222. public final class EventProcessor extends Thread {
  223. protected EventProcessor() {
  224. setName(toString());
  225. }
  226. protected EventLoop serving() { return owner(); }
  227. public final void run() {
  228. while(!askedToStop_) {
  229. execute();
  230. // give other event loops a chance to process an event
  231. Thread.yield();
  232. }
  233. }
  234. public String toString() {
  235. return "Event Loop " + serving().toString();
  236. }
  237. }
  238. }