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

http://ambienttalk.googlecode.com/ · Java · 255 lines · 85 code · 32 blank · 138 comment · 2 complexity · 9c2bf96adc3e02dbc7ea6cf2e84e28d8 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. return future.get();
  159. }
  160. /**
  161. * When an event loop receives an asynchronously emitted event, this message is
  162. * immediately placed into its incoming event queue and will be processed later.
  163. * Using this method, events are scheduled first in the queue of upcoming events.
  164. *
  165. * This method is declared protected such that subclasses can provide a cleaner
  166. * interface as to what kind of events can be received by this event loop.
  167. * The convention is that this method is only used to put back events that could
  168. * not be processed due to problems outside of the influence of the interpreter
  169. * (e.g. host unreachability). If a subclass provides direct access to this
  170. * primitive it should do so in methods prefixed with prioritized_event_ which
  171. * call this protected method to schedule a certain event.
  172. */
  173. protected final void receivePrioritized(Event event) {
  174. eventQueue_.enqueueFirst(event);
  175. }
  176. /**
  177. * Subclasses are responsible for defining a meaningful implementation
  178. * strategy to handle events from the event queue.
  179. *
  180. * @param event the event object which was dequeued and which should be processed
  181. */
  182. public abstract void handle(Event event);
  183. protected final EventLoop owner() { return this; }
  184. /**
  185. * Invoked by the event processor thread continually while
  186. * the event loop is alive.
  187. *
  188. * The default behaviour is to continually dequeue events
  189. * and make a subclass handle the event.
  190. *
  191. * Overridable by subclasses to customize event processing.
  192. */
  193. protected void execute() {
  194. try {
  195. Event event = eventQueue_.dequeue();
  196. Logging.EventLoop_LOG.debug(owner() + " is processing " + event);
  197. handle(event);
  198. } catch (InterruptedException e) {
  199. // If interrupted, we may be asked to stop
  200. }
  201. }
  202. /**
  203. * EventProcessor is a thread subclass whose primary goal is to keep a reference to the
  204. * associated event loop, which is used to transform threads into the more manageable
  205. * event loops
  206. */
  207. public final class EventProcessor extends Thread {
  208. protected EventProcessor() {
  209. setName(toString());
  210. }
  211. protected EventLoop serving() { return owner(); }
  212. public final void run() {
  213. while(!askedToStop_) {
  214. execute();
  215. // give other event loops a chance to process an event
  216. Thread.yield();
  217. }
  218. }
  219. public String toString() {
  220. return "Event Loop " + serving().toString();
  221. }
  222. }
  223. }