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

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