Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.0.7/SimSharp-3.0.7/Core/Events/Process.cs @ 14185

Last change on this file since 14185 was 14185, checked in by swagner, 8 years ago

#2526: Updated year of copyrights in license headers

File size: 6.3 KB
Line 
1#region License Information
2/* SimSharp - A .NET port of SimPy, discrete event simulation framework
3Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
17#endregion
18
19using System;
20using System.Collections.Generic;
21
22namespace SimSharp {
23  /// <summary>
24  /// A Process handles the iteration of events. Processes may define steps that
25  /// a certain entity in the simulation has to perform. Each time the process
26  /// should wait it yields an event and will be resumed when that event is processed.
27  /// </summary>
28  /// <remarks>
29  /// Since an iterator method does not have access to its process, the method can
30  /// retrieve the associated Process through the ActiveProcess property of the
31  /// environment. Each Process sets and resets that property during Resume.
32  /// </remarks>
33  public class Process : Event {
34    private readonly IEnumerator<Event> generator;
35    private Event target;
36    /// <summary>
37    /// Target is the event that is expected to be executed next in the process.
38    /// </summary>
39    public Event Target {
40      get { return target; }
41      protected set { target = value; }
42    }
43
44    public Process(Environment environment, IEnumerable<Event> generator)
45      : base(environment) {
46      this.generator = generator.GetEnumerator();
47      IsOk = true;
48      target = new Initialize(environment, this);
49    }
50
51    /// <summary>
52    /// This interrupts a process and causes the IsOk flag to be set to false.
53    /// If a process is interrupted the iterator method needs to call HandleFault()
54    /// before continuing to yield further events.
55    /// </summary>
56    /// <exception cref="InvalidOperationException">This is thrown in three conditions:
57    ///  - If the process has already been triggered.
58    ///  - If the process attempts to interrupt itself.
59    ///  - If the process continues to yield events despite being faulted.</exception>
60    /// <param name="cause">The cause of the interrupt.</param>
61    public virtual void Interrupt(object cause = null) {
62      if (IsTriggered) throw new InvalidOperationException("The process has terminated and cannot be interrupted.");
63      if (Environment.ActiveProcess == this) throw new InvalidOperationException("A process is not allowed to interrupt itself.");
64
65      var interruptEvent = new Event(Environment);
66      interruptEvent.AddCallback(Resume);
67      interruptEvent.Fail(cause);
68
69      if (Target != null)
70        Target.RemoveCallback(Resume);
71    }
72
73    protected virtual void Resume(Event @event) {
74      Environment.ActiveProcess = this;
75      while (true) {
76        if (@event.IsOk) {
77          if (generator.MoveNext()) {
78            if (IsTriggered) {
79              // the generator called e.g. Environment.ActiveProcess.Fail
80              Environment.ActiveProcess = null;
81              return;
82            }
83            if (ProceedToEvent()) break;
84          } else if (!IsTriggered) {
85            Succeed(@event.Value);
86            break;
87          } else break;
88        } else {
89          /* Fault handling differs from SimPy as in .NET it is not possible to inject an
90         * exception into an enumerator and it is impossible to put a yield return inside
91         * a try-catch block. In SimSharp the Process will set IsOk and will then move to
92         * the next yield in the generator. However, if after this move IsOk is still false
93         * we know that the error was not handled. It is assumed the error is handled if
94         * HandleFault() is called on the environment's ActiveProcess which will reset the
95         * flag. */
96          IsOk = false;
97          Value = @event.Value;
98
99          if (generator.MoveNext()) {
100            if (IsTriggered) {
101              // the generator called e.g. Environment.ActiveProcess.Fail
102              Environment.ActiveProcess = null;
103              return;
104            }
105            // if we move next, but IsOk is still false
106            if (!IsOk) throw new InvalidOperationException("The process did not react to being faulted.");
107            // otherwise HandleFault was called and the fault was handled
108            if (ProceedToEvent()) break;
109          } else if (!IsTriggered) {
110            if (!IsOk) Fail(@event.Value);
111            else Succeed(@event.Value);
112            break;
113          } else break;
114        }
115      }
116      Environment.ActiveProcess = null;
117    }
118
119    protected virtual bool ProceedToEvent() {
120      target = generator.Current;
121      Value = target.Value;
122      if (target.IsProcessed) return false;
123      target.AddCallback(Resume);
124      return true;
125    }
126
127    /// <summary>
128    /// This method must be called to reset the IsOk flag of the process back to true.
129    /// The IsOk flag may be set to false if the process waited on an event that failed.
130    /// </summary>
131    /// <remarks>
132    /// In SimPy a faulting process would throw an exception which is then catched and
133    /// chained. In SimSharp catching exceptions from a yield is not possible as a yield
134    /// return statement may not throw an exception.
135    /// If a processes faulted the Value property may indicate a cause for the fault.
136    /// </remarks>
137    /// <returns>True if a faulting situation needs to be handled, false if the process
138    /// is okay and the last yielded event succeeded.</returns>
139    public virtual bool HandleFault() {
140      if (IsOk) return false;
141      IsOk = true;
142      return true;
143    }
144
145    private class Initialize : Event {
146      public Initialize(Environment environment, Process process)
147        : base(environment) {
148        CallbackList.Add(process.Resume);
149        IsOk = true;
150        IsTriggered = true;
151        environment.Schedule(this);
152      }
153    }
154  }
155}
Note: See TracBrowser for help on using the repository browser.