fan-1.0 /src/concurrent/dotnet/Future.cs

Language C# Lines 207
MD5 Hash a85fff2338331d0b8a82d05a65b68337 Estimated Cost $3,480 (why?)
Repository https://bitbucket.org/bedlaczech/fan-1.0 View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//
// Copyright (c) 2009, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   30 Mar 09  Andy Frank  Creation
//

using System.Collections;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Fan.Sys
{
  /// <summary>
  /// Future is used to manage the entire lifecycle of each
  /// message send to an Actor.  An actor's queue is a linked
  /// list of messages.
  /// </summary>
  public sealed class Future : FanObj
  {

  //////////////////////////////////////////////////////////////////////////
  // Construction
  //////////////////////////////////////////////////////////////////////////

    internal Future(object msg)
    {
      this.m_msg   = msg;
      this.m_state = PENDING;
    }

  //////////////////////////////////////////////////////////////////////////
  // Obj
  //////////////////////////////////////////////////////////////////////////

    public override Type @typeof()
    {
      if (m_type == null) m_type = Type.find("concurrent::Future");
      return m_type;
    }
    private static Type m_type;

  //////////////////////////////////////////////////////////////////////////
  // Future
  //////////////////////////////////////////////////////////////////////////

    public bool isDone()
    {
      return (m_state & DONE) != 0;
    }

    public bool isCancelled()
    {
      return m_state == DONE_CANCEL;
    }

    public object get() { return get(null); }
    public object get(Duration timeout)
    {
      object r = null;
      try
      {
        lock (this)
        {
          // wait until we enter a done state, the only notifies
          // on this object should be from cancel, set, or err
          if (timeout == null)
          {
            // wait forever until done
            while ((m_state & DONE) == 0) Monitor.Wait(this);
          }
          else
          {
            // if not done, then wait with timeout and then
            // if still not done throw a timeout exception
            if ((m_state & DONE) == 0)
            {
              Monitor.Wait(this, (int)timeout.millis());
              if ((m_state & DONE) == 0) throw TimeoutErr.make("Future.get timed out").val;
            }
          }

          // if canceled throw CancelErr
          if (m_state == DONE_CANCEL)
            throw CancelledErr.make("message canceled").val;

          // if error was raised, raise it to caller
          if (m_state == DONE_ERR)
            throw ((Err)m_result).rebase();

          // assign result to local variable for return
          r = m_result;
        }
      }
      catch (ThreadInterruptedException e)
      {
        throw InterruptedErr.make(e).val;
      }

      // ensure immutable or safe copy
      return Sys.safe(r);
    }

    public void cancel()
    {
      ArrayList wd;
      lock (this)
      {
        if ((m_state & DONE) == 0) m_state = DONE_CANCEL;
        m_msg = m_result = null;  // allow gc
        Monitor.PulseAll(this);
        wd = whenDone; whenDone = null;
      }
      sendWhenDone(wd);
    }

    internal void set(object r)
    {
      r = Sys.safe(r);
      ArrayList wd;
      lock (this)
      {
        m_state = DONE_OK;
        m_result = r;
        Monitor.PulseAll(this);
        wd = whenDone; whenDone = null;
      }
      sendWhenDone(wd);
    }

    internal void err(Err e)
    {
      ArrayList wd;
      lock (this)
      {
        m_state = DONE_ERR;
        m_result = e;
        Monitor.PulseAll(this);
        wd = whenDone; whenDone = null;
      }
      sendWhenDone(wd);
    }

  //////////////////////////////////////////////////////////////////////////
  // When Done
  //////////////////////////////////////////////////////////////////////////

    internal void sendWhenDone(Actor a, Future f)
    {
      // if already done, then set immediate flag
      // otherwise add to our when done list
      bool immediate = false;
      lock (this)
      {
        if (isDone()) immediate = true;
        else
        {
          if (whenDone == null) whenDone = new ArrayList();
          whenDone.Add(new WhenDone(a, f));
        }
      }

      // if immediate we are already done so enqueue immediately
      if (immediate)
      {
        try { a._enqueue(f, false); }
        catch (System.Exception e) { Err.dumpStack(e); }
      }
    }

    internal static void sendWhenDone(ArrayList list)
    {
      if (list == null) return;
      for (int i=0; i<list.Count; ++i)
      {
        WhenDone wd = (WhenDone)list[i];
        try { wd.actor._enqueue(wd.future, false); }
        catch (System.Exception e) { Err.dumpStack(e); }
      }
    }

    internal class WhenDone
    {
      public WhenDone(Actor a, Future f) { actor = a; future = f; }
      public Actor actor;
      public Future future;
    }

  //////////////////////////////////////////////////////////////////////////
  // Fields
  //////////////////////////////////////////////////////////////////////////

    const int PENDING     = 0x00;
    const int DONE        = 0x0f;
    const int DONE_CANCEL = 0x1f;
    const int DONE_OK     = 0x2f;
    const int DONE_ERR    = 0x4f;

    internal object m_msg;         // message send to Actor
    internal Future m_next;        // linked list in Actor
    private volatile int m_state;  // processing state of message
    private object m_result;       // result or exception of processing
    private ArrayList whenDone;    // list of messages to deliver when done

  }
}
Back to Top