PageRenderTime 52ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/concurrent/dotnet/Future.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 207 lines | 142 code | 26 blank | 39 comment | 25 complexity | a85fff2338331d0b8a82d05a65b68337 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2009, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 30 Mar 09 Andy Frank Creation
  7. //
  8. using System.Collections;
  9. using System.Runtime.CompilerServices;
  10. using System.Threading;
  11. namespace Fan.Sys
  12. {
  13. /// <summary>
  14. /// Future is used to manage the entire lifecycle of each
  15. /// message send to an Actor. An actor's queue is a linked
  16. /// list of messages.
  17. /// </summary>
  18. public sealed class Future : FanObj
  19. {
  20. //////////////////////////////////////////////////////////////////////////
  21. // Construction
  22. //////////////////////////////////////////////////////////////////////////
  23. internal Future(object msg)
  24. {
  25. this.m_msg = msg;
  26. this.m_state = PENDING;
  27. }
  28. //////////////////////////////////////////////////////////////////////////
  29. // Obj
  30. //////////////////////////////////////////////////////////////////////////
  31. public override Type @typeof()
  32. {
  33. if (m_type == null) m_type = Type.find("concurrent::Future");
  34. return m_type;
  35. }
  36. private static Type m_type;
  37. //////////////////////////////////////////////////////////////////////////
  38. // Future
  39. //////////////////////////////////////////////////////////////////////////
  40. public bool isDone()
  41. {
  42. return (m_state & DONE) != 0;
  43. }
  44. public bool isCancelled()
  45. {
  46. return m_state == DONE_CANCEL;
  47. }
  48. public object get() { return get(null); }
  49. public object get(Duration timeout)
  50. {
  51. object r = null;
  52. try
  53. {
  54. lock (this)
  55. {
  56. // wait until we enter a done state, the only notifies
  57. // on this object should be from cancel, set, or err
  58. if (timeout == null)
  59. {
  60. // wait forever until done
  61. while ((m_state & DONE) == 0) Monitor.Wait(this);
  62. }
  63. else
  64. {
  65. // if not done, then wait with timeout and then
  66. // if still not done throw a timeout exception
  67. if ((m_state & DONE) == 0)
  68. {
  69. Monitor.Wait(this, (int)timeout.millis());
  70. if ((m_state & DONE) == 0) throw TimeoutErr.make("Future.get timed out").val;
  71. }
  72. }
  73. // if canceled throw CancelErr
  74. if (m_state == DONE_CANCEL)
  75. throw CancelledErr.make("message canceled").val;
  76. // if error was raised, raise it to caller
  77. if (m_state == DONE_ERR)
  78. throw ((Err)m_result).rebase();
  79. // assign result to local variable for return
  80. r = m_result;
  81. }
  82. }
  83. catch (ThreadInterruptedException e)
  84. {
  85. throw InterruptedErr.make(e).val;
  86. }
  87. // ensure immutable or safe copy
  88. return Sys.safe(r);
  89. }
  90. public void cancel()
  91. {
  92. ArrayList wd;
  93. lock (this)
  94. {
  95. if ((m_state & DONE) == 0) m_state = DONE_CANCEL;
  96. m_msg = m_result = null; // allow gc
  97. Monitor.PulseAll(this);
  98. wd = whenDone; whenDone = null;
  99. }
  100. sendWhenDone(wd);
  101. }
  102. internal void set(object r)
  103. {
  104. r = Sys.safe(r);
  105. ArrayList wd;
  106. lock (this)
  107. {
  108. m_state = DONE_OK;
  109. m_result = r;
  110. Monitor.PulseAll(this);
  111. wd = whenDone; whenDone = null;
  112. }
  113. sendWhenDone(wd);
  114. }
  115. internal void err(Err e)
  116. {
  117. ArrayList wd;
  118. lock (this)
  119. {
  120. m_state = DONE_ERR;
  121. m_result = e;
  122. Monitor.PulseAll(this);
  123. wd = whenDone; whenDone = null;
  124. }
  125. sendWhenDone(wd);
  126. }
  127. //////////////////////////////////////////////////////////////////////////
  128. // When Done
  129. //////////////////////////////////////////////////////////////////////////
  130. internal void sendWhenDone(Actor a, Future f)
  131. {
  132. // if already done, then set immediate flag
  133. // otherwise add to our when done list
  134. bool immediate = false;
  135. lock (this)
  136. {
  137. if (isDone()) immediate = true;
  138. else
  139. {
  140. if (whenDone == null) whenDone = new ArrayList();
  141. whenDone.Add(new WhenDone(a, f));
  142. }
  143. }
  144. // if immediate we are already done so enqueue immediately
  145. if (immediate)
  146. {
  147. try { a._enqueue(f, false); }
  148. catch (System.Exception e) { Err.dumpStack(e); }
  149. }
  150. }
  151. internal static void sendWhenDone(ArrayList list)
  152. {
  153. if (list == null) return;
  154. for (int i=0; i<list.Count; ++i)
  155. {
  156. WhenDone wd = (WhenDone)list[i];
  157. try { wd.actor._enqueue(wd.future, false); }
  158. catch (System.Exception e) { Err.dumpStack(e); }
  159. }
  160. }
  161. internal class WhenDone
  162. {
  163. public WhenDone(Actor a, Future f) { actor = a; future = f; }
  164. public Actor actor;
  165. public Future future;
  166. }
  167. //////////////////////////////////////////////////////////////////////////
  168. // Fields
  169. //////////////////////////////////////////////////////////////////////////
  170. const int PENDING = 0x00;
  171. const int DONE = 0x0f;
  172. const int DONE_CANCEL = 0x1f;
  173. const int DONE_OK = 0x2f;
  174. const int DONE_ERR = 0x4f;
  175. internal object m_msg; // message send to Actor
  176. internal Future m_next; // linked list in Actor
  177. private volatile int m_state; // processing state of message
  178. private object m_result; // result or exception of processing
  179. private ArrayList whenDone; // list of messages to deliver when done
  180. }
  181. }