/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. */
  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. private boolean askedToStop_;
  60. private final String name_;
  61. /**
  62. * Constructos 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. public static EventLoop toEventLoop(Thread t) throws IllegalStateException {
  76. try {
  77. EventProcessor processor = (EventProcessor) t;
  78. return processor.serving();
  79. } catch (ClassCastException e) {
  80. e.printStackTrace();
  81. throw new IllegalStateException("Asked to transform a non-event loop thread to an event loop");
  82. }
  83. }
  84. /**
  85. * Allows access to the currently running event loop.
  86. * @return the currently serving event loop
  87. * @throws IllegalStateException if the current thread is not the thread of an event loop
  88. */
  89. public static EventLoop currentEventLoop() throws IllegalStateException {
  90. Thread current = Thread.currentThread();
  91. try {
  92. EventProcessor processor = (EventProcessor) current;
  93. return processor.serving();
  94. } catch (ClassCastException e) {
  95. throw new IllegalStateException("Asked for current event loop when none was active");
  96. }
  97. }
  98. public final void stopProcessing() {
  99. askedToStop_ = true;
  100. }
  101. /**
  102. * When an event loop receives an asynchronously emitted event, this message is
  103. * immediately placed into its incoming event queue and will be processed later.
  104. *
  105. * This method is declared protected such that subclasses can provide a cleaner
  106. * interface as to what kind of events can be received by this event loop.
  107. * The convention is that a subclass provides a number of methods prefixed with
  108. * event_ which call this protected method to schedule a certain event.
  109. */
  110. protected final void receive(Event event) {
  111. eventQueue_.enqueue(event);
  112. }
  113. /**
  114. * Schedules an event in this event loop's queue which will execute the provided
  115. * callable object at a later point in time. Moreover, this method immediately
  116. * makes the calling thread WAIT for the return value or resulting exception
  117. * of the callable.
  118. *
  119. * Caller must ensure that the thread invoking this method is not this event
  120. * loop its own thread, which inevitably leads to deadlock.
  121. *
  122. * This method is declared protected such that subclasses can provide a cleaner
  123. * interface as to what kind of tasks may be scheduled in this event loop.
  124. * The convention is that a subclass provides a number of methods prefixed with
  125. * sync_event_ which call this protected method to schedule a certain task.
  126. *
  127. * @param description a description of the task being scheduled, for debugging purposes
  128. * @param callable the functor object encapsulating the task to be performed inside the event loop
  129. */
  130. protected final Object receiveAndWait(String description, final Callable callable) throws Exception {
  131. if (Thread.currentThread() == processor_) {
  132. throw new RuntimeException("Potential deadlock detected: "
  133. + processor_ + " tried to perform a synchronous operation on itself");
  134. }
  135. BlockingFuture future = new BlockingFuture();
  136. eventQueue_.enqueue(new FutureEvent(description, future) {
  137. public Object execute(Object owner) throws Exception {
  138. return callable.call(owner);
  139. }
  140. });
  141. return future.get();
  142. }
  143. /**
  144. * When an event loop receives an asynchronously emitted event, this message is
  145. * immediately placed into its incoming event queue and will be processed later.
  146. * Using this method, events are scheduled first in the queue of upcoming events.
  147. *
  148. * This method is declared protected such that subclasses can provide a cleaner
  149. * interface as to what kind of events can be received by this event loop.
  150. * The convention is that this method is only used to put back events that could
  151. * not be processed due to problems outside of the influence of the interpreter
  152. * (e.g. host unreachability). If a subclass provides direct access to this
  153. * primitive it should do so in methods prefixed with prioritized_event_ which
  154. * call this protected method to schedule a certain event.
  155. */
  156. protected final void receivePrioritized(Event event) {
  157. eventQueue_.enqueueFirst(event);
  158. }
  159. /**
  160. * Subclasses are responsible for defining a meaningful implementation
  161. * strategy to handle events from the event queue.
  162. *
  163. * @param event the event object which was dequeued and which should be processed
  164. */
  165. public abstract void handle(Event event);
  166. protected final EventLoop owner() { return this; }
  167. public void execute() {
  168. try {
  169. Event event = eventQueue_.dequeue();
  170. Logging.EventLoop_LOG.info(owner() + " is processing " + event);
  171. handle(event);
  172. } catch (InterruptedException e) {
  173. // If interrupted, we may be asked to stop
  174. }
  175. }
  176. /**
  177. * EventProcessor is a thread subclass whose primary goal is to keep a reference to the
  178. * associated event loop, which is used to transform threads into the more manageable
  179. * event loops
  180. */
  181. public final class EventProcessor extends Thread {
  182. public EventProcessor() {
  183. setName(toString());
  184. }
  185. protected EventLoop serving() { return owner(); }
  186. public final void run() {
  187. while(!askedToStop_) {
  188. execute();
  189. // give other event loops a chance to process an event
  190. Thread.yield();
  191. }
  192. }
  193. public String toString() {
  194. return "Event Loop " + serving().toString();
  195. }
  196. }
  197. }