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

Last change on this file since 1617 was 1617, checked in by kopal, 11 years ago
  • a delete of a plugin now leads to the delete of all left connections
  • added a first version of a Settings to the WorkspaceManager
  • some small bug fixes
File size: 14.2 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            }
232            , null);
233        }
234    }
235
236    /// <summary>
237    /// A Protocol for checking if plugins are executable in time intervals
238    /// </summary>
239    public class CheckExecutableProtocol : ProtocolBase
240    {
241        private WorkspaceModel workspaceModel;
242        private ExecutionEngine executionEngine;
243
244        /// <summary>
245        /// Create a new protocol. Each protocol requires a scheduler which provides
246        /// a thread for execution.
247        /// </summary>
248        /// <param name="scheduler"></param>
249        public CheckExecutableProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
250            : base(scheduler)
251        {
252            this.workspaceModel = workspaceModel;
253            this.executionEngine = executionEngine;
254        }
255
256        /// <summary>
257        /// The main function of the protocol
258        /// </summary>
259        /// <param name="stateMachine"></param>
260        /// <returns></returns>
261        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
262        {
263            while (this.executionEngine.IsRunning)
264            {
265                yield return Timeout(10, HandleCheckExecutable);
266            }
267        }
268
269        /// <summary>
270        /// Handler function for a message.
271        /// This handler must not block, because it executes inside the thread of the scheduler.
272        /// </summary>
273        /// <param name="msg"></param>
274        private void HandleCheckExecutable()
275        {
276            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
277            {
278                pluginModel.checkExecutable(pluginModel.PluginProtocol);
279            }
280        }
281    }
282
283    /// <summary>
284    /// A Protocol for a PluginModel
285    /// </summary>
286    public class PluginProtocol : ProtocolBase
287    {
288        private PluginModel pluginModel;
289        private ExecutionEngine executionEngine;
290
291        /// <summary>
292        /// Create a new protocol. Each protocol requires a scheduler which provides
293        /// a thread for execution.
294        /// </summary>
295        /// <param name="scheduler"></param>
296        public PluginProtocol(Scheduler scheduler, PluginModel pluginModel,ExecutionEngine executionEngine)
297            : base(scheduler)
298        {
299            this.pluginModel = pluginModel;
300            this.executionEngine = executionEngine;
301        }
302
303        /// <summary>
304        /// The main function of the protocol
305        ///
306        /// states are here:
307        ///
308        ///     PreExecution -> Execution -> PostExecution
309        ///        /\                           |
310        ///         |---------------------------|
311        ///         
312        /// </summary>
313        /// <param name="stateMachine"></param>
314        /// <returns></returns>
315        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
316        {
317            while (this.executionEngine.IsRunning)
318            {
319                yield return Receive<MessagePreExecution>(null, this.HandlePreExecute);
320                MessageExecution msg_exec = new MessageExecution();
321                msg_exec.PluginModel = this.pluginModel;
322                this.BroadcastMessageReliably(msg_exec);
323                yield return Receive<MessageExecution>(null, this.HandleExecute);
324                MessagePostExecution msg_post = new MessagePostExecution();
325                msg_post.PluginModel = this.pluginModel;
326                this.BroadcastMessageReliably(msg_post);
327                yield return Receive<MessagePostExecution>(null, this.HandlePostExecute);
328            }
329        }
330
331        /// <summary>
332        /// Call the pre execution function of the wrapped IPlugin
333        /// </summary>
334        /// <param name="msg"></param>
335        private void HandlePreExecute(MessagePreExecution msg)
336        {
337            //executionEngine.GuiLogMessage("HandlePreExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
338            msg.PluginModel.Plugin.PreExecution();
339        }
340
341        /// <summary>
342        /// Call the execution function of the wrapped IPlugin
343        /// </summary>
344        /// <param name="msg"></param>
345        private void HandleExecute(MessageExecution msg)
346        {
347            //executionEngine.GuiLogMessage("HandleExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
348            //Fill the plugins Inputs with data
349            foreach (ConnectorModel connectorModel in pluginModel.InputConnectors)
350            {
351                if (connectorModel.HasData)
352                {
353                    PropertyInfo propertyInfo = pluginModel.Plugin.GetType().GetProperty(connectorModel.PropertyName);
354                    propertyInfo.SetValue(pluginModel.Plugin, connectorModel.Data, null);
355                    connectorModel.Data = null;
356                    connectorModel.HasData = false;
357                    connectorModel.InputConnection.Active = false;                   
358                }
359            }
360           
361            msg.PluginModel.Plugin.Execute();
362                       
363        }
364
365        /// <summary>
366        /// Call the post execution function of the wrapped IPlugin
367        /// </summary>
368        /// <param name="msg"></param>
369        private void HandlePostExecute(MessagePostExecution msg)
370        {
371            //executionEngine.GuiLogMessage("HandlePostExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
372            msg.PluginModel.Plugin.PostExecution();
373                     
374        }
375    }
376}
Note: See TracBrowser for help on using the repository browser.