ThreadPoolClientBranch
Tedd Hansen 2008-01-12 14:45:59 +00:00
parent 33d82aa532
commit 0081c060d0
9 changed files with 6855 additions and 6855 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,239 +1,239 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using OpenSim.Region.ScriptEngine.Common; using OpenSim.Region.ScriptEngine.Common;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
public class AppDomainManager public class AppDomainManager
{ {
// //
// This class does AppDomain handling and loading/unloading of scripts in it. // This class does AppDomain handling and loading/unloading of scripts in it.
// It is instanced in "ScriptEngine" and controlled from "ScriptManager" // It is instanced in "ScriptEngine" and controlled from "ScriptManager"
// //
// 1. Create a new AppDomain if old one is full (or doesn't exist) // 1. Create a new AppDomain if old one is full (or doesn't exist)
// 2. Load scripts into AppDomain // 2. Load scripts into AppDomain
// 3. Unload scripts from AppDomain (stopping them and marking them as inactive) // 3. Unload scripts from AppDomain (stopping them and marking them as inactive)
// 4. Unload AppDomain completely when all scripts in it has stopped // 4. Unload AppDomain completely when all scripts in it has stopped
// //
private int maxScriptsPerAppDomain = 1; private int maxScriptsPerAppDomain = 1;
/// <summary> /// <summary>
/// Internal list of all AppDomains /// Internal list of all AppDomains
/// </summary> /// </summary>
private List<AppDomainStructure> appDomains = new List<AppDomainStructure>(); private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
/// <summary> /// <summary>
/// Structure to keep track of data around AppDomain /// Structure to keep track of data around AppDomain
/// </summary> /// </summary>
private class AppDomainStructure private class AppDomainStructure
{ {
/// <summary> /// <summary>
/// The AppDomain itself /// The AppDomain itself
/// </summary> /// </summary>
public AppDomain CurrentAppDomain; public AppDomain CurrentAppDomain;
/// <summary> /// <summary>
/// Number of scripts loaded into AppDomain /// Number of scripts loaded into AppDomain
/// </summary> /// </summary>
public int ScriptsLoaded; public int ScriptsLoaded;
/// <summary> /// <summary>
/// Number of dead scripts /// Number of dead scripts
/// </summary> /// </summary>
public int ScriptsWaitingUnload; public int ScriptsWaitingUnload;
} }
/// <summary> /// <summary>
/// Current AppDomain /// Current AppDomain
/// </summary> /// </summary>
private AppDomainStructure currentAD; private AppDomainStructure currentAD;
private object getLock = new object(); // Mutex private object getLock = new object(); // Mutex
private object freeLock = new object(); // Mutex private object freeLock = new object(); // Mutex
//private ScriptEngine m_scriptEngine; //private ScriptEngine m_scriptEngine;
//public AppDomainManager(ScriptEngine scriptEngine) //public AppDomainManager(ScriptEngine scriptEngine)
public AppDomainManager() public AppDomainManager()
{ {
//m_scriptEngine = scriptEngine; //m_scriptEngine = scriptEngine;
} }
/// <summary> /// <summary>
/// Find a free AppDomain, creating one if necessary /// Find a free AppDomain, creating one if necessary
/// </summary> /// </summary>
/// <returns>Free AppDomain</returns> /// <returns>Free AppDomain</returns>
private AppDomainStructure GetFreeAppDomain() private AppDomainStructure GetFreeAppDomain()
{ {
Console.WriteLine("Finding free AppDomain"); Console.WriteLine("Finding free AppDomain");
lock (getLock) lock (getLock)
{ {
// Current full? // Current full?
if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain) if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
{ {
// Add it to AppDomains list and empty current // Add it to AppDomains list and empty current
appDomains.Add(currentAD); appDomains.Add(currentAD);
currentAD = null; currentAD = null;
} }
// No current // No current
if (currentAD == null) if (currentAD == null)
{ {
// Create a new current AppDomain // Create a new current AppDomain
currentAD = new AppDomainStructure(); currentAD = new AppDomainStructure();
currentAD.CurrentAppDomain = PrepareNewAppDomain(); currentAD.CurrentAppDomain = PrepareNewAppDomain();
} }
Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded); Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
return currentAD; return currentAD;
} // lock } // lock
} }
private int AppDomainNameCount; private int AppDomainNameCount;
/// <summary> /// <summary>
/// Create and prepare a new AppDomain for scripts /// Create and prepare a new AppDomain for scripts
/// </summary> /// </summary>
/// <returns>The new AppDomain</returns> /// <returns>The new AppDomain</returns>
private AppDomain PrepareNewAppDomain() private AppDomain PrepareNewAppDomain()
{ {
// Create and prepare a new AppDomain // Create and prepare a new AppDomain
AppDomainNameCount++; AppDomainNameCount++;
// TODO: Currently security match current appdomain // TODO: Currently security match current appdomain
// Construct and initialize settings for a second AppDomain. // Construct and initialize settings for a second AppDomain.
AppDomainSetup ads = new AppDomainSetup(); AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
ads.DisallowBindingRedirects = false; ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true; ads.DisallowCodeDownload = true;
ads.LoaderOptimization = LoaderOptimization.MultiDomain; // Sounds good ;) ads.LoaderOptimization = LoaderOptimization.MultiDomain; // Sounds good ;)
ads.ShadowCopyFiles = "true"; // Enabled shadowing ads.ShadowCopyFiles = "true"; // Enabled shadowing
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads); AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
Console.WriteLine("Loading: " + Console.WriteLine("Loading: " +
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString()); AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll")); AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
// Return the new AppDomain // Return the new AppDomain
return AD; return AD;
} }
/// <summary> /// <summary>
/// Unload appdomains that are full and have only dead scripts /// Unload appdomains that are full and have only dead scripts
/// </summary> /// </summary>
private void UnloadAppDomains() private void UnloadAppDomains()
{ {
lock (freeLock) lock (freeLock)
{ {
// Go through all // Go through all
foreach (AppDomainStructure ads in new ArrayList(appDomains)) foreach (AppDomainStructure ads in new ArrayList(appDomains))
{ {
// Don't process current AppDomain // Don't process current AppDomain
if (ads.CurrentAppDomain != currentAD.CurrentAppDomain) if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
{ {
// Not current AppDomain // Not current AppDomain
// Is number of unloaded bigger or equal to number of loaded? // Is number of unloaded bigger or equal to number of loaded?
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload) if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
{ {
Console.WriteLine("Found empty AppDomain, unloading"); Console.WriteLine("Found empty AppDomain, unloading");
// Remove from internal list // Remove from internal list
appDomains.Remove(ads); appDomains.Remove(ads);
#if DEBUG #if DEBUG
long m = GC.GetTotalMemory(true); long m = GC.GetTotalMemory(true);
#endif #endif
// Unload // Unload
AppDomain.Unload(ads.CurrentAppDomain); AppDomain.Unload(ads.CurrentAppDomain);
#if DEBUG #if DEBUG
Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
" bytes of memory"); " bytes of memory");
#endif #endif
} }
} }
} // foreach } // foreach
} // lock } // lock
} }
public IScript LoadScript(string FileName) public IScript LoadScript(string FileName)
{ {
// Find next available AppDomain to put it in // Find next available AppDomain to put it in
AppDomainStructure FreeAppDomain = GetFreeAppDomain(); AppDomainStructure FreeAppDomain = GetFreeAppDomain();
Console.WriteLine("Loading into AppDomain: " + FileName); Console.WriteLine("Loading into AppDomain: " + FileName);
IScript mbrt = IScript mbrt =
(IScript) (IScript)
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
//Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt)); //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
FreeAppDomain.ScriptsLoaded++; FreeAppDomain.ScriptsLoaded++;
return mbrt; return mbrt;
} }
/// <summary> /// <summary>
/// Increase "dead script" counter for an AppDomain /// Increase "dead script" counter for an AppDomain
/// </summary> /// </summary>
/// <param name="ad"></param> /// <param name="ad"></param>
//[Obsolete("Needs fixing, needs a real purpose in life!!!")] //[Obsolete("Needs fixing, needs a real purpose in life!!!")]
public void StopScript(AppDomain ad) public void StopScript(AppDomain ad)
{ {
lock (freeLock) lock (freeLock)
{ {
Console.WriteLine("Stopping script in AppDomain"); Console.WriteLine("Stopping script in AppDomain");
// Check if it is current AppDomain // Check if it is current AppDomain
if (currentAD.CurrentAppDomain == ad) if (currentAD.CurrentAppDomain == ad)
{ {
// Yes - increase // Yes - increase
currentAD.ScriptsWaitingUnload++; currentAD.ScriptsWaitingUnload++;
return; return;
} }
// Lopp through all AppDomains // Lopp through all AppDomains
foreach (AppDomainStructure ads in new ArrayList(appDomains)) foreach (AppDomainStructure ads in new ArrayList(appDomains))
{ {
if (ads.CurrentAppDomain == ad) if (ads.CurrentAppDomain == ad)
{ {
// Found it // Found it
ads.ScriptsWaitingUnload++; ads.ScriptsWaitingUnload++;
break; break;
} }
} // foreach } // foreach
} // lock } // lock
UnloadAppDomains(); // Outsite lock, has its own GetLock UnloadAppDomains(); // Outsite lock, has its own GetLock
} }
} }
} }

View File

@ -1,58 +1,58 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
public static class Common public static class Common
{ {
public static bool debug = true; public static bool debug = true;
public static ScriptEngine mySE; public static ScriptEngine mySE;
// This class just contains some static log stuff used for debugging. // This class just contains some static log stuff used for debugging.
//public delegate void SendToDebugEventDelegate(string Message); //public delegate void SendToDebugEventDelegate(string Message);
//public delegate void SendToLogEventDelegate(string Message); //public delegate void SendToLogEventDelegate(string Message);
//static public event SendToDebugEventDelegate SendToDebugEvent; //static public event SendToDebugEventDelegate SendToDebugEvent;
//static public event SendToLogEventDelegate SendToLogEvent; //static public event SendToLogEventDelegate SendToLogEvent;
public static void SendToDebug(string Message) public static void SendToDebug(string Message)
{ {
//if (Debug == true) //if (Debug == true)
mySE.Log.Verbose("ScriptEngine", "Debug: " + Message); mySE.Log.Verbose("ScriptEngine", "Debug: " + Message);
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); //SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
} }
public static void SendToLog(string Message) public static void SendToLog(string Message)
{ {
//if (Debug == true) //if (Debug == true)
mySE.Log.Verbose("ScriptEngine", "LOG: " + Message); mySE.Log.Verbose("ScriptEngine", "LOG: " + Message);
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message); //SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
} }
} }
} }

View File

@ -1,260 +1,260 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using libsecondlife; using libsecondlife;
using OpenSim.Framework; using OpenSim.Framework;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
/// <summary> /// <summary>
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it. /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
/// </summary> /// </summary>
[Serializable] [Serializable]
public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents
{ {
// //
// Class is instanced in "ScriptEngine" and Uses "EventQueueManager" that is also instanced in "ScriptEngine". // Class is instanced in "ScriptEngine" and Uses "EventQueueManager" that is also instanced in "ScriptEngine".
// This class needs a bit of explaining: // This class needs a bit of explaining:
// //
// This class it the link between an event inside OpenSim and the corresponding event in a user script being executed. // This class it the link between an event inside OpenSim and the corresponding event in a user script being executed.
// //
// For example when an user touches an object then the "myScriptEngine.World.EventManager.OnObjectGrab" event is fired inside OpenSim. // For example when an user touches an object then the "myScriptEngine.World.EventManager.OnObjectGrab" event is fired inside OpenSim.
// We hook up to this event and queue a touch_start in EventQueueManager with the proper LSL parameters. // We hook up to this event and queue a touch_start in EventQueueManager with the proper LSL parameters.
// It will then be delivered to the script by EventQueueManager. // It will then be delivered to the script by EventQueueManager.
// //
// You can check debug C# dump of an LSL script if you need to verify what exact parameters are needed. // You can check debug C# dump of an LSL script if you need to verify what exact parameters are needed.
// //
private ScriptEngine myScriptEngine; private ScriptEngine myScriptEngine;
//public IScriptHost TEMP_OBJECT_ID; //public IScriptHost TEMP_OBJECT_ID;
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp) public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
{ {
myScriptEngine = _ScriptEngine; myScriptEngine = _ScriptEngine;
// Hook up to events from OpenSim // Hook up to events from OpenSim
// We may not want to do it because someone is controlling us and will deliver events to us // We may not want to do it because someone is controlling us and will deliver events to us
if (performHookUp) if (performHookUp)
{ {
myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events"); myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events");
myScriptEngine.World.EventManager.OnObjectGrab += touch_start; myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
myScriptEngine.World.EventManager.OnRezScript += OnRezScript; myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript; myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
// TODO: HOOK ALL EVENTS UP TO SERVER! // TODO: HOOK ALL EVENTS UP TO SERVER!
} }
} }
public void touch_start(uint localID, LLVector3 offsetPos, IClientAPI remoteClient) public void touch_start(uint localID, LLVector3 offsetPos, IClientAPI remoteClient)
{ {
// Add to queue for all scripts in ObjectID object // Add to queue for all scripts in ObjectID object
myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "touch_start", new object[] {(int) 1}); myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "touch_start", new object[] {(int) 1});
} }
public void OnRezScript(uint localID, LLUUID itemID, string script) public void OnRezScript(uint localID, LLUUID itemID, string script)
{ {
Console.WriteLine("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " + Console.WriteLine("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " +
script.Length); script.Length);
myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script); myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script);
} }
public void OnRemoveScript(uint localID, LLUUID itemID) public void OnRemoveScript(uint localID, LLUUID itemID)
{ {
Console.WriteLine("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString()); Console.WriteLine("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString());
myScriptEngine.m_ScriptManager.StopScript( myScriptEngine.m_ScriptManager.StopScript(
localID, localID,
itemID itemID
); );
} }
// TODO: Replace placeholders below // TODO: Replace placeholders below
// NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT! // NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT!
// These needs to be hooked up to OpenSim during init of this class // These needs to be hooked up to OpenSim during init of this class
// then queued in EventQueueManager. // then queued in EventQueueManager.
// When queued in EventQueueManager they need to be LSL compatible (name and params) // When queued in EventQueueManager they need to be LSL compatible (name and params)
public void state_exit(uint localID, LLUUID itemID) public void state_exit(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_exit"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_exit");
} }
public void touch(uint localID, LLUUID itemID) public void touch(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch");
} }
public void touch_end(uint localID, LLUUID itemID) public void touch_end(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch_end"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch_end");
} }
public void collision_start(uint localID, LLUUID itemID) public void collision_start(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_start"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_start");
} }
public void collision(uint localID, LLUUID itemID) public void collision(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision");
} }
public void collision_end(uint localID, LLUUID itemID) public void collision_end(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_end"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_end");
} }
public void land_collision_start(uint localID, LLUUID itemID) public void land_collision_start(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_start"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_start");
} }
public void land_collision(uint localID, LLUUID itemID) public void land_collision(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision");
} }
public void land_collision_end(uint localID, LLUUID itemID) public void land_collision_end(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_end"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_end");
} }
// Handled by long commands // Handled by long commands
public void timer(uint localID, LLUUID itemID) public void timer(uint localID, LLUUID itemID)
{ {
//myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, ""); //myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "");
} }
public void listen(uint localID, LLUUID itemID) public void listen(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "listen"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "listen");
} }
public void on_rez(uint localID, LLUUID itemID) public void on_rez(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez");
} }
public void sensor(uint localID, LLUUID itemID) public void sensor(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "sensor"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "sensor");
} }
public void no_sensor(uint localID, LLUUID itemID) public void no_sensor(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "no_sensor"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "no_sensor");
} }
public void control(uint localID, LLUUID itemID) public void control(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "control"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "control");
} }
public void money(uint localID, LLUUID itemID) public void money(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "money"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "money");
} }
public void email(uint localID, LLUUID itemID) public void email(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "email"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "email");
} }
public void at_target(uint localID, LLUUID itemID) public void at_target(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_target"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_target");
} }
public void not_at_target(uint localID, LLUUID itemID) public void not_at_target(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_target"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_target");
} }
public void at_rot_target(uint localID, LLUUID itemID) public void at_rot_target(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_rot_target"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_rot_target");
} }
public void not_at_rot_target(uint localID, LLUUID itemID) public void not_at_rot_target(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_rot_target"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_rot_target");
} }
public void run_time_permissions(uint localID, LLUUID itemID) public void run_time_permissions(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "run_time_permissions"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "run_time_permissions");
} }
public void changed(uint localID, LLUUID itemID) public void changed(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "changed"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "changed");
} }
public void attach(uint localID, LLUUID itemID) public void attach(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "attach"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "attach");
} }
public void dataserver(uint localID, LLUUID itemID) public void dataserver(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "dataserver"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "dataserver");
} }
public void link_message(uint localID, LLUUID itemID) public void link_message(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "link_message"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "link_message");
} }
public void moving_start(uint localID, LLUUID itemID) public void moving_start(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_start"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_start");
} }
public void moving_end(uint localID, LLUUID itemID) public void moving_end(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_end"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_end");
} }
public void object_rez(uint localID, LLUUID itemID) public void object_rez(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "object_rez"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "object_rez");
} }
public void remote_data(uint localID, LLUUID itemID) public void remote_data(uint localID, LLUUID itemID)
{ {
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "remote_data"); myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "remote_data");
} }
// Handled by long commands // Handled by long commands
public void http_response(uint localID, LLUUID itemID) public void http_response(uint localID, LLUUID itemID)
{ {
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response"); // myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response");
} }
} }
} }

View File

@ -1,364 +1,364 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using libsecondlife; using libsecondlife;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Environment.Scenes.Scripting; using OpenSim.Region.Environment.Scenes.Scripting;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
/// <summary> /// <summary>
/// EventQueueManager handles event queues /// EventQueueManager handles event queues
/// Events are queued and executed in separate thread /// Events are queued and executed in separate thread
/// </summary> /// </summary>
[Serializable] [Serializable]
public class EventQueueManager public class EventQueueManager
{ {
// //
// Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine". // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
// //
// Class purpose is to queue and execute functions that are received by "EventManager": // Class purpose is to queue and execute functions that are received by "EventManager":
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution. // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
// - allowing us to prioritize and control execution of script functions. // - allowing us to prioritize and control execution of script functions.
// Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety. // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
// //
// 1. Hold an execution queue for scripts // 1. Hold an execution queue for scripts
// 2. Use threads to process queue, each thread executes one script function on each pass. // 2. Use threads to process queue, each thread executes one script function on each pass.
// 3. Catch any script error and process it // 3. Catch any script error and process it
// //
// //
// Notes: // Notes:
// * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts. // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
// Not noticeable unless server is under high load. // Not noticeable unless server is under high load.
// * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet, // * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet,
// increase number of threads to allow more concurrent script executions in OpenSim. // increase number of threads to allow more concurrent script executions in OpenSim.
// //
/// <summary> /// <summary>
/// List of threads processing event queue /// List of threads processing event queue
/// </summary> /// </summary>
private List<Thread> eventQueueThreads = new List<Thread>(); private List<Thread> eventQueueThreads = new List<Thread>();
private object queueLock = new object(); // Mutex lock object private object queueLock = new object(); // Mutex lock object
/// <summary> /// <summary>
/// How many ms to sleep if queue is empty /// How many ms to sleep if queue is empty
/// </summary> /// </summary>
private int nothingToDoSleepms = 50; private int nothingToDoSleepms = 50;
/// <summary> /// <summary>
/// How many threads to process queue with /// How many threads to process queue with
/// </summary> /// </summary>
private int numberOfThreads = 2; private int numberOfThreads = 2;
/// <summary> /// <summary>
/// Queue containing events waiting to be executed /// Queue containing events waiting to be executed
/// </summary> /// </summary>
private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>(); private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
/// <summary> /// <summary>
/// Queue item structure /// Queue item structure
/// </summary> /// </summary>
private struct QueueItemStruct private struct QueueItemStruct
{ {
public uint localID; public uint localID;
public LLUUID itemID; public LLUUID itemID;
public string functionName; public string functionName;
public object[] param; public object[] param;
} }
/// <summary> /// <summary>
/// List of localID locks for mutex processing of script events /// List of localID locks for mutex processing of script events
/// </summary> /// </summary>
private List<uint> objectLocks = new List<uint>(); private List<uint> objectLocks = new List<uint>();
private object tryLockLock = new object(); // Mutex lock object private object tryLockLock = new object(); // Mutex lock object
private ScriptEngine m_ScriptEngine; private ScriptEngine m_ScriptEngine;
public EventQueueManager(ScriptEngine _ScriptEngine) public EventQueueManager(ScriptEngine _ScriptEngine)
{ {
m_ScriptEngine = _ScriptEngine; m_ScriptEngine = _ScriptEngine;
// //
// Start event queue processing threads (worker threads) // Start event queue processing threads (worker threads)
// //
for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
{ {
Thread EventQueueThread = new Thread(EventQueueThreadLoop); Thread EventQueueThread = new Thread(EventQueueThreadLoop);
eventQueueThreads.Add(EventQueueThread); eventQueueThreads.Add(EventQueueThread);
EventQueueThread.IsBackground = true; EventQueueThread.IsBackground = true;
EventQueueThread.Priority = ThreadPriority.BelowNormal; EventQueueThread.Priority = ThreadPriority.BelowNormal;
EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
EventQueueThread.Start(); EventQueueThread.Start();
} }
} }
~EventQueueManager() ~EventQueueManager()
{ {
// Kill worker threads // Kill worker threads
foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads)) foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads))
{ {
if (EventQueueThread != null && EventQueueThread.IsAlive == true) if (EventQueueThread != null && EventQueueThread.IsAlive == true)
{ {
try try
{ {
EventQueueThread.Abort(); EventQueueThread.Abort();
EventQueueThread.Join(); EventQueueThread.Join();
} }
catch (Exception) catch (Exception)
{ {
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
} }
} }
} }
eventQueueThreads.Clear(); eventQueueThreads.Clear();
// Todo: Clean up our queues // Todo: Clean up our queues
eventQueue.Clear(); eventQueue.Clear();
} }
/// <summary> /// <summary>
/// Queue processing thread loop /// Queue processing thread loop
/// </summary> /// </summary>
private void EventQueueThreadLoop() private void EventQueueThreadLoop()
{ {
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
try try
{ {
QueueItemStruct BlankQIS = new QueueItemStruct(); QueueItemStruct BlankQIS = new QueueItemStruct();
while (true) while (true)
{ {
try try
{ {
QueueItemStruct QIS = BlankQIS; QueueItemStruct QIS = BlankQIS;
bool GotItem = false; bool GotItem = false;
if (eventQueue.Count == 0) if (eventQueue.Count == 0)
{ {
// Nothing to do? Sleep a bit waiting for something to do // Nothing to do? Sleep a bit waiting for something to do
Thread.Sleep(nothingToDoSleepms); Thread.Sleep(nothingToDoSleepms);
} }
else else
{ {
// Something in queue, process // Something in queue, process
//myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
// OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
lock (queueLock) lock (queueLock)
{ {
GotItem = false; GotItem = false;
for (int qc = 0; qc < eventQueue.Count; qc++) for (int qc = 0; qc < eventQueue.Count; qc++)
{ {
// Get queue item // Get queue item
QIS = eventQueue.Dequeue(); QIS = eventQueue.Dequeue();
// Check if object is being processed by someone else // Check if object is being processed by someone else
if (TryLock(QIS.localID) == false) if (TryLock(QIS.localID) == false)
{ {
// Object is already being processed, requeue it // Object is already being processed, requeue it
eventQueue.Enqueue(QIS); eventQueue.Enqueue(QIS);
} }
else else
{ {
// We have lock on an object and can process it // We have lock on an object and can process it
GotItem = true; GotItem = true;
break; break;
} }
} // go through queue } // go through queue
} // lock } // lock
if (GotItem == true) if (GotItem == true)
{ {
// Execute function // Execute function
try try
{ {
#if DEBUG #if DEBUG
m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n" m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n"
+ "QIS.localID: " + QIS.localID + "QIS.localID: " + QIS.localID
+ ", QIS.itemID: " + QIS.itemID + ", QIS.itemID: " + QIS.itemID
+ ", QIS.functionName: " + QIS.functionName); + ", QIS.functionName: " + QIS.functionName);
#endif #endif
m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID,
QIS.functionName, QIS.param); QIS.functionName, QIS.param);
} }
catch (Exception e) catch (Exception e)
{ {
// DISPLAY ERROR INWORLD // DISPLAY ERROR INWORLD
string text = "Error executing script function \"" + QIS.functionName + "\":\r\n"; string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
//if (e.InnerException != null) //if (e.InnerException != null)
//{ //{
// Send inner exception // Send inner exception
text += e.InnerException.Message.ToString(); text += e.InnerException.Message.ToString();
//} //}
//else //else
//{ //{
text += "\r\n"; text += "\r\n";
// Send normal // Send normal
text += e.Message.ToString(); text += e.Message.ToString();
//} //}
try try
{ {
if (text.Length > 1500) if (text.Length > 1500)
text = text.Substring(0, 1500); text = text.Substring(0, 1500);
IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
//if (m_host != null) //if (m_host != null)
//{ //{
m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0, m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0,
m_host.AbsolutePosition, m_host.Name, m_host.UUID); m_host.AbsolutePosition, m_host.Name, m_host.UUID);
} }
catch catch
{ {
//} //}
//else //else
//{ //{
// T oconsole // T oconsole
m_ScriptEngine.Log.Error("ScriptEngine", m_ScriptEngine.Log.Error("ScriptEngine",
"Unable to send text in-world:\r\n" + text); "Unable to send text in-world:\r\n" + text);
} }
} }
finally finally
{ {
ReleaseLock(QIS.localID); ReleaseLock(QIS.localID);
} }
} }
} // Something in queue } // Something in queue
} }
catch (ThreadAbortException tae) catch (ThreadAbortException tae)
{ {
throw tae; throw tae;
} }
catch (Exception e) catch (Exception e)
{ {
m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString()); m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
} }
} // while } // while
} // try } // try
catch (ThreadAbortException) catch (ThreadAbortException)
{ {
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
} }
} }
/// <summary> /// <summary>
/// Try to get a mutex lock on localID /// Try to get a mutex lock on localID
/// </summary> /// </summary>
/// <param name="localID"></param> /// <param name="localID"></param>
/// <returns></returns> /// <returns></returns>
private bool TryLock(uint localID) private bool TryLock(uint localID)
{ {
lock (tryLockLock) lock (tryLockLock)
{ {
if (objectLocks.Contains(localID) == true) if (objectLocks.Contains(localID) == true)
{ {
return false; return false;
} }
else else
{ {
objectLocks.Add(localID); objectLocks.Add(localID);
return true; return true;
} }
} }
} }
/// <summary> /// <summary>
/// Release mutex lock on localID /// Release mutex lock on localID
/// </summary> /// </summary>
/// <param name="localID"></param> /// <param name="localID"></param>
private void ReleaseLock(uint localID) private void ReleaseLock(uint localID)
{ {
lock (tryLockLock) lock (tryLockLock)
{ {
if (objectLocks.Contains(localID) == true) if (objectLocks.Contains(localID) == true)
{ {
objectLocks.Remove(localID); objectLocks.Remove(localID);
} }
} }
} }
/// <summary> /// <summary>
/// Add event to event execution queue /// Add event to event execution queue
/// </summary> /// </summary>
/// <param name="localID"></param> /// <param name="localID"></param>
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
/// <param name="param">Array of parameters to match event mask</param> /// <param name="param">Array of parameters to match event mask</param>
public void AddToObjectQueue(uint localID, string FunctionName, params object[] param) public void AddToObjectQueue(uint localID, string FunctionName, params object[] param)
{ {
// Determine all scripts in Object and add to their queue // Determine all scripts in Object and add to their queue
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
// Do we have any scripts in this object at all? If not, return // Do we have any scripts in this object at all? If not, return
if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
{ {
//Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
return; return;
} }
Dictionary<LLUUID, IScript>.KeyCollection scriptKeys = Dictionary<LLUUID, IScript>.KeyCollection scriptKeys =
m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
foreach (LLUUID itemID in scriptKeys) foreach (LLUUID itemID in scriptKeys)
{ {
// Add to each script in that object // Add to each script in that object
// TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
AddToScriptQueue(localID, itemID, FunctionName, param); AddToScriptQueue(localID, itemID, FunctionName, param);
} }
} }
/// <summary> /// <summary>
/// Add event to event execution queue /// Add event to event execution queue
/// </summary> /// </summary>
/// <param name="localID"></param> /// <param name="localID"></param>
/// <param name="itemID"></param> /// <param name="itemID"></param>
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
/// <param name="param">Array of parameters to match event mask</param> /// <param name="param">Array of parameters to match event mask</param>
public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param) public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param)
{ {
lock (queueLock) lock (queueLock)
{ {
// Create a structure and add data // Create a structure and add data
QueueItemStruct QIS = new QueueItemStruct(); QueueItemStruct QIS = new QueueItemStruct();
QIS.localID = localID; QIS.localID = localID;
QIS.itemID = itemID; QIS.itemID = itemID;
QIS.functionName = FunctionName; QIS.functionName = FunctionName;
QIS.param = param; QIS.param = param;
// Add it to queue // Add it to queue
eventQueue.Enqueue(QIS); eventQueue.Enqueue(QIS);
} }
} }
} }
} }

View File

@ -1,295 +1,295 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using libsecondlife; using libsecondlife;
using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Modules; using OpenSim.Region.Environment.Modules;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
/// <summary> /// <summary>
/// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc. /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
/// </summary> /// </summary>
public class LSLLongCmdHandler public class LSLLongCmdHandler
{ {
private Thread cmdHandlerThread; private Thread cmdHandlerThread;
private int cmdHandlerThreadCycleSleepms = 100; private int cmdHandlerThreadCycleSleepms = 100;
private ScriptEngine m_ScriptEngine; private ScriptEngine m_ScriptEngine;
public LSLLongCmdHandler(ScriptEngine _ScriptEngine) public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
{ {
m_ScriptEngine = _ScriptEngine; m_ScriptEngine = _ScriptEngine;
// Start the thread that will be doing the work // Start the thread that will be doing the work
cmdHandlerThread = new Thread(CmdHandlerThreadLoop); cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
cmdHandlerThread.Name = "CmdHandlerThread"; cmdHandlerThread.Name = "CmdHandlerThread";
cmdHandlerThread.Priority = ThreadPriority.BelowNormal; cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
cmdHandlerThread.IsBackground = true; cmdHandlerThread.IsBackground = true;
cmdHandlerThread.Start(); cmdHandlerThread.Start();
} }
~LSLLongCmdHandler() ~LSLLongCmdHandler()
{ {
// Shut down thread // Shut down thread
try try
{ {
if (cmdHandlerThread != null) if (cmdHandlerThread != null)
{ {
if (cmdHandlerThread.IsAlive == true) if (cmdHandlerThread.IsAlive == true)
{ {
cmdHandlerThread.Abort(); cmdHandlerThread.Abort();
cmdHandlerThread.Join(); cmdHandlerThread.Join();
} }
} }
} }
catch catch
{ {
} }
} }
private void CmdHandlerThreadLoop() private void CmdHandlerThreadLoop()
{ {
while (true) while (true)
{ {
// Check timers // Check timers
CheckTimerEvents(); CheckTimerEvents();
Thread.Sleep(25); Thread.Sleep(25);
// Check HttpRequests // Check HttpRequests
CheckHttpRequests(); CheckHttpRequests();
Thread.Sleep(25); Thread.Sleep(25);
// Check XMLRPCRequests // Check XMLRPCRequests
CheckXMLRPCRequests(); CheckXMLRPCRequests();
Thread.Sleep(25); Thread.Sleep(25);
// Check Listeners // Check Listeners
CheckListeners(); CheckListeners();
Thread.Sleep(25); Thread.Sleep(25);
// Sleep before next cycle // Sleep before next cycle
//Thread.Sleep(cmdHandlerThreadCycleSleepms); //Thread.Sleep(cmdHandlerThreadCycleSleepms);
} }
} }
/// <summary> /// <summary>
/// Remove a specific script (and all its pending commands) /// Remove a specific script (and all its pending commands)
/// </summary> /// </summary>
/// <param name="m_localID"></param> /// <param name="m_localID"></param>
/// <param name="m_itemID"></param> /// <param name="m_itemID"></param>
public void RemoveScript(uint localID, LLUUID itemID) public void RemoveScript(uint localID, LLUUID itemID)
{ {
// Remove a specific script // Remove a specific script
// Remove from: Timers // Remove from: Timers
UnSetTimerEvents(localID, itemID); UnSetTimerEvents(localID, itemID);
// Remove from: HttpRequest // Remove from: HttpRequest
IHttpRequests iHttpReq = IHttpRequests iHttpReq =
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
iHttpReq.StopHttpRequest(localID, itemID); iHttpReq.StopHttpRequest(localID, itemID);
} }
#region TIMER #region TIMER
// //
// TIMER // TIMER
// //
private class TimerClass private class TimerClass
{ {
public uint localID; public uint localID;
public LLUUID itemID; public LLUUID itemID;
public double interval; public double interval;
public DateTime next; public DateTime next;
} }
private List<TimerClass> Timers = new List<TimerClass>(); private List<TimerClass> Timers = new List<TimerClass>();
private object TimerListLock = new object(); private object TimerListLock = new object();
public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec) public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
{ {
Console.WriteLine("SetTimerEvent"); Console.WriteLine("SetTimerEvent");
// Always remove first, in case this is a re-set // Always remove first, in case this is a re-set
UnSetTimerEvents(m_localID, m_itemID); UnSetTimerEvents(m_localID, m_itemID);
if (sec == 0) // Disabling timer if (sec == 0) // Disabling timer
return; return;
// Add to timer // Add to timer
TimerClass ts = new TimerClass(); TimerClass ts = new TimerClass();
ts.localID = m_localID; ts.localID = m_localID;
ts.itemID = m_itemID; ts.itemID = m_itemID;
ts.interval = sec; ts.interval = sec;
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
lock (TimerListLock) lock (TimerListLock)
{ {
Timers.Add(ts); Timers.Add(ts);
} }
} }
public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID) public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
{ {
// Remove from timer // Remove from timer
lock (TimerListLock) lock (TimerListLock)
{ {
List<TimerClass> NewTimers = new List<TimerClass>(); List<TimerClass> NewTimers = new List<TimerClass>();
foreach (TimerClass ts in Timers) foreach (TimerClass ts in Timers)
{ {
if (ts.localID != m_localID && ts.itemID != m_itemID) if (ts.localID != m_localID && ts.itemID != m_itemID)
{ {
NewTimers.Add(ts); NewTimers.Add(ts);
} }
} }
Timers.Clear(); Timers.Clear();
Timers = NewTimers; Timers = NewTimers;
} }
} }
public void CheckTimerEvents() public void CheckTimerEvents()
{ {
// Nothing to do here? // Nothing to do here?
if (Timers.Count == 0) if (Timers.Count == 0)
return; return;
lock (TimerListLock) lock (TimerListLock)
{ {
// Go through all timers // Go through all timers
foreach (TimerClass ts in Timers) foreach (TimerClass ts in Timers)
{ {
// Time has passed? // Time has passed?
if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
{ {
// Add it to queue // Add it to queue
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer",
new object[] {}); new object[] {});
// set next interval // set next interval
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
} }
} }
} // lock } // lock
} }
#endregion #endregion
#region HTTP REQUEST #region HTTP REQUEST
public void CheckHttpRequests() public void CheckHttpRequests()
{ {
if (m_ScriptEngine.World == null) if (m_ScriptEngine.World == null)
return; return;
IHttpRequests iHttpReq = IHttpRequests iHttpReq =
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
HttpRequestClass httpInfo = null; HttpRequestClass httpInfo = null;
if (iHttpReq != null) if (iHttpReq != null)
httpInfo = iHttpReq.GetNextCompletedRequest(); httpInfo = iHttpReq.GetNextCompletedRequest();
while (httpInfo != null) while (httpInfo != null)
{ {
//Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status); //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
// Deliver data to prim's remote_data handler // Deliver data to prim's remote_data handler
// //
// TODO: Returning null for metadata, since the lsl function // TODO: Returning null for metadata, since the lsl function
// only returns the byte for HTTP_BODY_TRUNCATED, which is not // only returns the byte for HTTP_BODY_TRUNCATED, which is not
// implemented here yet anyway. Should be fixed if/when maxsize // implemented here yet anyway. Should be fixed if/when maxsize
// is supported // is supported
object[] resobj = new object[] object[] resobj = new object[]
{ {
httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
}; };
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
httpInfo.localID, httpInfo.itemID, "http_response", resobj httpInfo.localID, httpInfo.itemID, "http_response", resobj
); );
httpInfo.Stop(); httpInfo.Stop();
httpInfo = null; httpInfo = null;
httpInfo = iHttpReq.GetNextCompletedRequest(); httpInfo = iHttpReq.GetNextCompletedRequest();
} }
} }
#endregion #endregion
public void CheckXMLRPCRequests() public void CheckXMLRPCRequests()
{ {
if (m_ScriptEngine.World == null) if (m_ScriptEngine.World == null)
return; return;
IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
if (xmlrpc != null) if (xmlrpc != null)
{ {
while (xmlrpc.hasRequests()) while (xmlrpc.hasRequests())
{ {
RPCRequestInfo rInfo = xmlrpc.GetNextRequest(); RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
//Console.WriteLine("PICKED REQUEST"); //Console.WriteLine("PICKED REQUEST");
//Deliver data to prim's remote_data handler //Deliver data to prim's remote_data handler
object[] resobj = new object[] object[] resobj = new object[]
{ {
2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), "", 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), "",
rInfo.GetIntValue(), rInfo.GetIntValue(),
rInfo.GetStrVal() rInfo.GetStrVal()
}; };
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", resobj rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", resobj
); );
} }
} }
} }
public void CheckListeners() public void CheckListeners()
{ {
if (m_ScriptEngine.World == null) if (m_ScriptEngine.World == null)
return; return;
IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
while (comms.HasMessages()) while (comms.HasMessages())
{ {
ListenerInfo lInfo = comms.GetNextMessage(); ListenerInfo lInfo = comms.GetNextMessage();
//Deliver data to prim's listen handler //Deliver data to prim's listen handler
object[] resobj = new object[] object[] resobj = new object[]
{ {
lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage() lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
}; };
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
lInfo.GetLocalID(), lInfo.GetItemID(), "listen", resobj lInfo.GetLocalID(), lInfo.GetItemID(), "listen", resobj
); );
} }
} }
} }
} }

View File

@ -1,132 +1,132 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using Nini.Config; using Nini.Config;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes;
using OpenSim.Region.ScriptEngine.Common; using OpenSim.Region.ScriptEngine.Common;
using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase; using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
/// <summary> /// <summary>
/// This is the root object for ScriptEngine. Objects access each other trough this class. /// This is the root object for ScriptEngine. Objects access each other trough this class.
/// </summary> /// </summary>
/// ///
[Serializable] [Serializable]
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine
{ {
public Scene World; public Scene World;
public EventManager m_EventManager; // Handles and queues incoming events from OpenSim public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
public EventQueueManager m_EventQueueManager; // Executes events public EventQueueManager m_EventQueueManager; // Executes events
public ScriptManager m_ScriptManager; // Load, unload and execute scripts public ScriptManager m_ScriptManager; // Load, unload and execute scripts
public AppDomainManager m_AppDomainManager; public AppDomainManager m_AppDomainManager;
public LSLLongCmdHandler m_LSLLongCmdHandler; public LSLLongCmdHandler m_LSLLongCmdHandler;
public ScriptManager GetScriptManager() public ScriptManager GetScriptManager()
{ {
return _GetScriptManager(); return _GetScriptManager();
} }
public abstract ScriptManager _GetScriptManager(); public abstract ScriptManager _GetScriptManager();
private LogBase m_log; private LogBase m_log;
public ScriptEngine() public ScriptEngine()
{ {
//Common.SendToDebug("ScriptEngine Object Initialized"); //Common.SendToDebug("ScriptEngine Object Initialized");
Common.mySE = this; Common.mySE = this;
} }
public LogBase Log public LogBase Log
{ {
get { return m_log; } get { return m_log; }
} }
public void InitializeEngine(Scene Sceneworld, LogBase logger, bool HookUpToServer, ScriptManager newScriptManager) public void InitializeEngine(Scene Sceneworld, LogBase logger, bool HookUpToServer, ScriptManager newScriptManager)
{ {
World = Sceneworld; World = Sceneworld;
m_log = logger; m_log = logger;
Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing"); Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing");
//m_logger.Status("ScriptEngine", "InitializeEngine"); //m_logger.Status("ScriptEngine", "InitializeEngine");
// Create all objects we'll be using // Create all objects we'll be using
m_EventQueueManager = new EventQueueManager(this); m_EventQueueManager = new EventQueueManager(this);
m_EventManager = new EventManager(this, HookUpToServer); m_EventManager = new EventManager(this, HookUpToServer);
m_ScriptManager = newScriptManager; m_ScriptManager = newScriptManager;
//m_ScriptManager = new ScriptManager(this); //m_ScriptManager = new ScriptManager(this);
m_AppDomainManager = new AppDomainManager(); m_AppDomainManager = new AppDomainManager();
m_LSLLongCmdHandler = new LSLLongCmdHandler(this); m_LSLLongCmdHandler = new LSLLongCmdHandler(this);
// Should we iterate the region for scripts that needs starting? // Should we iterate the region for scripts that needs starting?
// Or can we assume we are loaded before anything else so we can use proper events? // Or can we assume we are loaded before anything else so we can use proper events?
} }
public void Shutdown() public void Shutdown()
{ {
// We are shutting down // We are shutting down
} }
ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager() ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager()
{ {
return this.m_EventManager; return this.m_EventManager;
} }
#region IRegionModule #region IRegionModule
public abstract void Initialise(Scene scene, IConfigSource config); public abstract void Initialise(Scene scene, IConfigSource config);
public void PostInitialise() public void PostInitialise()
{ {
} }
public void Close() public void Close()
{ {
} }
public string Name public string Name
{ {
get { return "DotNetEngine"; } get { return "DotNetEngine"; }
} }
public bool IsSharedModule public bool IsSharedModule
{ {
get { return false; } get { return false; }
} }
#endregion #endregion
} }
} }

View File

@ -1,348 +1,348 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.Threading; using System.Threading;
using libsecondlife; using libsecondlife;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes;
using OpenSim.Region.ScriptEngine.Common; using OpenSim.Region.ScriptEngine.Common;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{ {
/// <summary> /// <summary>
/// Loads scripts /// Loads scripts
/// Compiles them if necessary /// Compiles them if necessary
/// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution) /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
/// </summary> /// </summary>
/// ///
// This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes. // This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes.
// * Keeps track of running scripts // * Keeps track of running scripts
// * Compiles script if necessary (through "Compiler") // * Compiles script if necessary (through "Compiler")
// * Loads script (through "AppDomainManager" called from for example "EventQueueManager") // * Loads script (through "AppDomainManager" called from for example "EventQueueManager")
// * Executes functions inside script (called from for example "EventQueueManager" class) // * Executes functions inside script (called from for example "EventQueueManager" class)
// * Unloads script (through "AppDomainManager" called from for example "EventQueueManager") // * Unloads script (through "AppDomainManager" called from for example "EventQueueManager")
// * Dedicated load/unload thread, and queues loading/unloading. // * Dedicated load/unload thread, and queues loading/unloading.
// This so that scripts starting or stopping will not slow down other theads or whole system. // This so that scripts starting or stopping will not slow down other theads or whole system.
// //
[Serializable] [Serializable]
public abstract class ScriptManager public abstract class ScriptManager
{ {
#region Declares #region Declares
private Thread scriptLoadUnloadThread; private Thread scriptLoadUnloadThread;
private int scriptLoadUnloadThread_IdleSleepms = 100; private int scriptLoadUnloadThread_IdleSleepms = 100;
private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
// Load/Unload structure // Load/Unload structure
private struct LUStruct private struct LUStruct
{ {
public uint localID; public uint localID;
public LLUUID itemID; public LLUUID itemID;
public string script; public string script;
public LUType Action; public LUType Action;
} }
private enum LUType private enum LUType
{ {
Unknown = 0, Unknown = 0,
Load = 1, Load = 1,
Unload = 2 Unload = 2
} }
// Object<string, Script<string, script>> // Object<string, Script<string, script>>
// IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
// Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead! // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
public Dictionary<uint, Dictionary<LLUUID, IScript>> Scripts = public Dictionary<uint, Dictionary<LLUUID, IScript>> Scripts =
new Dictionary<uint, Dictionary<LLUUID, IScript>>(); new Dictionary<uint, Dictionary<LLUUID, IScript>>();
public Scene World public Scene World
{ {
get { return m_scriptEngine.World; } get { return m_scriptEngine.World; }
} }
#endregion #endregion
#region Object init/shutdown #region Object init/shutdown
public ScriptEngineBase.ScriptEngine m_scriptEngine; public ScriptEngineBase.ScriptEngine m_scriptEngine;
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine) public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
{ {
m_scriptEngine = scriptEngine; m_scriptEngine = scriptEngine;
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop); scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread"; scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
scriptLoadUnloadThread.IsBackground = true; scriptLoadUnloadThread.IsBackground = true;
scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal; scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal;
scriptLoadUnloadThread.Start(); scriptLoadUnloadThread.Start();
} }
~ScriptManager() ~ScriptManager()
{ {
// Abort load/unload thread // Abort load/unload thread
try try
{ {
if (scriptLoadUnloadThread != null) if (scriptLoadUnloadThread != null)
{ {
if (scriptLoadUnloadThread.IsAlive == true) if (scriptLoadUnloadThread.IsAlive == true)
{ {
scriptLoadUnloadThread.Abort(); scriptLoadUnloadThread.Abort();
scriptLoadUnloadThread.Join(); scriptLoadUnloadThread.Join();
} }
} }
} }
catch catch
{ {
} }
} }
#endregion #endregion
#region Load / Unload scripts (Thread loop) #region Load / Unload scripts (Thread loop)
private void ScriptLoadUnloadThreadLoop() private void ScriptLoadUnloadThreadLoop()
{ {
try try
{ {
while (true) while (true)
{ {
if (LUQueue.Count == 0) if (LUQueue.Count == 0)
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms); Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
if (LUQueue.Count > 0) if (LUQueue.Count > 0)
{ {
LUStruct item = LUQueue.Dequeue(); LUStruct item = LUQueue.Dequeue();
lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts
{ {
if (item.Action == LUType.Unload) if (item.Action == LUType.Unload)
{ {
_StopScript(item.localID, item.itemID); _StopScript(item.localID, item.itemID);
} }
if (item.Action == LUType.Load) if (item.Action == LUType.Load)
{ {
_StartScript(item.localID, item.itemID, item.script); _StartScript(item.localID, item.itemID, item.script);
} }
} }
} }
} }
} }
catch (ThreadAbortException tae) catch (ThreadAbortException tae)
{ {
string a = tae.ToString(); string a = tae.ToString();
a = ""; a = "";
// Expected // Expected
} }
} }
#endregion #endregion
#region Helper functions #region Helper functions
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{ {
//Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name); //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null; return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
} }
#endregion #endregion
#region Start/Stop/Reset script #region Start/Stop/Reset script
private readonly Object startStopLock = new Object(); private readonly Object startStopLock = new Object();
/// <summary> /// <summary>
/// Fetches, loads and hooks up a script to an objects events /// Fetches, loads and hooks up a script to an objects events
/// </summary> /// </summary>
/// <param name="itemID"></param> /// <param name="itemID"></param>
/// <param name="localID"></param> /// <param name="localID"></param>
public void StartScript(uint localID, LLUUID itemID, string Script) public void StartScript(uint localID, LLUUID itemID, string Script)
{ {
LUStruct ls = new LUStruct(); LUStruct ls = new LUStruct();
ls.localID = localID; ls.localID = localID;
ls.itemID = itemID; ls.itemID = itemID;
ls.script = Script; ls.script = Script;
ls.Action = LUType.Load; ls.Action = LUType.Load;
LUQueue.Enqueue(ls); LUQueue.Enqueue(ls);
} }
/// <summary> /// <summary>
/// Disables and unloads a script /// Disables and unloads a script
/// </summary> /// </summary>
/// <param name="localID"></param> /// <param name="localID"></param>
/// <param name="itemID"></param> /// <param name="itemID"></param>
public void StopScript(uint localID, LLUUID itemID) public void StopScript(uint localID, LLUUID itemID)
{ {
LUStruct ls = new LUStruct(); LUStruct ls = new LUStruct();
ls.localID = localID; ls.localID = localID;
ls.itemID = itemID; ls.itemID = itemID;
ls.Action = LUType.Unload; ls.Action = LUType.Unload;
LUQueue.Enqueue(ls); LUQueue.Enqueue(ls);
} }
// Create a new instance of the compiler (reuse) // Create a new instance of the compiler (reuse)
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler(); //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
public abstract void _StartScript(uint localID, LLUUID itemID, string Script); public abstract void _StartScript(uint localID, LLUUID itemID, string Script);
public abstract void _StopScript(uint localID, LLUUID itemID); public abstract void _StopScript(uint localID, LLUUID itemID);
#endregion #endregion
#region Perform event execution in script #region Perform event execution in script
/// <summary> /// <summary>
/// Execute a LL-event-function in Script /// Execute a LL-event-function in Script
/// </summary> /// </summary>
/// <param name="localID">Object the script is located in</param> /// <param name="localID">Object the script is located in</param>
/// <param name="itemID">Script ID</param> /// <param name="itemID">Script ID</param>
/// <param name="FunctionName">Name of function</param> /// <param name="FunctionName">Name of function</param>
/// <param name="args">Arguments to pass to function</param> /// <param name="args">Arguments to pass to function</param>
internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, object[] args) internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, object[] args)
{ {
#if DEBUG #if DEBUG
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName); Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
#endif #endif
// Execute a function in the script // Execute a function in the script
//m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName); //m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID); //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
IScript Script = GetScript(localID, itemID); IScript Script = GetScript(localID, itemID);
if (Script == null) if (Script == null)
return; return;
#if DEBUG #if DEBUG
Console.WriteLine("ScriptEngine: Executing event: " + FunctionName); Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
#endif #endif
// Must be done in correct AppDomain, so leaving it up to the script itself // Must be done in correct AppDomain, so leaving it up to the script itself
Script.Exec.ExecuteEvent(FunctionName, args); Script.Exec.ExecuteEvent(FunctionName, args);
} }
#endregion #endregion
#region Internal functions to keep track of script #region Internal functions to keep track of script
public Dictionary<LLUUID, IScript>.KeyCollection GetScriptKeys(uint localID) public Dictionary<LLUUID, IScript>.KeyCollection GetScriptKeys(uint localID)
{ {
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
return null; return null;
Dictionary<LLUUID, IScript> Obj; Dictionary<LLUUID, IScript> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
return Obj.Keys; return Obj.Keys;
} }
public IScript GetScript(uint localID, LLUUID itemID) public IScript GetScript(uint localID, LLUUID itemID)
{ {
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
return null; return null;
Dictionary<LLUUID, IScript> Obj; Dictionary<LLUUID, IScript> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == false) if (Obj.ContainsKey(itemID) == false)
return null; return null;
// Get script // Get script
IScript Script; IScript Script;
Obj.TryGetValue(itemID, out Script); Obj.TryGetValue(itemID, out Script);
return Script; return Script;
} }
public void SetScript(uint localID, LLUUID itemID, IScript Script) public void SetScript(uint localID, LLUUID itemID, IScript Script)
{ {
// Create object if it doesn't exist // Create object if it doesn't exist
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
{ {
Scripts.Add(localID, new Dictionary<LLUUID, IScript>()); Scripts.Add(localID, new Dictionary<LLUUID, IScript>());
} }
// Delete script if it exists // Delete script if it exists
Dictionary<LLUUID, IScript> Obj; Dictionary<LLUUID, IScript> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == true) if (Obj.ContainsKey(itemID) == true)
Obj.Remove(itemID); Obj.Remove(itemID);
// Add to object // Add to object
Obj.Add(itemID, Script); Obj.Add(itemID, Script);
} }
public void RemoveScript(uint localID, LLUUID itemID) public void RemoveScript(uint localID, LLUUID itemID)
{ {
// Don't have that object? // Don't have that object?
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
return; return;
// Delete script if it exists // Delete script if it exists
Dictionary<LLUUID, IScript> Obj; Dictionary<LLUUID, IScript> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == true) if (Obj.ContainsKey(itemID) == true)
Obj.Remove(itemID); Obj.Remove(itemID);
} }
#endregion #endregion
public void ResetScript(uint localID, LLUUID itemID) public void ResetScript(uint localID, LLUUID itemID)
{ {
string script = GetScript(localID, itemID).Source; string script = GetScript(localID, itemID).Source;
StopScript(localID, itemID); StopScript(localID, itemID);
StartScript(localID, itemID, script); StartScript(localID, itemID, script);
} }
#region Script serialization/deserialization #region Script serialization/deserialization
public void GetSerializedScript(uint localID, LLUUID itemID) public void GetSerializedScript(uint localID, LLUUID itemID)
{ {
// Serialize the script and return it // Serialize the script and return it
// Should not be a problem // Should not be a problem
FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID); FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
BinaryFormatter b = new BinaryFormatter(); BinaryFormatter b = new BinaryFormatter();
b.Serialize(fs, GetScript(localID, itemID)); b.Serialize(fs, GetScript(localID, itemID));
fs.Close(); fs.Close();
} }
public void PutSerializedScript(uint localID, LLUUID itemID) public void PutSerializedScript(uint localID, LLUUID itemID)
{ {
// Deserialize the script and inject it into an AppDomain // Deserialize the script and inject it into an AppDomain
// How to inject into an AppDomain? // How to inject into an AppDomain?
} }
#endregion #endregion
} }
} }