From 883f7dde3884bca10f324f6a31e0882cf23c04d8 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Fri, 24 Apr 2009 05:33:23 +0000 Subject: * Implements Microthreading for MRM scripting. * This is achieved through two new keywords "microthreaded" and "relax". example: public microthreaded void MyFunc(...) { ... relax; ... } --- .../OptionalModules/Scripting/Minimodule/Host.cs | 9 ++++- .../Scripting/Minimodule/Interfaces/IHost.cs | 1 + .../Minimodule/Interfaces/IMicrothreader.cs | 12 ++++++ .../Scripting/Minimodule/MRMModule.cs | 21 ++++++++++- .../Scripting/Minimodule/MicroScheduler.cs | 38 +++++++++++++++++++ .../Test/Microthreads/MicrothreadSample.txt | 40 ++++++++++++++++++++ .../Scripting/Minimodule/Test/TestModule.cs | 43 ++++++++++++++++++++++ 7 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IMicrothreader.cs create mode 100644 OpenSim/Region/OptionalModules/Scripting/Minimodule/MicroScheduler.cs create mode 100644 OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/Microthreads/MicrothreadSample.txt (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Host.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Host.cs index 94796e4..193461d 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Host.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Host.cs @@ -38,11 +38,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private readonly IGraphics m_graphics; private readonly IExtension m_extend; + private readonly IMicrothreader m_threader; //private Scene m_scene; - public Host(IObject m_obj, Scene m_scene, IExtension m_extend) + public Host(IObject m_obj, Scene m_scene, IExtension m_extend, IMicrothreader m_threader) { this.m_obj = m_obj; + this.m_threader = m_threader; this.m_extend = m_extend; //this.m_scene = m_scene; @@ -68,5 +70,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule { get { return m_extend; } } + + public IMicrothreader Microthreads + { + get { return m_threader; } + } } } diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IHost.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IHost.cs index fd73ffd..cf63fd6 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IHost.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IHost.cs @@ -39,5 +39,6 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule ILog Console { get; } IGraphics Graphics { get; } IExtension Extensions { get; } + IMicrothreader Microthreads { get; } } } diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IMicrothreader.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IMicrothreader.cs new file mode 100644 index 0000000..22d3a99 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Interfaces/IMicrothreader.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Region.OptionalModules.Scripting.Minimodule.Interfaces +{ + public interface IMicrothreader + { + void Run(IEnumerable microthread); + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs index a7b63b0..73eb98f 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs @@ -52,6 +52,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule private static readonly CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); + private readonly MicroScheduler m_microthreads = new MicroScheduler(); + public void RegisterExtension(T instance) { m_extensions[typeof (T)] = instance; @@ -66,6 +68,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule m_log.Info("[MRM] Enabling MRM Module"); m_scene = scene; scene.EventManager.OnRezScript += EventManager_OnRezScript; + scene.EventManager.OnFrame += EventManager_OnFrame; scene.RegisterModuleInterface(this); } @@ -80,6 +83,19 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule } } + void EventManager_OnFrame() + { + m_microthreads.Tick(1000); + } + + static string ConvertMRMKeywords(string script) + { + script = script.Replace("microthreaded void ", "IEnumerable"); + script = script.Replace("relax;", "yield return null;"); + + return script; + } + void EventManager_OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource) { if (script.StartsWith("//MRM:C#")) @@ -87,11 +103,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule if (m_scene.GetSceneObjectPart(localID).OwnerID != m_scene.RegionInfo.MasterAvatarAssignedUUID) return; + script = ConvertMRMKeywords(script); + try { m_log.Info("[MRM] Found C# MRM"); IWorld m_world = new World(m_scene); - IHost m_host = new Host(new SOPObject(m_scene, localID), m_scene, new ExtensionHandler(m_extensions)); + IHost m_host = new Host(new SOPObject(m_scene, localID), m_scene, new ExtensionHandler(m_extensions), + m_microthreads); MRMBase mmb = (MRMBase)AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap( CompileFromDotNetText(script, itemID.ToString()), diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MicroScheduler.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MicroScheduler.cs new file mode 100644 index 0000000..a5da87b --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MicroScheduler.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using OpenSim.Region.OptionalModules.Scripting.Minimodule.Interfaces; + +namespace OpenSim.Region.OptionalModules.Scripting.Minimodule +{ + public class MicroScheduler : IMicrothreader + { + private readonly List m_threads = new List(); + + public void Run(IEnumerable microthread) + { + lock (m_threads) + m_threads.Add(microthread.GetEnumerator()); + } + + public void Tick(int count) + { + lock (m_threads) + { + if(m_threads.Count == 0) + return; + + int i = 0; + while (m_threads.Count > 0 && i < count) + { + i++; + bool running = m_threads[i%m_threads.Count].MoveNext(); + + if (!running) + m_threads.Remove(m_threads[i%m_threads.Count]); + } + } + } + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/Microthreads/MicrothreadSample.txt b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/Microthreads/MicrothreadSample.txt new file mode 100644 index 0000000..dc15c47 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/Microthreads/MicrothreadSample.txt @@ -0,0 +1,40 @@ +//MRM:C# +using System.Collections; +using System.Collections.Generic; +using OpenSim.Region.OptionalModules.Scripting.Minimodule; + +namespace OpenSim +{ + class MiniModule : MRMBase + { + public microthreaded void MicroThreadFunction(string testparam) + { + Host.Object.Say("Hello " + testparam); + + relax; // the 'relax' keyword gives up processing time. + // and should be inserted before, after or in + // any computationally "heavy" zones. + + int c = 500; + while(c-- < 0) { + Host.Object.Say("C=" + c); + relax; // Putting 'relax' in microthreaded loops + // is an easy way to lower the CPU tax + // on your script. + } + + } + + public override void Start() + { + Host.Microthreads.Run( + MicroThreadFunction("World!") + ); + } + + public override void Stop() + { + + } + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/TestModule.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/TestModule.cs index 702ac74..73af7f0 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/TestModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/Test/TestModule.cs @@ -25,12 +25,55 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System.Collections; +using System.Collections.Generic; using OpenSim.Region.OptionalModules.Scripting.Minimodule; namespace OpenSim { class MiniModule : MRMBase { + // private microthreaded Function(params...) + private IEnumerable TestMicrothread(string param) + { + Host.Console.Info("Microthreaded " + param); + // relax; + yield return null; + Host.Console.Info("Microthreaded 2" + param); + yield return null; + int c = 100; + while(c-- < 0) + { + Host.Console.Info("Microthreaded Looped " + c + " " + param); + yield return null; + } + } + + public void Microthread(IEnumerable thread) + { + + } + + public void RunMicrothread() + { + List threads = new List(); + threads.Add(TestMicrothread("A").GetEnumerator()); + threads.Add(TestMicrothread("B").GetEnumerator()); + threads.Add(TestMicrothread("C").GetEnumerator()); + + Microthread(TestMicrothread("Ohai")); + + int i = 0; + while(threads.Count > 0) + { + i++; + bool running = threads[i%threads.Count].MoveNext(); + + if (!running) + threads.Remove(threads[i%threads.Count]); + } + } + public override void Start() { // Say Hello -- cgit v1.1