From d02a90823f2873f1b4de63062e3909d03a5a91fa Mon Sep 17 00:00:00 2001
From: Tedd Hansen
Date: Fri, 1 Feb 2008 23:36:36 +0000
Subject: SCRIPTING STILL BROKEN Added comments and regions, restructured code
Changed a lot of AppDomain junk from console from using Console.Write to
Log.Verbose and set it to #if DEBUG All modules should now refresh their
configuration runtime Made all logging in ScriptEngine.Common get script name
from actual engine Renamed LSLLongCmdHandler to AsyncLSLCommandManager Added
auto-recover with 5 sec throttle for new MaintenanceThread
---
.../Common/ScriptEngineBase/AppDomainManager.cs | 44 ++-
.../ScriptEngineBase/AsyncLSLCommandManager.cs | 313 +++++++++++++++++++++
.../ScriptEngine/Common/ScriptEngineBase/Common.cs | 4 +-
.../Common/ScriptEngineBase/EventManager.cs | 21 +-
.../Common/ScriptEngineBase/EventQueueManager.cs | 42 ++-
.../ScriptEngineBase/EventQueueThreadClass.cs | 82 ++++--
.../Common/ScriptEngineBase/LSLLongCmdHandler.cs | 295 -------------------
.../Common/ScriptEngineBase/MaintenanceThread.cs | 86 ++++--
.../Common/ScriptEngineBase/ScriptEngine.cs | 70 +++--
.../Common/ScriptEngineBase/ScriptManager.cs | 23 +-
.../iScriptEngineFunctionModule.cs | 12 +
11 files changed, 596 insertions(+), 396 deletions(-)
create mode 100644 OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
delete mode 100644 OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs
create mode 100644 OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs
(limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase')
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs
index 3519d54..2ed0529 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AppDomainManager.cs
@@ -35,7 +35,7 @@ using OpenSim.Region.ScriptEngine.Common;
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
- public class AppDomainManager
+ public class AppDomainManager : iScriptEngineFunctionModule
{
//
@@ -85,12 +85,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
private object getLock = new object(); // Mutex
private object freeLock = new object(); // Mutex
- //private ScriptEngine m_scriptEngine;
+ private ScriptEngine m_scriptEngine;
//public AppDomainManager(ScriptEngine scriptEngine)
- public AppDomainManager(int MaxScriptsPerDomain)
+ public AppDomainManager(ScriptEngine scriptEngine)
{
- maxScriptsPerAppDomain = MaxScriptsPerDomain;
- //m_scriptEngine = scriptEngine;
+ m_scriptEngine = scriptEngine;
+ ReadConfig();
+ }
+
+ public void ReadConfig()
+ {
+ maxScriptsPerAppDomain = m_scriptEngine.ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1);
}
///
@@ -99,7 +104,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// Free AppDomain
private AppDomainStructure GetFreeAppDomain()
{
- Console.WriteLine("Finding free AppDomain");
+ // Console.WriteLine("Finding free AppDomain");
lock (getLock)
{
// Current full?
@@ -117,7 +122,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
currentAD.CurrentAppDomain = PrepareNewAppDomain();
}
- Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
+ // Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
return currentAD;
} // lock
}
@@ -144,7 +149,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
- Console.WriteLine("Loading: " +
+ m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain Loading: " +
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
@@ -169,17 +174,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// Is number of unloaded bigger or equal to number of loaded?
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
{
- Console.WriteLine("Found empty AppDomain, unloading");
// Remove from internal list
appDomains.Remove(ads);
#if DEBUG
+ Console.WriteLine("Found empty AppDomain, unloading");
long m = GC.GetTotalMemory(true);
#endif
// Unload
AppDomain.Unload(ads.CurrentAppDomain);
#if DEBUG
- Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
- " bytes of memory");
+ m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "AppDomain unload freed " + (m - GC.GetTotalMemory(true)) + " bytes of memory");
#endif
}
}
@@ -193,7 +197,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// Find next available AppDomain to put it in
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
- Console.WriteLine("Loading into AppDomain: " + FileName);
+#if DEBUG
+ m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Loading into AppDomain: " + FileName);
+#endif
IScript mbrt =
(IScript)
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
@@ -213,7 +219,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
lock (freeLock)
{
- Console.WriteLine("Stopping script in AppDomain");
+#if DEBUG
+ m_scriptEngine.Log.Verbose(m_scriptEngine.ScriptEngineName, "Stopping script in AppDomain");
+#endif
// Check if it is current AppDomain
if (currentAD.CurrentAppDomain == ad)
{
@@ -236,5 +244,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
UnloadAppDomains(); // Outsite lock, has its own GetLock
}
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
new file mode 100644
index 0000000..5ec8f50
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
@@ -0,0 +1,313 @@
+/*
+* Copyright (c) Contributors, http://opensimulator.org/
+* See CONTRIBUTORS.TXT for a full list of copyright holders.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the OpenSim Project nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* 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
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using libsecondlife;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Modules;
+
+namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
+{
+ ///
+ /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
+ ///
+ public class AsyncLSLCommandManager : iScriptEngineFunctionModule
+ {
+ private Thread cmdHandlerThread;
+ private int cmdHandlerThreadCycleSleepms;
+
+ private ScriptEngine m_ScriptEngine;
+
+ public AsyncLSLCommandManager(ScriptEngine _ScriptEngine)
+ {
+ m_ScriptEngine = _ScriptEngine;
+ ReadConfig();
+
+ // Start the thread that will be doing the work
+ cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
+ cmdHandlerThread.Name = "CmdHandlerThread";
+ cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
+ cmdHandlerThread.IsBackground = true;
+ cmdHandlerThread.Start();
+ }
+
+ public void ReadConfig()
+ {
+ cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50);
+ }
+
+
+ ~AsyncLSLCommandManager()
+ {
+ // Shut down thread
+ try
+ {
+ if (cmdHandlerThread != null)
+ {
+ if (cmdHandlerThread.IsAlive == true)
+ {
+ cmdHandlerThread.Abort();
+ cmdHandlerThread.Join();
+ }
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ private void CmdHandlerThreadLoop()
+ {
+ while (true)
+ {
+ // Check timers
+ CheckTimerEvents();
+ Thread.Sleep(25);
+ // Check HttpRequests
+ CheckHttpRequests();
+ Thread.Sleep(25);
+ // Check XMLRPCRequests
+ CheckXMLRPCRequests();
+ Thread.Sleep(25);
+ // Check Listeners
+ CheckListeners();
+ Thread.Sleep(25);
+
+ // Sleep before next cycle
+ //Thread.Sleep(cmdHandlerThreadCycleSleepms);
+ }
+ }
+
+ ///
+ /// Remove a specific script (and all its pending commands)
+ ///
+ ///
+ ///
+ public void RemoveScript(uint localID, LLUUID itemID)
+ {
+ // Remove a specific script
+
+ // Remove from: Timers
+ UnSetTimerEvents(localID, itemID);
+ // Remove from: HttpRequest
+ IHttpRequests iHttpReq =
+ m_ScriptEngine.World.RequestModuleInterface();
+ iHttpReq.StopHttpRequest(localID, itemID);
+ }
+
+ #region TIMER
+
+ //
+ // TIMER
+ //
+ private class TimerClass
+ {
+ public uint localID;
+ public LLUUID itemID;
+ public double interval;
+ public DateTime next;
+ }
+
+ private List Timers = new List();
+ private object TimerListLock = new object();
+
+ public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
+ {
+ Console.WriteLine("SetTimerEvent");
+
+ // Always remove first, in case this is a re-set
+ UnSetTimerEvents(m_localID, m_itemID);
+ if (sec == 0) // Disabling timer
+ return;
+
+ // Add to timer
+ TimerClass ts = new TimerClass();
+ ts.localID = m_localID;
+ ts.itemID = m_itemID;
+ ts.interval = sec;
+ ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+ lock (TimerListLock)
+ {
+ Timers.Add(ts);
+ }
+ }
+
+ public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
+ {
+ // Remove from timer
+ lock (TimerListLock)
+ {
+ List NewTimers = new List();
+ foreach (TimerClass ts in Timers)
+ {
+ if (ts.localID != m_localID && ts.itemID != m_itemID)
+ {
+ NewTimers.Add(ts);
+ }
+ }
+ Timers.Clear();
+ Timers = NewTimers;
+ }
+ }
+
+ public void CheckTimerEvents()
+ {
+ // Nothing to do here?
+ if (Timers.Count == 0)
+ return;
+
+ lock (TimerListLock)
+ {
+ // Go through all timers
+ foreach (TimerClass ts in Timers)
+ {
+ // Time has passed?
+ if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
+ {
+ // Add it to queue
+ m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull,
+ new object[] {});
+ // set next interval
+
+
+ ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+ }
+ }
+ } // lock
+ }
+
+ #endregion
+
+ #region HTTP REQUEST
+
+ public void CheckHttpRequests()
+ {
+ if (m_ScriptEngine.World == null)
+ return;
+
+ IHttpRequests iHttpReq =
+ m_ScriptEngine.World.RequestModuleInterface();
+
+ HttpRequestClass httpInfo = null;
+
+ if (iHttpReq != null)
+ httpInfo = iHttpReq.GetNextCompletedRequest();
+
+ while (httpInfo != null)
+ {
+ //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
+
+ // Deliver data to prim's remote_data handler
+ //
+ // TODO: Returning null for metadata, since the lsl function
+ // only returns the byte for HTTP_BODY_TRUNCATED, which is not
+ // implemented here yet anyway. Should be fixed if/when maxsize
+ // is supported
+
+ object[] resobj = new object[]
+ {
+ httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
+ };
+
+ m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
+ httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj
+ );
+
+ httpInfo.Stop();
+ httpInfo = null;
+
+ httpInfo = iHttpReq.GetNextCompletedRequest();
+ }
+ }
+
+ #endregion
+
+ public void CheckXMLRPCRequests()
+ {
+ if (m_ScriptEngine.World == null)
+ return;
+
+ IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface();
+
+ if (xmlrpc != null)
+ {
+ while (xmlrpc.hasRequests())
+ {
+ RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
+ //Console.WriteLine("PICKED REQUEST");
+
+ //Deliver data to prim's remote_data handler
+ object[] resobj = new object[]
+ {
+ 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty,
+ rInfo.GetIntValue(),
+ rInfo.GetStrVal()
+ };
+ m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
+ rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj
+ );
+ }
+ }
+ }
+
+ public void CheckListeners()
+ {
+ if (m_ScriptEngine.World == null)
+ return;
+ IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface();
+
+ while (comms.HasMessages())
+ {
+ ListenerInfo lInfo = comms.GetNextMessage();
+
+ //Deliver data to prim's listen handler
+ object[] resobj = new object[]
+ {
+ lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
+ };
+
+ m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
+ lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj
+ );
+ }
+ }
+
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs
index bce26ff..fe6dfcd 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/Common.cs
@@ -44,14 +44,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public static void SendToDebug(string Message)
{
//if (Debug == true)
- mySE.Log.Verbose("ScriptEngine", "Debug: " + Message);
+ mySE.Log.Verbose(mySE.ScriptEngineName, "Debug: " + Message);
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
}
public static void SendToLog(string Message)
{
//if (Debug == true)
- mySE.Log.Verbose("ScriptEngine", "LOG: " + Message);
+ mySE.Log.Verbose(mySE.ScriptEngineName, "LOG: " + Message);
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
}
}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs
index 250a5df..678c3d0 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventManager.cs
@@ -37,7 +37,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
///
[Serializable]
- public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents
+ public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents, iScriptEngineFunctionModule
{
//
@@ -59,12 +59,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
{
myScriptEngine = _ScriptEngine;
+ ReadConfig();
// Hook up to events from OpenSim
// We may not want to do it because someone is controlling us and will deliver events to us
if (performHookUp)
{
- myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events");
+ myScriptEngine.Log.Verbose(myScriptEngine.ScriptEngineName, "Hooking up to server events");
myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
@@ -73,6 +74,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
+ public void ReadConfig()
+ {
+ }
+
+
public void changed(uint localID, uint change)
{
// Add to queue for all scripts in localID, Object pass change.
@@ -263,5 +269,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response", EventQueueManager.llDetectNull);
}
+
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
index 04c084a..3ba4618 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// Events are queued and executed in separate thread
///
[Serializable]
- public class EventQueueManager
+ public class EventQueueManager : iScriptEngineFunctionModule
{
//
@@ -197,13 +197,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
- private void ReadConfig()
+ public void ReadConfig()
{
+ // Refresh config
numberOfThreads = m_ScriptEngine.ScriptConfigSource.GetInt("NumberOfScriptThreads", 2);
maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
+ // Now refresh config in all threads
+ lock (eventQueueThreadsLock)
+ {
+ foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
+ {
+ EventQueueThread.ReadConfig();
+ }
+ }
}
#endregion
@@ -222,7 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
{
- EventQueueThread.Shutdown();
+ AbortThreadClass(EventQueueThread);
}
eventQueueThreads.Clear();
staticGlobalEventQueueThreads.Clear();
@@ -243,7 +252,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
EventQueueThreadClass eqtc = new EventQueueThreadClass(this);
eventQueueThreads.Add(eqtc);
staticGlobalEventQueueThreads.Add(eqtc);
- m_ScriptEngine.Log.Debug("DotNetEngine", "Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
+ m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
}
private void AbortThreadClass(EventQueueThreadClass threadClass)
@@ -252,16 +261,17 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
eventQueueThreads.Remove(threadClass);
if (staticGlobalEventQueueThreads.Contains(threadClass))
staticGlobalEventQueueThreads.Remove(threadClass);
+
try
{
- threadClass.Shutdown();
+ threadClass.Stop();
}
catch (Exception ex)
{
- m_ScriptEngine.Log.Error("EventQueueManager", "If you see this, could you please report it to Tedd:");
- m_ScriptEngine.Log.Error("EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString());
+ m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "If you see this, could you please report it to Tedd:");
+ m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName + ":EventQueueManager", "Script thread execution timeout kill ended in exception: " + ex.ToString());
}
- m_ScriptEngine.Log.Debug("DotNetEngine", "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
+ m_ScriptEngine.Log.Debug(m_ScriptEngine.ScriptEngineName, "Killed script execution thread. Remaining thread count: " + eventQueueThreads.Count);
}
#endregion
@@ -313,7 +323,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public void AddToObjectQueue(uint localID, string FunctionName, Queue_llDetectParams_Struct qParams, params object[] param)
{
// 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(ScriptEngineName, "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
// Do we have any scripts in this object at all? If not, return
@@ -367,6 +377,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
public void AdjustNumberOfScriptThreads()
{
+ // Is there anything here for us to do?
+ if (eventQueueThreads.Count == numberOfThreads)
+ return;
+
lock (eventQueueThreadsLock)
{
int diff = numberOfThreads - eventQueueThreads.Count;
@@ -424,5 +438,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
#endregion
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
index e610c36..c19d641 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueThreadClass.cs
@@ -12,12 +12,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
/// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
///
- public class EventQueueThreadClass
+ public class EventQueueThreadClass: iScriptEngineFunctionModule
{
///
/// How many ms to sleep if queue is empty
///
private int nothingToDoSleepms;// = 50;
+ private ThreadPriority MyThreadPriority;
public long LastExecutionStarted;
public bool InExecution = false;
@@ -26,25 +27,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
private EventQueueManager eventQueueManager;
public Thread EventQueueThread;
private static int ThreadCount = 0;
- private ThreadPriority MyThreadPriority;
+
+ private string ScriptEngineName = "ScriptEngine.Common";
public EventQueueThreadClass(EventQueueManager eqm)
{
eventQueueManager = eqm;
- nothingToDoSleepms = eqm.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
+ ReadConfig();
Start();
}
~EventQueueThreadClass()
{
- Shutdown();
+ Stop();
}
- ///
- /// Start thread
- ///
- private void Start()
+
+ public void ReadConfig()
{
+ ScriptEngineName = eventQueueManager.m_ScriptEngine.ScriptEngineName;
+ nothingToDoSleepms = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50);
+
// Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually
string pri = eventQueueManager.m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
switch (pri.ToLower())
@@ -70,6 +73,19 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
break;
}
+ // Now set that priority
+ if (EventQueueThread != null)
+ if (EventQueueThread.IsAlive)
+ EventQueueThread.Priority = MyThreadPriority;
+
+ }
+
+
+ ///
+ /// Start thread
+ ///
+ private void Start()
+ {
EventQueueThread = new Thread(EventQueueThreadLoop);
EventQueueThread.IsBackground = true;
@@ -84,18 +100,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
ThreadCount++;
}
- public void Shutdown()
+ public void Stop()
{
+ PleaseShutdown = true; // Set shutdown flag
+ Thread.Sleep(100); // Wait a bit
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
{
try
{
- EventQueueThread.Abort();
- EventQueueThread.Join();
+ EventQueueThread.Abort(); // Send abort
+ EventQueueThread.Join(); // Wait for it
}
catch (Exception)
{
- //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
+ //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Exception killing worker thread: " + e.ToString());
}
}
}
@@ -106,10 +124,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
private void EventQueueThreadLoop()
{
- //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
+ //myScriptEngine.m_logger.Verbose(ScriptEngineName, "EventQueueManager Worker thread spawned");
try
{
- while (true)
+ while (true)
{
try
{
@@ -117,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
while (true)
{
// Every now and then check if we should shut down
- if (eventQueueManager.ThreadsToExit > 0)
+ if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0)
{
// Someone should shut down, lets get exclusive lock
lock (eventQueueManager.ThreadsToExitLock)
@@ -125,9 +143,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// Lets re-check in case someone grabbed it
if (eventQueueManager.ThreadsToExit > 0)
{
- // We are go for shutdown
+ // Its crowded here so we'll shut down
eventQueueManager.ThreadsToExit--;
- Shutdown();
+ Stop();
+ return;
+ }
+ else
+ {
+ // We have been asked to shut down
+ Stop();
return;
}
}
@@ -139,6 +163,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
EventQueueManager.QueueItemStruct QIS = BlankQIS;
bool GotItem = false;
+ if (PleaseShutdown)
+ return;
+
if (eventQueueManager.eventQueue.Count == 0)
{
// Nothing to do? Sleep a bit waiting for something to do
@@ -147,7 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
else
{
// 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(ScriptEngineName, "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
// OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
lock (eventQueueManager.queueLock)
@@ -179,7 +206,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
try
{
#if DEBUG
- eventQueueManager.m_ScriptEngine.Log.Debug("ScriptEngine",
+ eventQueueManager.m_ScriptEngine.Log.Debug(ScriptEngineName,
"Executing event:\r\n"
+ "QIS.localID: " + QIS.localID
+ ", QIS.itemID: " + QIS.itemID
@@ -235,7 +262,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
//else
//{
// T oconsole
- eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine",
+ eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName,
"Unable to send text in-world:\r\n" +
text);
}
@@ -260,19 +287,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
catch (ThreadAbortException tae)
{
- eventQueueManager.m_ScriptEngine.Log.Notice("ScriptEngine", "ThreadAbortException while executing function.");
+ eventQueueManager.m_ScriptEngine.Log.Notice(ScriptEngineName, "ThreadAbortException while executing function.");
}
catch (Exception e)
{
- eventQueueManager.m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
+ eventQueueManager.m_ScriptEngine.Log.Error(ScriptEngineName, "Exception in EventQueueThreadLoop: " + e.ToString());
}
} // while
} // try
catch (ThreadAbortException)
{
- //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
+ //myScriptEngine.Log.Verbose(ScriptEngineName, "EventQueueManager Worker thread killed: " + tae.Message);
}
}
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
}
}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs
deleted file mode 100644
index 7d66638..0000000
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-* Copyright (c) Contributors, http://opensimulator.org/
-* See CONTRIBUTORS.TXT for a full list of copyright holders.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are met:
-* * Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* * Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* * Neither the name of the OpenSim Project nor the
-* names of its contributors may be used to endorse or promote products
-* derived from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
-* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
-* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-* 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
-* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-*/
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using libsecondlife;
-using OpenSim.Region.Environment.Interfaces;
-using OpenSim.Region.Environment.Modules;
-
-namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
-{
- ///
- /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
- ///
- public class LSLLongCmdHandler
- {
- private Thread cmdHandlerThread;
- private int cmdHandlerThreadCycleSleepms = 100;
-
- private ScriptEngine m_ScriptEngine;
-
- public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
- {
- m_ScriptEngine = _ScriptEngine;
-
- // Start the thread that will be doing the work
- cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
- cmdHandlerThread.Name = "CmdHandlerThread";
- cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
- cmdHandlerThread.IsBackground = true;
- cmdHandlerThread.Start();
- }
-
- ~LSLLongCmdHandler()
- {
- // Shut down thread
- try
- {
- if (cmdHandlerThread != null)
- {
- if (cmdHandlerThread.IsAlive == true)
- {
- cmdHandlerThread.Abort();
- cmdHandlerThread.Join();
- }
- }
- }
- catch
- {
- }
- }
-
- private void CmdHandlerThreadLoop()
- {
- while (true)
- {
- // Check timers
- CheckTimerEvents();
- Thread.Sleep(25);
- // Check HttpRequests
- CheckHttpRequests();
- Thread.Sleep(25);
- // Check XMLRPCRequests
- CheckXMLRPCRequests();
- Thread.Sleep(25);
- // Check Listeners
- CheckListeners();
- Thread.Sleep(25);
-
- // Sleep before next cycle
- //Thread.Sleep(cmdHandlerThreadCycleSleepms);
- }
- }
-
- ///
- /// Remove a specific script (and all its pending commands)
- ///
- ///
- ///
- public void RemoveScript(uint localID, LLUUID itemID)
- {
- // Remove a specific script
-
- // Remove from: Timers
- UnSetTimerEvents(localID, itemID);
- // Remove from: HttpRequest
- IHttpRequests iHttpReq =
- m_ScriptEngine.World.RequestModuleInterface();
- iHttpReq.StopHttpRequest(localID, itemID);
- }
-
- #region TIMER
-
- //
- // TIMER
- //
- private class TimerClass
- {
- public uint localID;
- public LLUUID itemID;
- public double interval;
- public DateTime next;
- }
-
- private List Timers = new List();
- private object TimerListLock = new object();
-
- public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
- {
- Console.WriteLine("SetTimerEvent");
-
- // Always remove first, in case this is a re-set
- UnSetTimerEvents(m_localID, m_itemID);
- if (sec == 0) // Disabling timer
- return;
-
- // Add to timer
- TimerClass ts = new TimerClass();
- ts.localID = m_localID;
- ts.itemID = m_itemID;
- ts.interval = sec;
- ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
- lock (TimerListLock)
- {
- Timers.Add(ts);
- }
- }
-
- public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
- {
- // Remove from timer
- lock (TimerListLock)
- {
- List NewTimers = new List();
- foreach (TimerClass ts in Timers)
- {
- if (ts.localID != m_localID && ts.itemID != m_itemID)
- {
- NewTimers.Add(ts);
- }
- }
- Timers.Clear();
- Timers = NewTimers;
- }
- }
-
- public void CheckTimerEvents()
- {
- // Nothing to do here?
- if (Timers.Count == 0)
- return;
-
- lock (TimerListLock)
- {
- // Go through all timers
- foreach (TimerClass ts in Timers)
- {
- // Time has passed?
- if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
- {
- // Add it to queue
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull,
- new object[] {});
- // set next interval
-
-
- ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
- }
- }
- } // lock
- }
-
- #endregion
-
- #region HTTP REQUEST
-
- public void CheckHttpRequests()
- {
- if (m_ScriptEngine.World == null)
- return;
-
- IHttpRequests iHttpReq =
- m_ScriptEngine.World.RequestModuleInterface();
-
- HttpRequestClass httpInfo = null;
-
- if (iHttpReq != null)
- httpInfo = iHttpReq.GetNextCompletedRequest();
-
- while (httpInfo != null)
- {
- //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
-
- // Deliver data to prim's remote_data handler
- //
- // TODO: Returning null for metadata, since the lsl function
- // only returns the byte for HTTP_BODY_TRUNCATED, which is not
- // implemented here yet anyway. Should be fixed if/when maxsize
- // is supported
-
- object[] resobj = new object[]
- {
- httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
- };
-
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
- httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj
- );
-
- httpInfo.Stop();
- httpInfo = null;
-
- httpInfo = iHttpReq.GetNextCompletedRequest();
- }
- }
-
- #endregion
-
- public void CheckXMLRPCRequests()
- {
- if (m_ScriptEngine.World == null)
- return;
-
- IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface();
-
- if (xmlrpc != null)
- {
- while (xmlrpc.hasRequests())
- {
- RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
- //Console.WriteLine("PICKED REQUEST");
-
- //Deliver data to prim's remote_data handler
- object[] resobj = new object[]
- {
- 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty,
- rInfo.GetIntValue(),
- rInfo.GetStrVal()
- };
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
- rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj
- );
- }
- }
- }
-
- public void CheckListeners()
- {
- if (m_ScriptEngine.World == null)
- return;
- IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface();
-
- while (comms.HasMessages())
- {
- ListenerInfo lInfo = comms.GetNextMessage();
-
- //Deliver data to prim's listen handler
- object[] resobj = new object[]
- {
- lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
- };
-
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
- lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj
- );
- }
- }
- }
-}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
index 9536291..105d47f 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/MaintenanceThread.cs
@@ -8,7 +8,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
/// This class does maintenance on script engine.
///
- public class MaintenanceThread
+ public class MaintenanceThread : iScriptEngineFunctionModule
{
public ScriptEngine m_ScriptEngine;
private int MaintenanceLoopms;
@@ -28,7 +28,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
StopMaintenanceThread();
}
- private void ReadConfig()
+ public void ReadConfig()
{
MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
}
@@ -80,48 +80,74 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
public void MaintenanceLoop()
{
- try
+ if (m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens < MaintenanceLoopms)
+ m_ScriptEngine.Log.Warn(m_ScriptEngine.ScriptEngineName,
+ "Configuration error: MaxEventExecutionTimeMs is less than MaintenanceLoopms. The Maintenance Loop will only check scripts once per run.");
+
+ while (true)
{
- long Last_maxFunctionExecutionTimens = 0;// DateTime.Now.Ticks;
- long Last_ReReadConfigFilens = DateTime.Now.Ticks;
- while (true)
+ try
{
- System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep
-
- // Re-reading config every x seconds?
- if (m_ScriptEngine.ReReadConfigFileSeconds > 0)
+ long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks;
+ long Last_ReReadConfigFilens = DateTime.Now.Ticks;
+ while (true)
{
- // Check if its time to re-read config
- if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.ReReadConfigFilens)
+ System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep before next pass
+ if (PleaseShutdown)
+ return;
+ //
+ // Re-reading config every x seconds
+ //
+ if (m_ScriptEngine.RefreshConfigFileSeconds > 0)
{
- // Its time to re-read config file
- m_ScriptEngine.ConfigSource.Reload(); // Re-read config
- Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
+ // Check if its time to re-read config
+ if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.RefreshConfigFilens)
+ {
+ // Its time to re-read config file
+ m_ScriptEngine.ConfigSource.Reload(); // Refresh config
+ m_ScriptEngine.ReadConfig();
+ Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
+ }
}
- }
- // Adjust number of running script threads if not correct
- if (m_ScriptEngine.m_EventQueueManager.eventQueueThreads.Count != m_ScriptEngine.m_EventQueueManager.numberOfThreads)
- {
+ //
+ // Adjust number of running script threads if not correct
+ //
m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
- }
-
- // Check if any script has exceeded its max execution time
- if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
- {
- if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens > m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens)
+ //
+ // Check if any script has exceeded its max execution time
+ //
+ if (m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
{
- m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
- Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
+ // We are enforcing execution time
+ if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
+ m_ScriptEngine.m_EventQueueManager.maxFunctionExecutionTimens)
+ {
+ // Its time to check again
+ m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
+ Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
+ }
}
}
}
- }
- catch (ThreadAbortException tae)
- {
+ catch (Exception ex)
+ {
+ m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: " + ex.ToString());
+ Thread.Sleep(5000);
+ }
}
}
#endregion
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs
index cfcc36e..c237282 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptEngine.cs
@@ -42,27 +42,28 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
///
///
[Serializable]
- public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine
+ public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine, iScriptEngineFunctionModule
{
public Scene World;
- public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
- public EventQueueManager m_EventQueueManager; // Executes events
- public ScriptManager m_ScriptManager; // Load, unload and execute scripts
- public AppDomainManager m_AppDomainManager;
- public LSLLongCmdHandler m_LSLLongCmdHandler;
+ public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
+ public EventQueueManager m_EventQueueManager; // Executes events, handles script threads
+ public ScriptManager m_ScriptManager; // Load, unload and execute scripts
+ public AppDomainManager m_AppDomainManager; // Handles loading/unloading of scripts into AppDomains
+ public AsyncLSLCommandManager m_ASYNCLSLCommandManager; // Asyncronous LSL commands (commands that returns with an event)
+ public MaintenanceThread m_MaintenanceThread; // Thread that does different kinds of maintenance, for example refreshing config and killing scripts that has been running too long
public IConfigSource ConfigSource;
public IConfig ScriptConfigSource;
- public abstract string ScriptConfigSourceName { get; }
+ public abstract string ScriptEngineName { get; }
///
/// How many seconds between re-reading config-file. 0 = never. ScriptEngine will try to adjust to new config changes.
///
- public int ReReadConfigFileSeconds {
- get { return (int)(ReReadConfigFilens / 10000); }
- set { ReReadConfigFilens = value * 10000; }
+ public int RefreshConfigFileSeconds {
+ get { return (int)(RefreshConfigFilens / 10000); }
+ set { RefreshConfigFilens = value * 10000; }
}
- public long ReReadConfigFilens = 0;
+ public long RefreshConfigFilens = 0;
public ScriptManager GetScriptManager()
{
@@ -88,21 +89,22 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
World = Sceneworld;
m_log = logger;
- ScriptConfigSource = ConfigSource.Configs[ScriptConfigSourceName];
+ ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
- Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing");
+ Log.Verbose(ScriptEngineName, "DotNet & LSL ScriptEngine initializing");
- //m_logger.Status("ScriptEngine", "InitializeEngine");
+ //m_logger.Status(ScriptEngineName, "InitializeEngine");
// Create all objects we'll be using
m_EventQueueManager = new EventQueueManager(this);
m_EventManager = new EventManager(this, HookUpToServer);
m_ScriptManager = newScriptManager;
- //m_ScriptManager = new ScriptManager(this);
- m_AppDomainManager = new AppDomainManager(ScriptConfigSource.GetInt("ScriptsPerAppDomain", 1));
- m_LSLLongCmdHandler = new LSLLongCmdHandler(this);
+ m_AppDomainManager = new AppDomainManager(this);
+ m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this);
+ m_MaintenanceThread = new MaintenanceThread(this);
+
+ ReadConfig();
- ReReadConfigFileSeconds = ScriptConfigSource.GetInt("ReReadConfig", 0);
// Should we iterate the region for scripts that needs starting?
@@ -118,6 +120,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
return this.m_EventManager;
}
+ public void ReadConfig()
+ {
+#if DEBUG
+ Log.Debug(ScriptEngineName, "Refreshing configuration for all modules");
+#endif
+ RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 0);
+
+ // Reload from disk
+ ConfigSource.Reload();
+ // Create a new object (probably not necessary?)
+// ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
+
+ if (m_EventQueueManager != null) m_EventQueueManager.ReadConfig();
+ if (m_EventManager != null) m_EventManager.ReadConfig();
+ if (m_ScriptManager != null) m_ScriptManager.ReadConfig();
+ if (m_AppDomainManager != null) m_AppDomainManager.ReadConfig();
+ if (m_ASYNCLSLCommandManager != null) m_ASYNCLSLCommandManager.ReadConfig();
+ if (m_MaintenanceThread != null) m_MaintenanceThread.ReadConfig();
+
+ }
#region IRegionModule
@@ -134,7 +156,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public string Name
{
- get { return "DotNetEngine"; }
+ get { return "Common." + ScriptEngineName; }
}
public bool IsSharedModule
@@ -146,5 +168,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#endregion
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
index ea87581..45cfced 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs
@@ -57,12 +57,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// This so that scripts starting or stopping will not slow down other theads or whole system.
//
[Serializable]
- public abstract class ScriptManager
+ public abstract class ScriptManager : iScriptEngineFunctionModule
{
#region Declares
private Thread scriptLoadUnloadThread;
- private int scriptLoadUnloadThread_IdleSleepms = 100;
+ private int scriptLoadUnloadThread_IdleSleepms;
private Queue LUQueue = new Queue();
@@ -95,6 +95,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#endregion
+ public void ReadConfig()
+ {
+ scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
+ }
+
#region Object init/shutdown
public ScriptEngineBase.ScriptEngine m_scriptEngine;
@@ -102,6 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
{
m_scriptEngine = scriptEngine;
+ ReadConfig();
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
@@ -238,7 +244,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
#endif
// Execute a function in the script
- //m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
+ //m_scriptEngine.Log.Verbose(ScriptEngineName, "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
IScript Script = GetScript(localID, itemID);
if (Script == null)
@@ -345,5 +351,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
#endregion
+
+ ///
+ /// If set to true then threads and stuff should try to make a graceful exit
+ ///
+ public bool PleaseShutdown
+ {
+ get { return _PleaseShutdown; }
+ set { _PleaseShutdown = value; }
+ }
+ private bool _PleaseShutdown = false;
+
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs
new file mode 100644
index 0000000..7539074
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/iScriptEngineFunctionModule.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
+{
+ public interface iScriptEngineFunctionModule
+ {
+ void ReadConfig();
+ bool PleaseShutdown { get; set; }
+ }
+}
\ No newline at end of file
--
cgit v1.1