source: trunk/CrypPlugins/WorkspaceManager/Execution/ExecutionEngine.cs @ 1620

Last change on this file since 1620 was 1620, checked in by kopal, 11 years ago
  • connectors now may only connect from output to InputConnection
  • view is disabled when editor is executing now
  • connector now has "lastData" which stores last used data
  • minwidth, minheight of an VisualElementModel can only be >=50 now
File size: 14.7 KB
Line 
1/*                             
2   Copyright 2010 Nils Kopal, Viktor M.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21
22using WorkspaceManager.Model;
23using System.Threading;
24using System.Collections;
25using Cryptool.PluginBase;
26using System.Reflection;
27using Gears4Net;
28using System.Windows.Threading;
29
30namespace WorkspaceManager.Execution
31{
32    /// <summary>
33    /// Engine to execute a model of the WorkspaceManager
34    /// This class needs a WorkspaceManager to be instantiated
35    /// To run an execution process it also needs a WorkspaceModel
36    ///
37    /// This class uses Gears4Net to execute the plugins
38    /// </summary>
39    public class ExecutionEngine
40    {
41        private WorkspaceManager WorkspaceManagerEditor;
42        private Scheduler[] schedulers;
43        private WorkspaceModel workspaceModel;
44     
45        /// <summary>
46        /// Creates a new ExecutionEngine
47        /// </summary>
48        /// <param name="workspaceManagerEditor"></param>
49        public ExecutionEngine(WorkspaceManager workspaceManagerEditor)
50        {
51            WorkspaceManagerEditor = workspaceManagerEditor;
52        }
53
54        /// <summary>
55        /// Is this ExecutionEngine running?
56        /// </summary>
57        public bool IsRunning
58        {
59            get;
60            private set;
61        }
62
63        /// <summary>
64        /// Execute the given Model
65        /// </summary>
66        /// <param name="workspaceModel"></param>
67        public void Execute(WorkspaceModel workspaceModel)
68        {
69            this.workspaceModel = workspaceModel;
70
71            if (!IsRunning)
72            {
73                IsRunning = true;
74
75                //Here we create n = "ProcessorsCount * 2" Gears4Net schedulers
76                //We do this, because measurements showed that we get the best performance if we
77                //use this amount of schedulers
78                schedulers = new Scheduler[System.Environment.ProcessorCount*2];
79                for(int i=0;i<System.Environment.ProcessorCount*2;i++){
80                    schedulers[i] = new WinFormsScheduler("Scheduler" + i);
81                }
82
83                //We have to reset all states of PluginModels, ConnectorModels and ConnectionModels:
84                workspaceModel.resetStates();
85
86                //The UpdateGuiProtocol is a kind of "daemon" which will update the view elements if necessary
87                UpdateGuiProtocol updateGuiProtocol = new UpdateGuiProtocol(schedulers[0], workspaceModel, this);
88                schedulers[0].AddProtocol(updateGuiProtocol);
89                updateGuiProtocol.Start();
90
91                //The CheckExecutableProtocl is also a kind of "daemon" which will check from time to time if a
92                //plugin can be executed again
93                CheckExecutableProtocol checkExecutableProtocol = new CheckExecutableProtocol(schedulers[0], workspaceModel, this);
94                schedulers[0].AddProtocol(checkExecutableProtocol);
95                checkExecutableProtocol.Start();
96
97                //Here we create for each PluginModel an own PluginProtocol
98                //By using round-robin we give each protocol to another scheduler to gain
99                //a good average load balancing of the schedulers
100                int counter=0;
101                foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
102                {
103                    PluginProtocol pluginProtocol = new PluginProtocol(schedulers[counter], pluginModel,this);
104                    pluginModel.PluginProtocol = pluginProtocol;
105                    schedulers[counter].AddProtocol(pluginProtocol);
106                    pluginModel.checkExecutable(pluginProtocol);
107                    pluginProtocol.Start();
108                    counter = (counter + 1) % (System.Environment.ProcessorCount*2);
109                }
110            }
111        }     
112     
113        /// <summary>
114        /// Stop the execution process:
115        /// calls shutdown on all schedulers + calls stop() on each plugin
116        /// </summary>
117        public void Stop()
118        {
119            //First stop all Gears4Net Schedulers
120            foreach (Scheduler scheduler in schedulers)
121            {
122                scheduler.Shutdown();
123            }
124            //Secondly stop alle plugins
125            foreach(PluginModel pluginModel in workspaceModel.AllPluginModels)
126            {
127                pluginModel.Plugin.Stop();
128            }
129            IsRunning = false;
130        }
131
132        /// <summary>
133        /// Pause the execution
134        /// </summary>
135        public void Pause()
136        {
137            //not implemented yet
138        }
139
140        /// <summary>
141        /// Use the logger of the WorkspaceManagerEditor
142        /// </summary>
143        /// <param name="message"></param>
144        /// <param name="level"></param>
145        public void GuiLogMessage(string message, NotificationLevel level)
146        {           
147            WorkspaceManagerEditor.GuiLogMessage(message, level);
148        }           
149    }
150
151    /// <summary>
152    /// Message send to scheduler for a Plugin to trigger the PreExecution
153    /// </summary>
154    public class MessagePreExecution : MessageBase
155    {
156        public PluginModel PluginModel;
157    }
158
159    /// <summary>
160    /// Message send to scheduler for a Plugin to trigger the Execution
161    /// </summary>
162    public class MessageExecution : MessageBase
163    {
164        public PluginModel PluginModel;
165    }
166
167    /// <summary>
168    /// Message send to scheduler for a Plugin to trigger the PostExecution
169    /// </summary>
170    public class MessagePostExecution : MessageBase
171    {
172        public PluginModel PluginModel;
173    }
174
175    /// <summary>
176    /// A Protocol for updating the GUI in time intervals
177    /// </summary>
178    public class UpdateGuiProtocol : ProtocolBase
179    {
180        private WorkspaceModel workspaceModel;
181        private ExecutionEngine executionEngine;
182
183        /// <summary>
184        /// Create a new protocol. Each protocol requires a scheduler which provides
185        /// a thread for execution.
186        /// </summary>
187        /// <param name="scheduler"></param>
188        public UpdateGuiProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
189            : base(scheduler)
190        {
191            this.workspaceModel = workspaceModel;
192            this.executionEngine = executionEngine;
193        }
194
195        /// <summary>
196        /// The main function of the protocol
197        /// </summary>
198        /// <param name="stateMachine"></param>
199        /// <returns></returns>
200        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
201        {
202            while (this.executionEngine.IsRunning)
203            {
204                yield return Timeout(1000, HandleUpdateGui);
205            }
206        }
207
208        /// <summary>
209        /// Handler function for a message.
210        /// This handler must not block, because it executes inside the thread of the scheduler.
211        /// </summary>
212        /// <param name="msg"></param>
213        private void HandleUpdateGui()
214        {
215            //Get the gui Thread
216            this.workspaceModel.WorkspaceManagerEditor.Presentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
217            {
218                foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
219                {
220                    if (pluginModel.GuiNeedsUpdate)
221                    {
222                        //executionEngine.GuiLogMessage("UpdateGui for \"" + pluginModel.Name + "\"", NotificationLevel.Debug);
223                        pluginModel.GuiNeedsUpdate = false;
224                        pluginModel.paint();
225                        if (pluginModel.UpdateableView != null)
226                        {
227                            pluginModel.UpdateableView.update();
228                        }
229                    }
230                }
231                foreach (ConnectionModel connectionModel in workspaceModel.AllConnectionModels)
232                {
233                    if (connectionModel.GuiNeedsUpdate)
234                    {
235                        if (connectionModel.UpdateableView != null)
236                        {
237                            connectionModel.UpdateableView.update();
238                        }
239                    }
240                }
241            }
242            , null);
243        }
244    }
245
246    /// <summary>
247    /// A Protocol for checking if plugins are executable in time intervals
248    /// </summary>
249    public class CheckExecutableProtocol : ProtocolBase
250    {
251        private WorkspaceModel workspaceModel;
252        private ExecutionEngine executionEngine;
253
254        /// <summary>
255        /// Create a new protocol. Each protocol requires a scheduler which provides
256        /// a thread for execution.
257        /// </summary>
258        /// <param name="scheduler"></param>
259        public CheckExecutableProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
260            : base(scheduler)
261        {
262            this.workspaceModel = workspaceModel;
263            this.executionEngine = executionEngine;
264        }
265
266        /// <summary>
267        /// The main function of the protocol
268        /// </summary>
269        /// <param name="stateMachine"></param>
270        /// <returns></returns>
271        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
272        {
273            while (this.executionEngine.IsRunning)
274            {
275                yield return Timeout(1, HandleCheckExecutable);
276            }
277        }
278
279        /// <summary>
280        /// Handler function for a message.
281        /// This handler must not block, because it executes inside the thread of the scheduler.
282        /// </summary>
283        /// <param name="msg"></param>
284        private void HandleCheckExecutable()
285        {
286            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
287            {
288                pluginModel.checkExecutable(pluginModel.PluginProtocol);
289            }
290        }
291    }
292
293    /// <summary>
294    /// A Protocol for a PluginModel
295    /// </summary>
296    public class PluginProtocol : ProtocolBase
297    {
298        private PluginModel pluginModel;
299        private ExecutionEngine executionEngine;
300
301        /// <summary>
302        /// Create a new protocol. Each protocol requires a scheduler which provides
303        /// a thread for execution.
304        /// </summary>
305        /// <param name="scheduler"></param>
306        public PluginProtocol(Scheduler scheduler, PluginModel pluginModel,ExecutionEngine executionEngine)
307            : base(scheduler)
308        {
309            this.pluginModel = pluginModel;
310            this.executionEngine = executionEngine;
311        }
312
313        /// <summary>
314        /// The main function of the protocol
315        ///
316        /// states are here:
317        ///
318        ///     PreExecution -> Execution -> PostExecution
319        ///        /\                           |
320        ///         |---------------------------|
321        ///         
322        /// </summary>
323        /// <param name="stateMachine"></param>
324        /// <returns></returns>
325        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
326        {
327            while (this.executionEngine.IsRunning)
328            {
329                yield return Receive<MessagePreExecution>(null, this.HandlePreExecute);
330                MessageExecution msg_exec = new MessageExecution();
331                msg_exec.PluginModel = this.pluginModel;
332                this.BroadcastMessageReliably(msg_exec);
333                yield return Receive<MessageExecution>(null, this.HandleExecute);
334                MessagePostExecution msg_post = new MessagePostExecution();
335                msg_post.PluginModel = this.pluginModel;
336                this.BroadcastMessageReliably(msg_post);
337                yield return Receive<MessagePostExecution>(null, this.HandlePostExecute);
338            }
339        }
340
341        /// <summary>
342        /// Call the pre execution function of the wrapped IPlugin
343        /// </summary>
344        /// <param name="msg"></param>
345        private void HandlePreExecute(MessagePreExecution msg)
346        {
347            //executionEngine.GuiLogMessage("HandlePreExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
348            msg.PluginModel.Plugin.PreExecution();
349        }
350
351        /// <summary>
352        /// Call the execution function of the wrapped IPlugin
353        /// </summary>
354        /// <param name="msg"></param>
355        private void HandleExecute(MessageExecution msg)
356        {
357            //executionEngine.GuiLogMessage("HandleExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
358            //Fill the plugins Inputs with data
359            foreach (ConnectorModel connectorModel in pluginModel.InputConnectors)
360            {
361                if (connectorModel.HasData)
362                {
363                    PropertyInfo propertyInfo = pluginModel.Plugin.GetType().GetProperty(connectorModel.PropertyName);
364                    propertyInfo.SetValue(pluginModel.Plugin, connectorModel.Data, null);
365                    connectorModel.HasLastData = true;
366                    connectorModel.LastData = connectorModel.Data;
367                    connectorModel.Data = null;
368                    connectorModel.HasData = false;
369                    connectorModel.InputConnection.Active = false;                   
370                }
371            }
372           
373            msg.PluginModel.Plugin.Execute();
374                       
375        }
376
377        /// <summary>
378        /// Call the post execution function of the wrapped IPlugin
379        /// </summary>
380        /// <param name="msg"></param>
381        private void HandlePostExecute(MessagePostExecution msg)
382        {
383            //executionEngine.GuiLogMessage("HandlePostExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
384            msg.PluginModel.Plugin.PostExecution();
385                     
386        }
387    }
388}
Note: See TracBrowser for help on using the repository browser.