some more code from mrieker for system threads, give up of all the other mono dependent theading models only availble for linux (and possible not all platforms). This only has impact on micro-threading switching, and this only happens on long events and only every 60ms, aditionally we do remove a totally extra set of threads (that could grow in a uncontroled way on win) and their hanshake with main ones. This may of course be even more broken now :P

httptests
UbitUmarov 2018-02-07 10:26:20 +00:00
parent aa2c710c57
commit 53a910e3e5
8 changed files with 874 additions and 1406 deletions

View File

@ -1,55 +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 OpenSimulator 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.
*/
// Used to build a dummy Mono.Tasklets.dll file when running on Windows
// Will also work if running with mono, it will just not allow use of
// the "con" and "mmr" thread models, only "sys" will work.
using System;
namespace Mono.Tasklets {
public class Continuation : IDisposable
{
public Continuation ()
{
throw new NotSupportedException ("'con' thread model requires mono");
}
public void Dispose ()
{ }
public void Mark ()
{ }
public int Store (int state)
{
return 0;
}
public void Restore (int state)
{ }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -119,6 +119,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
//FAST: return ++ counter; //FAST: return ++ counter;
// VS2017 in debug mode seems content to run this quickly though: // VS2017 in debug mode seems content to run this quickly though:
try { try {
return lis.Size; return lis.Size;
} catch { } catch {

View File

@ -31,7 +31,6 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.Serialization;
using System.Text; using System.Text;
using System.Threading; using System.Threading;

View File

@ -78,9 +78,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
if (stackSize < 16384) stackSize = 16384; if (stackSize < 16384) stackSize = 16384;
if (heapSize < 16384) heapSize = 16384; if (heapSize < 16384) heapSize = 16384;
/* // Save all call parameters in instance vars for easy access.
* Save all call parameters in instance vars for easy access.
*/
m_Engine = engine; m_Engine = engine;
m_ScriptBasePath = scriptBasePath; m_ScriptBasePath = scriptBasePath;
m_StackSize = stackSize; m_StackSize = stackSize;
@ -88,185 +86,167 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_CompilerErrors = errors; m_CompilerErrors = errors;
m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID); m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
/* // Not in any XMRInstQueue.
* Not in any XMRInstQueue.
*/
m_NextInst = this; m_NextInst = this;
m_PrevInst = this; m_PrevInst = this;
/* // Set up list of API calls it has available.
* Set up list of API calls it has available. // This also gets the API modules ready to accept setup data, such as
* This also gets the API modules ready to accept setup data, such as // active listeners being restored.
* active listeners being restored.
*/
IScriptApi scriptApi; IScriptApi scriptApi;
ApiManager am = new ApiManager(); ApiManager am = new ApiManager();
foreach (string api in am.GetApis()) foreach (string api in am.GetApis())
{ {
/* // Instantiate the API for this script instance.
* Instantiate the API for this script instance.
*/
if (api != "LSL") { if (api != "LSL") {
scriptApi = am.CreateApi(api); scriptApi = am.CreateApi(api);
} else { } else {
scriptApi = m_XMRLSLApi = new XMRLSL_Api(); scriptApi = m_XMRLSLApi = new XMRLSL_Api();
} }
/* // Connect it up to the instance.
* Connect it up to the instance.
*/
InitScriptApi (engine, api, scriptApi); InitScriptApi (engine, api, scriptApi);
} }
m_XMRLSLApi.InitXMRLSLApi(this); m_XMRLSLApi.InitXMRLSLApi(this);
/* // Get object loaded, compiling script and reading .state file as
* Get object loaded, compiling script and reading .state file as // necessary to restore the state.
* necessary to restore the state.
*/
suspendOnCheckRunHold = true; suspendOnCheckRunHold = true;
InstantiateScript(); InstantiateScript();
m_SourceCode = null; m_SourceCode = null;
if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode"); if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode");
if (m_ObjCode.scriptEventHandlerTable == null) { if (m_ObjCode.scriptEventHandlerTable == null)
throw new ArgumentNullException ("m_ObjCode.scriptEventHandlerTable"); throw new ArgumentNullException ("m_ObjCode.scriptEventHandlerTable");
}
suspendOnCheckRunHold = false; suspendOnCheckRunHold = false;
suspendOnCheckRunTemp = false; suspendOnCheckRunTemp = false;
/* // Declare which events the script's current state can handle.
* Declare which events the script's current state can handle.
*/
int eventMask = GetStateEventFlags(stateCode); int eventMask = GetStateEventFlags(stateCode);
m_Part.SetScriptEvents(m_ItemID, eventMask); m_Part.SetScriptEvents(m_ItemID, eventMask);
} }
private void InitScriptApi (XMREngine engine, string api, IScriptApi scriptApi) private void InitScriptApi (XMREngine engine, string api, IScriptApi scriptApi)
{ {
/* // Set up m_ApiManager_<APINAME> = instance pointer.
* Set up m_ApiManager_<APINAME> = instance pointer.
*/
engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue (this, scriptApi); engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue (this, scriptApi);
/* // Initialize the API instance.
* Initialize the API instance.
*/
scriptApi.Initialize(m_Engine, m_Part, m_Item); scriptApi.Initialize(m_Engine, m_Part, m_Item);
this.InitApi (api, scriptApi); this.InitApi (api, scriptApi);
} }
/*
// Get script object code loaded in memory and all ready to run, * Get script object code loaded in memory and all ready to run,
// ready to resume it from where the .state file says it was last * ready to resume it from where the .state file says it was last
*/
private void InstantiateScript() private void InstantiateScript()
{ {
bool compiledIt = false; bool compiledIt = false;
ScriptObjCode objCode; ScriptObjCode objCode;
/* // If source code string is empty, use the asset ID as the object file name.
* If source code string is empty, use the asset ID as the object file name. // Allow lines of // comments at the beginning (for such as engine selection).
* Allow lines of // comments at the beginning (for such as engine selection).
*/
int i, j, len; int i, j, len;
if (m_SourceCode == null) m_SourceCode = String.Empty; if (m_SourceCode == null) m_SourceCode = String.Empty;
for (len = m_SourceCode.Length; len > 0; -- len) { for (len = m_SourceCode.Length; len > 0; --len)
if (m_SourceCode[len-1] > ' ') break; {
if (m_SourceCode[len-1] > ' ')
break;
} }
for (i = 0; i < len; i ++) { for (i = 0; i < len; i ++)
{
char c = m_SourceCode[i]; char c = m_SourceCode[i];
if (c <= ' ') continue; if (c <= ' ')
if (c != '/') break; continue;
if ((i + 1 >= len) || (m_SourceCode[i+1] != '/')) break; if (c != '/')
break;
if ((i + 1 >= len) || (m_SourceCode[i+1] != '/'))
break;
i = m_SourceCode.IndexOf ('\n', i); i = m_SourceCode.IndexOf ('\n', i);
if (i < 0) i = len - 1; if (i < 0)
i = len - 1;
} }
if ((i >= len) || !m_Engine.m_UseSourceHashCode) { if ((i >= len) || !m_Engine.m_UseSourceHashCode)
{
/* // Source consists of nothing but // comments and whitespace,
* Source consists of nothing but // comments and whitespace, // or we are being forced to use the asset-id as the key, to
* or we are being forced to use the asset-id as the key, to // open an already existing object code file.
* open an already existing object code file.
*/
m_ScriptObjCodeKey = m_Item.AssetID.ToString (); m_ScriptObjCodeKey = m_Item.AssetID.ToString ();
if (i >= len) m_SourceCode = ""; if (i >= len)
} else { m_SourceCode = "";
}
/* else
* Make up dictionary key for the object code. {
* Use the same object code for identical source code // Make up dictionary key for the object code.
* regardless of asset ID, so we don't care if they // Use the same object code for identical source code
* copy scripts or not. // regardless of asset ID, so we don't care if they
*/ // copy scripts or not.
byte[] scbytes = System.Text.Encoding.UTF8.GetBytes (m_SourceCode); byte[] scbytes = System.Text.Encoding.UTF8.GetBytes (m_SourceCode);
StringBuilder sb = new StringBuilder ((256 + 5) / 6); StringBuilder sb = new StringBuilder ((256 + 5) / 6);
ByteArrayToSixbitStr (sb, System.Security.Cryptography.SHA256.Create ().ComputeHash (scbytes)); ByteArrayToSixbitStr (sb, System.Security.Cryptography.SHA256.Create ().ComputeHash (scbytes));
m_ScriptObjCodeKey = sb.ToString (); m_ScriptObjCodeKey = sb.ToString ();
/* // But source code can be just a sixbit string itself
* But source code can be just a sixbit string itself // that identifies an already existing object code file.
* that identifies an already existing object code file. if (len - i == m_ScriptObjCodeKey.Length)
*/ {
if (len - i == m_ScriptObjCodeKey.Length) { for (j = len; -- j >= i;)
for (j = len; -- j >= i;) { {
if (sixbit.IndexOf (m_SourceCode[j]) < 0) break; if (sixbit.IndexOf (m_SourceCode[j]) < 0)
break;
} }
if (j < i) { if (j < i)
{
m_ScriptObjCodeKey = m_SourceCode.Substring (i, len - i); m_ScriptObjCodeKey = m_SourceCode.Substring (i, len - i);
m_SourceCode = ""; m_SourceCode = "";
} }
} }
} }
/* // There may already be an ScriptObjCode struct in memory that
* There may already be an ScriptObjCode struct in memory that // we can use. If not, try to compile it.
* we can use. If not, try to compile it. lock (m_CompileLock)
*/ {
lock (m_CompileLock) { if (!m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) || m_ForceRecomp)
if (!m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) || m_ForceRecomp) { {
objCode = TryToCompile (); objCode = TryToCompile ();
compiledIt = true; compiledIt = true;
} }
/* // Loaded successfully, increment reference count.
* Loaded successfully, increment reference count.
* // If we just compiled it though, reset count to 0 first as
* If we just compiled it though, reset count to 0 first as // this is the one-and-only existance of this objCode struct,
* this is the one-and-only existance of this objCode struct, // and we want any old ones for this source code to be garbage
* and we want any old ones for this source code to be garbage // collected.
* collected.
*/ if (compiledIt)
if (compiledIt) { {
m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode; m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode;
objCode.refCount = 0; objCode.refCount = 0;
} }
objCode.refCount ++; objCode.refCount ++;
/* // Now set up to decrement ref count on dispose.
* Now set up to decrement ref count on dispose.
*/
m_ObjCode = objCode; m_ObjCode = objCode;
} }
try { try
{
/* // Fill in script instance from object code
* Fill in script instance from object code // Script instance is put in a "never-ever-has-run-before" state.
* Script instance is put in a "never-ever-has-run-before" state.
*/
LoadObjCode(); LoadObjCode();
/* // Fill in script intial state
* Fill in script intial state // - either as loaded from a .state file
* - either as loaded from a .state file // - or initial default state_entry() event
* - or initial default state_entry() event
*/
LoadInitialState(); LoadInitialState();
} catch { }
catch
/* {
* If any error loading, decrement object code reference count. // If any error loading, decrement object code reference count.
*/
DecObjCodeRefCount (); DecObjCodeRefCount ();
throw; throw;
} }
@ -277,42 +257,41 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
int bit = 0; int bit = 0;
int val = 0; int val = 0;
foreach (byte b in bytes) { foreach (byte b in bytes)
{
val |= (int)((uint)b << bit); val |= (int)((uint)b << bit);
bit += 8; bit += 8;
while (bit >= 6) { while (bit >= 6)
{
sb.Append (sixbit[val&63]); sb.Append (sixbit[val&63]);
val >>= 6; val >>= 6;
bit -= 6; bit -= 6;
} }
} }
if (bit > 0) { if (bit > 0)
sb.Append (sixbit[val&63]); sb.Append (sixbit[val&63]);
}
} }
// Try to create object code from source code /*
// If error, just throw exception * Try to create object code from source code
* If error, just throw exception
*/
private ScriptObjCode TryToCompile () private ScriptObjCode TryToCompile ()
{ {
m_CompilerErrors.Clear(); m_CompilerErrors.Clear();
/* // If object file exists, create ScriptObjCode directly from that.
* If object file exists, create ScriptObjCode directly from that. // Otherwise, compile the source to create object file then create
* Otherwise, compile the source to create object file then create // ScriptObjCode from that.
* ScriptObjCode from that.
*/
string assetID = m_Item.AssetID.ToString(); string assetID = m_Item.AssetID.ToString();
m_CameFrom = "asset://" + assetID; m_CameFrom = "asset://" + assetID;
ScriptObjCode objCode = Compile (); ScriptObjCode objCode = Compile ();
if (m_CompilerErrors.Count != 0) if (m_CompilerErrors.Count != 0)
{
throw new Exception ("compilation errors"); throw new Exception ("compilation errors");
}
if (objCode == null) if (objCode == null)
{
throw new Exception ("compilation failed"); throw new Exception ("compilation failed");
}
return objCode; return objCode;
} }
@ -323,18 +302,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private string FetchSource (string cameFrom) private string FetchSource (string cameFrom)
{ {
m_log.Debug ("[XMREngine]: fetching source " + cameFrom); m_log.Debug ("[XMREngine]: fetching source " + cameFrom);
if (!cameFrom.StartsWith ("asset://")) { if (!cameFrom.StartsWith ("asset://"))
throw new Exception ("unable to retrieve source from " + cameFrom); throw new Exception ("unable to retrieve source from " + cameFrom);
}
string assetID = cameFrom.Substring (8); string assetID = cameFrom.Substring (8);
AssetBase asset = m_Engine.World.AssetService.Get(assetID); AssetBase asset = m_Engine.World.AssetService.Get(assetID);
if (asset == null) { if (asset == null)
throw new Exception ("source not found " + cameFrom); throw new Exception ("source not found " + cameFrom);
}
string source = Encoding.UTF8.GetString (asset.Data); string source = Encoding.UTF8.GetString (asset.Data);
if (EmptySource (source)) { if (EmptySource (source))
throw new Exception ("fetched source empty " + cameFrom); throw new Exception ("fetched source empty " + cameFrom);
}
return source; return source;
} }
@ -344,53 +323,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private void LoadObjCode () private void LoadObjCode ()
{ {
/* // Script must leave this much stack remaining on calls to CheckRun().
* Script must leave this much stack remaining on calls to CheckRun().
*/
this.stackLimit = m_StackSize / 2; this.stackLimit = m_StackSize / 2;
/* // This is how many total heap bytes script is allowed to use.
* This is how many total heap bytes script is allowed to use.
*/
this.heapLimit = m_HeapSize; this.heapLimit = m_HeapSize;
/* // Allocate global variable arrays.
* Allocate global variable arrays.
*/
this.glblVars.AllocVarArrays (m_ObjCode.glblSizes); this.glblVars.AllocVarArrays (m_ObjCode.glblSizes);
/* // Script can handle these event codes.
* Script can handle these event codes.
*/
m_HaveEventHandlers = new bool[m_ObjCode.scriptEventHandlerTable.GetLength(1)]; m_HaveEventHandlers = new bool[m_ObjCode.scriptEventHandlerTable.GetLength(1)];
for (int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); -- i >= 0;) { for (int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); -- i >= 0;)
for (int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); -- j >= 0;) { {
if (m_ObjCode.scriptEventHandlerTable[i,j] != null) { for (int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); -- j >= 0;)
{
if (m_ObjCode.scriptEventHandlerTable[i,j] != null)
{
m_HaveEventHandlers[j] = true; m_HaveEventHandlers[j] = true;
} }
} }
} }
/* // Set up microthread object which actually calls the script event handler functions.
* Set up microthread object which actually calls the script event handler functions.
*/
this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this }); this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
} }
// LoadInitialState() /*
// if no state XML file exists for the asset, * LoadInitialState()
// post initial default state events * if no state XML file exists for the asset,
// else * post initial default state events
// try to restore from .state file * else
// If any error, throw exception * try to restore from .state file
// * If any error, throw exception
*/
private void LoadInitialState() private void LoadInitialState()
{ {
/* // If no .state file exists, start from default state
* If no .state file exists, start from default state // Otherwise, read initial state from the .state file
* Otherwise, read initial state from the .state file if (!File.Exists(m_StateFileName))
*/ {
if (!File.Exists(m_StateFileName)) {
m_Running = true; // event processing is enabled m_Running = true; // event processing is enabled
eventCode = ScriptEventCode.None; // not processing any event eventCode = ScriptEventCode.None; // not processing any event
@ -401,7 +374,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
PostEvent(new EventParams("state_entry", PostEvent(new EventParams("state_entry",
zeroObjectArray, zeroObjectArray,
zeroDetectParams)); zeroDetectParams));
} else { }
else
{
FileStream fs = File.Open(m_StateFileName, FileStream fs = File.Open(m_StateFileName,
FileMode.Open, FileMode.Open,
FileAccess.Read); FileAccess.Read);
@ -415,31 +390,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
LoadScriptState(doc); LoadScriptState(doc);
} }
/* // Post event(s) saying what caused the script to start.
* Post event(s) saying what caused the script to start. if (m_PostOnRez)
*/ {
if (m_PostOnRez) {
PostEvent(new EventParams("on_rez", PostEvent(new EventParams("on_rez",
new Object[] { m_StartParam }, new Object[] { m_StartParam },
zeroDetectParams)); zeroDetectParams));
} }
switch (m_StateSource) { switch (m_StateSource)
case StateSource.AttachedRez: { {
case StateSource.AttachedRez:
// PostEvent(new EventParams("attach", // PostEvent(new EventParams("attach",
// new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() }, // new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() },
// zeroDetectParams)); // zeroDetectParams));
break; break;
}
case StateSource.PrimCrossing: { case StateSource.PrimCrossing:
PostEvent(new EventParams("changed", PostEvent(new EventParams("changed",
sbcCR, sbcCR,
zeroDetectParams)); zeroDetectParams));
break; break;
}
case StateSource.Teleporting: { case StateSource.Teleporting:
PostEvent(new EventParams("changed", PostEvent(new EventParams("changed",
sbcCR, sbcCR,
zeroDetectParams)); zeroDetectParams));
@ -447,14 +420,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
sbcCT, sbcCT,
zeroDetectParams)); zeroDetectParams));
break; break;
}
case StateSource.RegionStart: { case StateSource.RegionStart:
PostEvent(new EventParams("changed", PostEvent(new EventParams("changed",
sbcCRS, sbcCRS,
zeroDetectParams)); zeroDetectParams));
break; break;
}
} }
} }
@ -468,17 +439,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private void ErrorHandler(Token token, string message) private void ErrorHandler(Token token, string message)
{ {
if (token != null) { if (token != null)
{
string srcloc = token.SrcLoc; string srcloc = token.SrcLoc;
if (srcloc.StartsWith (m_CameFrom)) { if (srcloc.StartsWith (m_CameFrom))
srcloc = srcloc.Substring (m_CameFrom.Length); srcloc = srcloc.Substring (m_CameFrom.Length);
}
m_CompilerErrors.Add(srcloc + " Error: " + message); m_CompilerErrors.Add(srcloc + " Error: " + message);
} else if (message != null) {
m_CompilerErrors.Add("(0,0) Error: " + message);
} else {
m_CompilerErrors.Add("(0,0) Error compiling, see exception in log");
} }
else if (message != null)
m_CompilerErrors.Add("(0,0) Error: " + message);
else
m_CompilerErrors.Add("(0,0) Error compiling, see exception in log");
} }
/** /**
@ -503,28 +476,25 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Everything we know is enclosed in <ScriptState>...</ScriptState> // Everything we know is enclosed in <ScriptState>...</ScriptState>
XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState"); XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState");
if (scriptStateN == null) { if (scriptStateN == null)
throw new Exception("no <ScriptState> tag"); throw new Exception("no <ScriptState> tag");
}
string sen = scriptStateN.GetAttribute("Engine"); string sen = scriptStateN.GetAttribute("Engine");
if ((sen == null) || (sen != m_Engine.ScriptEngineName)) { if ((sen == null) || (sen != m_Engine.ScriptEngineName))
throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute"); throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute");
}
// AssetID is unique for the script source text so make sure the // AssetID is unique for the script source text so make sure the
// state file was written for that source file // state file was written for that source file
string assetID = scriptStateN.GetAttribute("Asset"); string assetID = scriptStateN.GetAttribute("Asset");
if (assetID != m_Item.AssetID.ToString()) if (assetID != m_Item.AssetID.ToString())
{
throw new Exception("<ScriptState> assetID mismatch"); throw new Exception("<ScriptState> assetID mismatch");
}
// Also match the sourceHash in case script was // Also match the sourceHash in case script was
// loaded via 'xmroption fetchsource' and has changed // loaded via 'xmroption fetchsource' and has changed
string sourceHash = scriptStateN.GetAttribute ("SourceHash"); string sourceHash = scriptStateN.GetAttribute ("SourceHash");
if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash)) { if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
throw new Exception ("<ScriptState> SourceHash mismatch"); throw new Exception ("<ScriptState> SourceHash mismatch");
}
// Get various attributes // Get various attributes
XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running"); XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running");
@ -549,8 +519,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin"); Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin");
// Script's global variables and stack contents // Script's global variables and stack contents
XmlElement snapshotN = XmlElement snapshotN = (XmlElement)scriptStateN.SelectSingleNode("Snapshot");
(XmlElement)scriptStateN.SelectSingleNode("Snapshot");
Byte[] data = Convert.FromBase64String(snapshotN.InnerText); Byte[] data = Convert.FromBase64String(snapshotN.InnerText);
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
@ -561,18 +530,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Restore event queues, preserving any events that queued // Restore event queues, preserving any events that queued
// whilst we were restoring the state // whilst we were restoring the state
lock (m_QueueLock) { lock (m_QueueLock)
{
m_DetectParams = detParams; m_DetectParams = detParams;
foreach (EventParams evt in m_EventQueue) { foreach (EventParams evt in m_EventQueue)
eventQueue.AddLast (evt); eventQueue.AddLast (evt);
}
m_EventQueue = eventQueue; m_EventQueue = eventQueue;
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0; for (int i = m_EventCounts.Length; -- i >= 0;)
m_EventCounts[i] = 0;
foreach (EventParams evt in m_EventQueue) foreach (EventParams evt in m_EventQueue)
{ {
ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName); evt.EventName);
m_EventCounts[(int)eventCode] ++; m_EventCounts[(int)eventCode]++;
} }
} }
@ -594,7 +566,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN) private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN)
{ {
LinkedList<EventParams> eventQueue = new LinkedList<EventParams>(); LinkedList<EventParams> eventQueue = new LinkedList<EventParams>();
if (eventsN != null) { if (eventsN != null)
{
XmlNodeList eventL = eventsN.SelectNodes("Event"); XmlNodeList eventL = eventsN.SelectNodes("Event");
foreach (XmlNode evnt in eventL) foreach (XmlNode evnt in eventL)
{ {
@ -629,8 +602,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlNodeList detectL = detectedN.SelectNodes("DetectParams"); XmlNodeList detectL = detectedN.SelectNodes("DetectParams");
DetectParams detprm = new DetectParams(); DetectParams detprm = new DetectParams();
foreach (XmlNode detxml in detectL) { foreach (XmlNode detxml in detectL)
try { {
try
{
detprm.Group = new UUID(detxml.Attributes.GetNamedItem("group").Value); detprm.Group = new UUID(detxml.Attributes.GetNamedItem("group").Value);
detprm.Key = new UUID(detxml.Attributes.GetNamedItem("key").Value); detprm.Key = new UUID(detxml.Attributes.GetNamedItem("key").Value);
detprm.Owner = new UUID(detxml.Attributes.GetNamedItem("owner").Value); detprm.Owner = new UUID(detxml.Attributes.GetNamedItem("owner").Value);
@ -648,7 +623,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
detected.Add(detprm); detected.Add(detprm);
detprm = new DetectParams(); detprm = new DetectParams();
} catch (Exception e) { }
catch (Exception e)
{
m_log.Warn("[XMREngine]: RestoreDetectParams bad XML: " + detxml.ToString()); m_log.Warn("[XMREngine]: RestoreDetectParams bad XML: " + detxml.ToString());
m_log.Warn("[XMREngine]: ... " + e.ToString()); m_log.Warn("[XMREngine]: ... " + e.ToString());
} }
@ -670,9 +647,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlNodeList itemL = parent.SelectNodes(tag); XmlNodeList itemL = parent.SelectNodes(tag);
foreach (XmlNode item in itemL) foreach (XmlNode item in itemL)
{
olist.Add(ExtractXMLObjectValue(item)); olist.Add(ExtractXMLObjectValue(item));
}
return olist.ToArray(); return olist.ToArray();
} }
@ -682,9 +657,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string itemType = item.Attributes.GetNamedItem("type").Value; string itemType = item.Attributes.GetNamedItem("type").Value;
if (itemType == "list") if (itemType == "list")
{
return new LSL_List(ExtractXMLObjectArray(item, "item")); return new LSL_List(ExtractXMLObjectArray(item, "item"));
}
if (itemType == "OpenMetaverse.UUID") if (itemType == "OpenMetaverse.UUID")
{ {
@ -701,9 +674,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared"; string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared";
itemT = Type.GetType(assembly); itemT = Type.GetType(assembly);
if (itemT == null) if (itemT == null)
{
return null; return null;
}
return Activator.CreateInstance(itemT, args); return Activator.CreateInstance(itemT, args);
} }
@ -724,77 +696,82 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
miehstream = stream; miehstream = stream;
XMRScriptThread cst = XMRScriptThread.CurrentScriptThread (); XMRScriptThread cst = XMRScriptThread.CurrentScriptThread ();
if (cst != null) { if (cst != null)
{
// in case we are getting called inside some LSL Api function // in case we are getting called inside some LSL Api function
MigrateInEventHandlerThread (); MigrateInEventHandlerThread ();
} else { }
else
{
// some other thread, do migration via a script thread // some other thread, do migration via a script thread
lock (XMRScriptThread.m_WakeUpLock) { lock (XMRScriptThread.m_WakeUpLock)
{
m_Engine.m_ThunkQueue.Enqueue (this.MigrateInEventHandlerThread); m_Engine.m_ThunkQueue.Enqueue (this.MigrateInEventHandlerThread);
} }
XMRScriptThread.WakeUpOne (); XMRScriptThread.WakeUpOne ();
// wait for it to complete // wait for it to complete
lock (miehdone) { lock (miehdone)
while (miehstream != null) { {
Monitor.Wait (miehdone); while (miehstream != null)
} Monitor.Wait(miehdone);
} }
} }
// maybe it threw up // maybe it threw up
if (miehexcep != null) throw miehexcep; if (miehexcep != null)
throw miehexcep;
} }
private Exception miehexcep; private Exception miehexcep;
private object miehdone = new object (); private object miehdone = new object ();
private Stream miehstream; private Stream miehstream;
private void MigrateInEventHandlerThread () private void MigrateInEventHandlerThread ()
{ {
try { try
{
int mv = miehstream.ReadByte (); int mv = miehstream.ReadByte ();
if (mv != migrationVersion) { if (mv != migrationVersion)
throw new Exception ("incoming migration version " + mv + " but accept only " + migrationVersion); throw new Exception ("incoming migration version " + mv + " but accept only " + migrationVersion);
}
miehstream.ReadByte (); // ignored miehstream.ReadByte (); // ignored
/* // Restore script variables and stack and other state from stream.
* Restore script variables and stack and other state from stream. // And it also marks us busy (by setting this.eventCode) so we can't be
* And it also marks us busy (by setting this.eventCode) so we can't be // started again and this event lost.
* started again and this event lost.
*/
BinaryReader br = new BinaryReader (miehstream); BinaryReader br = new BinaryReader (miehstream);
this.MigrateIn (br); this.MigrateIn (br);
/* // If eventCode is None, it means the script was idle when migrated.
* If eventCode is None, it means the script was idle when migrated.
*/ if (this.eventCode != ScriptEventCode.None)
if (this.eventCode != ScriptEventCode.None) { {
// So microthread.Start() calls XMRScriptUThread.Main() which calls the
// event handler function. The event handler function sees the stack
// frames in this.stackFrames and restores its args and locals, then calls
// whatever it was calling when the snapshot was taken. That function also
// sees this.stackFrames and restores its args and locals, and so on...
// Eventually it gets to the point of calling CheckRun() which sees we are
// doing a restore and it suspends, returning here with the microthread
// stack all restored. It shouldn't ever throw an exception.
/*
* So microthread.Start() calls XMRScriptUThread.Main() which calls the
* event handler function. The event handler function sees the stack
* frames in this.stackFrames and restores its args and locals, then calls
* whatever it was calling when the snapshot was taken. That function also
* sees this.stackFrames and restores its args and locals, and so on...
* Eventually it gets to the point of calling CheckRun() which sees we are
* doing a restore and it suspends, returning here with the microthread
* stack all restored. It shouldn't ever throw an exception.
*/
this.stackFramesRestored = false; this.stackFramesRestored = false;
Exception te = microthread.StartEx (); Exception te = microthread.StartEx ();
if (te != null) throw te; if (te != null) throw te;
if (!this.stackFramesRestored) throw new Exception ("migrate in did not complete"); if (!this.stackFramesRestored)
throw new Exception ("migrate in did not complete");
} }
} catch (Exception e) { }
catch (Exception e)
{
miehexcep = e; miehexcep = e;
} finally { }
finally
/* {
* Wake the MigrateInEventHandler() method above. // Wake the MigrateInEventHandler() method above.
*/ lock (miehdone)
lock (miehdone) { {
miehstream = null; miehstream = null;
Monitor.Pulse (miehdone); Monitor.Pulse (miehdone);
} }
@ -807,67 +784,67 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public string CheckFetchbinaryAllowed () public string CheckFetchbinaryAllowed ()
{ {
string ownerPerm = m_Engine.Config.GetString ("Allow_fetchbinary", ""); string ownerPerm = m_Engine.Config.GetString ("Allow_fetchbinary", "");
UUID ownerID = m_Item.OwnerID; UUID ownerID = m_Item.OwnerID;
string[] ids = ownerPerm.Split (new char[] { ',' }); string[] ids = ownerPerm.Split (new char[] { ',' });
foreach (string id in ids) { foreach (string id in ids)
string curuc = id.Trim ().ToUpperInvariant (); {
string curuc = id.Trim().ToUpperInvariant();
switch (curuc) { switch (curuc)
case "ESTATE_MANAGER": { {
case "ESTATE_MANAGER":
if (m_Engine.m_Scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner (ownerID) && if (m_Engine.m_Scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner (ownerID) &&
(m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner != ownerID)) { (m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner != ownerID))
return null; return null;
}
break;
}
case "ESTATE_OWNER": { break;
if (m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner == ownerID) {
case "ESTATE_OWNER":
if (m_Engine.m_Scene.RegionInfo.EstateSettings.EstateOwner == ownerID)
return null; return null;
}
break;
}
case "PARCEL_GROUP_MEMBER": { break;
case "PARCEL_GROUP_MEMBER":
ILandObject land = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition); ILandObject land = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition);
if (land.LandData.GroupID == m_Item.GroupID && land.LandData.GroupID != UUID.Zero) { if (land.LandData.GroupID == m_Item.GroupID && land.LandData.GroupID != UUID.Zero)
return null; return null;
}
break;
}
case "PARCEL_OWNER": { break;
ILandObject land = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition);
if (land.LandData.OwnerID == ownerID) { case "PARCEL_OWNER":
ILandObject Oland = m_Engine.m_Scene.LandChannel.GetLandObject (m_Part.AbsolutePosition);
if (Oland.LandData.OwnerID == ownerID)
return null; return null;
}
break;
}
case "TRUE": { break;
case "TRUE":
return null; return null;
}
default: { default:
UUID uuid; UUID uuid;
if (UUID.TryParse (curuc, out uuid)) { if (UUID.TryParse (curuc, out uuid))
if (uuid == ownerID) return null; if (uuid == ownerID) return null;
}
break; break;
}
} }
} }
string creatorPerm = m_Engine.Config.GetString ("Creators_fetchbinary", ""); string creatorPerm = m_Engine.Config.GetString ("Creators_fetchbinary", "");
UUID creatorID = m_Item.CreatorID; UUID creatorID = m_Item.CreatorID;
ids = creatorPerm.Split (new char[] { ',' }); ids = creatorPerm.Split (new char[] { ',' });
foreach (string id in ids) { foreach (string id in ids)
{
string current = id.Trim (); string current = id.Trim ();
UUID uuid; UUID uuid;
if (UUID.TryParse (current, out uuid)) { if (UUID.TryParse (current, out uuid))
if (uuid != UUID.Zero) { {
if (creatorID == uuid) return null; if (uuid != UUID.Zero)
{
if (creatorID == uuid)
return null;
} }
} }
} }

View File

@ -25,7 +25,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using Mono.Tasklets;
using OpenSim.Framework.Monitoring; using OpenSim.Framework.Monitoring;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -70,7 +69,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private bool m_Exiting = false; private bool m_Exiting = false;
private bool m_SuspendScriptThreadFlag = false; private bool m_SuspendScriptThreadFlag = false;
private bool m_WakeUpThis = false; private bool m_WakeUpThis = false;
private bool m_Continuations = false;
public DateTime m_LastRanAt = DateTime.MinValue; public DateTime m_LastRanAt = DateTime.MinValue;
public int m_ScriptThreadTID = 0; public int m_ScriptThreadTID = 0;
public long m_ScriptExecTime = 0; public long m_ScriptExecTime = 0;
@ -78,15 +76,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private XMREngine engine; private XMREngine engine;
public XMRInstance m_RunInstance = null; public XMRInstance m_RunInstance = null;
public XMRScriptThread(XMREngine eng) public XMRScriptThread(XMREngine eng, int i)
{ {
engine = eng; engine = eng;
m_Continuations = engine.uThreadCtor.DeclaringType == typeof (ScriptUThread_Con); if(i < 0)
// thd = XMREngine.StartMyThread (RunScriptThread, "xmrengine script", ThreadPriority.BelowNormal); thd = XMREngine.StartMyThread (RunScriptThread, "xmrengine script", ThreadPriority.Normal);
thd = XMREngine.StartMyThread (RunScriptThread, "xmrengine script", ThreadPriority.Normal); else
thd = XMREngine.StartMyThread (RunScriptThread, "xmrengineExec" + i.ToString(), ThreadPriority.Normal);
lock (m_AllThreads) lock (m_AllThreads)
m_AllThreads.Add (thd, this); m_AllThreads.Add (thd, this);
} }
public void SuspendThread() public void SuspendThread()
@ -125,7 +123,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private void WakeUpScriptThread() private void WakeUpScriptThread()
{ {
lock (m_WakeUpLock) { lock (m_WakeUpLock)
{
m_WakeUpThis = true; m_WakeUpThis = true;
Monitor.PulseAll (m_WakeUpLock); Monitor.PulseAll (m_WakeUpLock);
} }
@ -137,24 +136,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void RunScriptThread() private void RunScriptThread()
{ {
XMRInstance inst; XMRInstance inst;
Mono.Tasklets.Continuation engstack = null;
if (m_Continuations) {
engstack = new Mono.Tasklets.Continuation ();
engstack.Mark ();
}
m_ScriptThreadTID = System.Threading.Thread.CurrentThread.ManagedThreadId; m_ScriptThreadTID = System.Threading.Thread.CurrentThread.ManagedThreadId;
while (!m_Exiting) { while (!m_Exiting)
{
XMREngine.UpdateMyThread (); XMREngine.UpdateMyThread ();
/* /*
* Handle 'xmr resume/suspend' commands. * Handle 'xmr resume/suspend' commands.
*/ */
if (m_SuspendScriptThreadFlag) { if (m_SuspendScriptThreadFlag)
{
lock (m_WakeUpLock) { lock (m_WakeUpLock) {
while (m_SuspendScriptThreadFlag && while (m_SuspendScriptThreadFlag &&
!m_Exiting && !m_Exiting &&
(engine.m_ThunkQueue.Count == 0)) { (engine.m_ThunkQueue.Count == 0))
{
Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
XMREngine.UpdateMyThread (); XMREngine.UpdateMyThread ();
} }
@ -165,81 +162,72 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Maybe there are some scripts waiting to be migrated in or out. * Maybe there are some scripts waiting to be migrated in or out.
*/ */
ThreadStart thunk = null; ThreadStart thunk = null;
lock (m_WakeUpLock) { lock (m_WakeUpLock)
if (engine.m_ThunkQueue.Count > 0) { {
if (engine.m_ThunkQueue.Count > 0)
thunk = engine.m_ThunkQueue.Dequeue (); thunk = engine.m_ThunkQueue.Dequeue ();
}
} }
if (thunk != null) { if (thunk != null)
{
inst = (XMRInstance)thunk.Target; inst = (XMRInstance)thunk.Target;
if (m_Continuations && (inst.scrstack == null)) {
inst.engstack = engstack;
inst.scrstack = new Mono.Tasklets.Continuation ();
inst.scrstack.Mark ();
}
thunk (); thunk ();
continue; continue;
} }
if (engine.m_StartProcessing) { if (engine.m_StartProcessing)
{
// If event just queued to any idle scripts
// start them right away. But only start so
// many so we can make some progress on yield
// queue.
/*
* If event just queued to any idle scripts
* start them right away. But only start so
* many so we can make some progress on yield
* queue.
*/
int numStarts; int numStarts;
for (numStarts = 5; -- numStarts >= 0;) { for (numStarts = 5; -- numStarts >= 0;)
lock (engine.m_StartQueue) { {
lock (engine.m_StartQueue)
{
inst = engine.m_StartQueue.RemoveHead(); inst = engine.m_StartQueue.RemoveHead();
} }
if (inst == null) break; if (inst == null) break;
if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state");
if (m_Continuations && (inst.scrstack == null)) {
inst.engstack = engstack;
inst.scrstack = new Mono.Tasklets.Continuation ();
inst.scrstack.Mark ();
}
RunInstance (inst); RunInstance (inst);
} }
/* // If there is something to run, run it
* If there is something to run, run it // then rescan from the beginning in case
* then rescan from the beginning in case // a lot of things have changed meanwhile.
* a lot of things have changed meanwhile. //
* // These are considered lower priority than
* These are considered lower priority than // m_StartQueue as they have been taking at
* m_StartQueue as they have been taking at // least one quantum of CPU time and event
* least one quantum of CPU time and event // handlers are supposed to be quick.
* handlers are supposed to be quick.
*/ lock (engine.m_YieldQueue)
lock (engine.m_YieldQueue) { {
inst = engine.m_YieldQueue.RemoveHead(); inst = engine.m_YieldQueue.RemoveHead();
} }
if (inst != null) { if (inst != null)
{
if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state"); if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state");
RunInstance (inst); RunInstance(inst);
numStarts = -1; numStarts = -1;
} }
/* // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
* If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it. if (numStarts < 0)
*/ continue;
if (numStarts < 0) continue;
} }
/* // Nothing to do, sleep.
* Nothing to do, sleep.
*/ lock (m_WakeUpLock)
lock (m_WakeUpLock) { {
if (!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting) { if (!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2); Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
}
m_WakeUpThis = false; m_WakeUpThis = false;
if ((m_WakeUpOne > 0) && (-- m_WakeUpOne > 0)) { if ((m_WakeUpOne > 0) && (-- m_WakeUpOne > 0))
Monitor.Pulse (m_WakeUpLock); Monitor.Pulse (m_WakeUpLock);
}
} }
} }
XMREngine.MyThreadExiting (); XMREngine.MyThreadExiting ();

View File

@ -25,31 +25,24 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using Mono.Tasklets;
using System; using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
/***************************\ /***************************\
* Use standard C# code * * Use standard C# code *
* - uses system threads * * - uses stack smashing *
\***************************/ \***************************/
namespace OpenSim.Region.ScriptEngine.XMREngine { namespace OpenSim.Region.ScriptEngine.XMREngine
{
public class ScriptUThread_Sys : IScriptUThread, IDisposable public class ScriptUThread_Nul : IScriptUThread, IDisposable
{ {
private Exception except;
private int active; // -1: hibernating private int active; // -1: hibernating
// 0: exited // 0: exited
// 1: running // 1: running
private object activeLock = new object ();
private XMRInstance instance; private XMRInstance instance;
public ScriptUThread_Sys (XMRInstance instance) public ScriptUThread_Nul (XMRInstance instance)
{ {
this.instance = instance; this.instance = instance;
} }
@ -63,31 +56,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
*/ */
public Exception StartEx () public Exception StartEx ()
{ {
lock (activeLock) { // We should only be called when no event handler running.
if (active != 0) throw new Exception ("active=" + active);
/* // Start script event handler from very beginning.
* We should only be called when script is inactive. active = 1;
*/ Exception except = null;
if (active != 0) throw new Exception ("active=" + active); instance.callMode = XMRInstance.CallMode_NORMAL;
try {
/* instance.CallSEH (); // run script event handler
* Tell CallSEHThread() to run script event handler in a thread. active = 0;
*/ } catch (StackHibernateException) {
active = 1; if (instance.callMode != XMRInstance.CallMode_SAVE) {
TredPoo.RunSomething (CallSEHThread); throw new Exception ("callMode=" + instance.callMode);
/*
* Wait for script to call Hiber() or for script to
* return back out to CallSEHThread().
*/
while (active > 0) {
Monitor.Wait (activeLock);
} }
active = -1; // it is hibernating, can be resumed
} catch (Exception e) {
active = 0;
except = e; // threw exception, save for Start()/Resume()
} }
/* // Return whether or not script threw an exception.
* Return whether or not script threw an exception.
*/
return except; return except;
} }
@ -98,31 +87,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
*/ */
public Exception ResumeEx () public Exception ResumeEx ()
{ {
lock (activeLock) { // We should only be called when script is hibernating.
if (active >= 0) throw new Exception ("active=" + active);
/* // Resume script from captured stack.
* We should only be called when script is hibernating. instance.callMode = XMRInstance.CallMode_RESTORE;
*/ instance.suspendOnCheckRunTemp = true;
if (active >= 0) throw new Exception ("active=" + active); Exception except = null;
try {
/* instance.CallSEH (); // run script event handler
* Tell Hiber() to return back to script. active = 0;
*/ } catch (StackHibernateException) {
active = 1; if (instance.callMode != XMRInstance.CallMode_SAVE) {
Monitor.PulseAll (activeLock); throw new Exception ("callMode=" + instance.callMode);
/*
* Wait for script to call Hiber() again or for script to
* return back out to CallSEHThread().
*/
while (active > 0) {
Monitor.Wait (activeLock);
} }
active = -1;
} catch (Exception e) {
active = 0;
except = e; // threw exception, save for Start()/Resume()
} }
/* // Return whether or not script threw an exception.
* Return whether or not script threw an exception.
*/
return except; return except;
} }
@ -130,241 +115,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* @brief Script is being closed out. * @brief Script is being closed out.
* Terminate thread asap. * Terminate thread asap.
*/ */
public void Dispose ()
{
lock (activeLock) {
instance = null;
Monitor.PulseAll (activeLock);
}
}
/**
* @brief Determine if script is active.
* Returns: 0: nothing started or has returned
* Resume() must not be called
* Start() may be called
* Hiber() must not be called
* -1: thread has called Hiber()
* Resume() may be called
* Start() may be called
* Hiber() must not be called
* 1: thread is running
* Resume() must not be called
* Start() must not be called
* Hiber() may be called
*/
public int Active ()
{
return active;
}
/**
* @brief This thread executes the script event handler code.
*/
private void CallSEHThread ()
{
lock (activeLock) {
if (active <= 0) throw new Exception ("active=" + active);
except = null; // assume completion without exception
try {
instance.CallSEH (); // run script event handler
} catch (Exception e) {
except = e; // threw exception, save for Start()/Resume()
}
active = 0; // tell Start() or Resume() we're done
Monitor.PulseAll (activeLock);
}
}
/**
* @brief Called by the script event handler whenever it wants to hibernate.
*/
public void Hiber ()
{
if (active <= 0) throw new Exception ("active=" + active);
// tell Start() or Resume() we are hibernating
active = -1;
Monitor.PulseAll (activeLock);
// wait for Resume() or Dispose() to be called
while ((active < 0) && (instance != null)) {
Monitor.Wait (activeLock);
}
// don't execute any more script code, just exit
if (instance == null) {
throw new AbortedByDisposeException ();
}
}
/**
* @brief Number of remaining stack bytes.
*/
public int StackLeft ()
{
return 0x7FFFFFFF;
}
public class AbortedByDisposeException : Exception, IXMRUncatchable { }
/**
* @brief Pool of threads that run script event handlers.
*/
private class TredPoo {
private static readonly TimeSpan idleTimeSpan = new TimeSpan (0, 0, 1, 0, 0); // 1 minute
private static int tredPooAvail = 0;
private static object tredPooLock = new object ();
private static Queue<ThreadStart> tredPooQueue = new Queue<ThreadStart> ();
/**
* @brief Queue a function for execution in a system thread.
*/
public static void RunSomething (ThreadStart entry)
{
lock (tredPooLock) {
tredPooQueue.Enqueue (entry);
Monitor.Pulse (tredPooLock);
if (tredPooAvail < tredPooQueue.Count) {
new TredPoo ();
}
}
}
/**
* @brief Start a new system thread.
* It will shortly attempt to dequeue work or if none,
* add itself to the available thread list.
*/
private TredPoo ()
{
Thread thread = new Thread (Main);
thread.Name = "XMRUThread_sys";
thread.IsBackground = true;
thread.Start ();
tredPooAvail ++;
}
/**
* @brief Executes items from the queue or waits a little while
* if nothing. If idle for a while, it exits.
*/
private void Main ()
{
int first = 1;
ThreadStart entry;
while (true) {
lock (tredPooLock) {
tredPooAvail -= first;
first = 0;
while (tredPooQueue.Count <= 0) {
tredPooAvail ++;
bool keepgoing = Monitor.Wait (tredPooLock, idleTimeSpan);
-- tredPooAvail;
if (!keepgoing) return;
}
entry = tredPooQueue.Dequeue ();
}
entry ();
}
}
}
}
}
/*************************************\
* Use Mono.Tasklets.Continuations *
* - memcpy's stack *
\*************************************/
namespace OpenSim.Region.ScriptEngine.XMREngine {
public partial class XMRInstance {
public Mono.Tasklets.Continuation engstack;
public Mono.Tasklets.Continuation scrstack;
}
public class ScriptUThread_Con : IScriptUThread, IDisposable
{
private XMRInstance instance;
public ScriptUThread_Con (XMRInstance instance)
{
this.instance = instance;
}
private const int SAVEENGINESTACK = 0;
private const int LOADENGINESTACK = 1;
private const int SAVESCRIPTSTACK = 2;
private const int LOADSCRIPTSTACK = 3;
private Exception except;
private int active;
/**
* @brief Start script event handler from the beginning.
* Return when either the script event handler completes
* or the script calls Hiber().
* @returns null: script did not throw any exception so far
* else: script threw an exception
*/
public Exception StartEx ()
{
/*
* Save engine stack so we know how to jump back to engine in case
* the script calls Hiber().
*/
switch (instance.engstack.Store (SAVEENGINESTACK)) {
/*
* Engine stack has been saved, start running the event handler.
*/
case SAVEENGINESTACK: {
/*
* Run event handler according to stackFrames.
* In either case it is assumed that stateCode and eventCode
* indicate which event handler is to be called and that ehArgs
* points to the event handler argument list.
*/
active = 1;
except = null;
try {
instance.CallSEH ();
} catch (Exception e) {
except = e;
}
/*
* We now want to return to the script engine.
* Setting active = 0 means the microthread has exited.
* We need to call engstack.Restore() in case the script called Hiber()
* anywhere, we want to return out the corresponding Restore() and not the
* Start().
*/
active = 0;
instance.engstack.Restore (LOADENGINESTACK);
throw new Exception ("returned from Restore()");
}
/*
* Script called Hiber() somewhere so just return back out.
*/
case LOADENGINESTACK: {
break;
}
default: throw new Exception ("bad engstack code");
}
return except;
}
public void Dispose () public void Dispose ()
{ } { }
@ -389,75 +139,33 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
} }
/** /**
* @brief Called by the script wherever it wants to hibernate. * @brief Called by the script event handler whenever it wants to hibernate.
* So this means to save the scripts stack in 'instance.scrstack' then
* restore the engstack to cause us to return back to the engine.
*/ */
public void Hiber () public void Hiber ()
{ {
/* if (instance.callMode != XMRInstance.CallMode_NORMAL) {
* Save where we are in the script's code in 'instance.scrstack' throw new Exception ("callMode=" + instance.callMode);
* so we can wake the script when Resume() is called.
*/
switch (instance.scrstack.Store (SAVESCRIPTSTACK)) {
/*
* Script's stack is now saved in 'instance.scrstack'.
* Reload the engine's stack from 'instance.engstack' and jump to it.
*/
case SAVESCRIPTSTACK: {
active = -1;
instance.engstack.Restore (LOADENGINESTACK);
throw new Exception ("returned from Restore()");
}
/*
* Resume() was just called and we want to resume executing script code.
*/
case LOADSCRIPTSTACK: {
break;
}
default: throw new Exception ("bad scrstack code");
} }
}
/** switch (active) {
* @brief We now want to run some more script code from where it last hibernated
* until it either finishes the script event handler or until the script
* calls Hiber() again.
*/
public Exception ResumeEx ()
{
/*
* Save where we are in the engine's code in 'instance.engstack'
* so if the script calls Hiber() again or exits, we know how to get
* back to the engine.
*/
switch (instance.engstack.Store (SAVEENGINESTACK)) {
/* // the stack has been restored as a result of calling ResumeEx()
* This is original call to Resume() from the engine, // say the microthread is now active and resume processing
* jump to where we left off within Hiber(). case -1: {
*/
case SAVEENGINESTACK: {
active = 1; active = 1;
instance.scrstack.Restore (LOADSCRIPTSTACK); return;
throw new Exception ("returned from Restore()");
} }
/* // the script event handler wants to hibernate
* Script has called Hiber() again, so return back to // capture stack frames and unwind to Start() or Resume()
* script engine code. case 1: {
*/ instance.callMode = XMRInstance.CallMode_SAVE;
case LOADENGINESTACK: { instance.stackFrames = null;
break; throw new StackHibernateException ();
} }
default: throw new Exception ("bad engstack code"); default: throw new Exception ("active=" + active);
} }
return except;
} }
/** /**
@ -467,91 +175,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
{ {
return 0x7FFFFFFF; return 0x7FFFFFFF;
} }
public class StackHibernateException : Exception, IXMRUncatchable { }
} }
} }
/***********************************\
* Use Mono.Tasklets.MMRUThreads *
* - switches stack pointer *
\***********************************/
namespace OpenSim.Region.ScriptEngine.XMREngine {
public class ScriptUThread_MMR : IScriptUThread, IDisposable
{
private static Exception uthread_looked;
private static Type uttype;
private static Type uthread_entry;
private static MethodInfo uthread_dispose;
private static MethodInfo uthread_startex;
private static MethodInfo uthread_resumex;
private static MethodInfo uthread_suspend;
private static MethodInfo uthread_active;
private static MethodInfo uthread_stackleft;
public static Exception LoadMono ()
{
if ((uthread_looked == null) && (uthread_stackleft == null)) {
try {
Assembly mt = Assembly.Load ("Mono.Tasklets");
uttype = mt.GetType ("Mono.Tasklets.MMRUThread", true);
uthread_entry = mt.GetType ("Mono.Tasklets.MMRUThread+Entry", true);
uthread_dispose = uttype.GetMethod ("Dispose"); // no parameters, no return value
uthread_startex = uttype.GetMethod ("StartEx"); // takes uthread_entry delegate as parameter, returns exception
uthread_resumex = uttype.GetMethod ("ResumeEx"); // takes exception as parameter, returns exception
uthread_suspend = uttype.GetMethod ("Suspend", new Type[] { }); // no return value
uthread_active = uttype.GetMethod ("Active"); // no parameters, returns int
uthread_stackleft = uttype.GetMethod ("StackLeft"); // no parameters, returns IntPtr
} catch (Exception e) {
uthread_looked = new NotSupportedException ("'mmr' thread model requires patched mono", e);
}
}
return uthread_looked;
}
private static object[] resumex_args = new object[] { null };
private object uthread; // type MMRUThread
private object[] startex_args = new object[1];
public ScriptUThread_MMR (XMRInstance instance)
{
this.uthread = Activator.CreateInstance (uttype, new object[] { (IntPtr) instance.m_StackSize, instance.m_DescName });
startex_args[0] = Delegate.CreateDelegate (uthread_entry, instance, "CallSEH");
}
public void Dispose ()
{
uthread_dispose.Invoke (uthread, null);
uthread = null;
}
public Exception StartEx ()
{
return (Exception) uthread_startex.Invoke (uthread, startex_args);
}
public Exception ResumeEx ()
{
return (Exception) uthread_resumex.Invoke (uthread, resumex_args);
}
public void Hiber ()
{
uthread_suspend.Invoke (null, null);
}
public int Active ()
{
return (int) uthread_active.Invoke (uthread, null);
}
public int StackLeft ()
{
return (int) (IntPtr) uthread_stackleft.Invoke (null, null);
}
}
}

View File

@ -2418,28 +2418,7 @@
</Files> </Files>
</Project> </Project>
<!-- XMRengine --> <!-- XMRengine -->
<Project frameworkVersion="v4_6" name="Mono.Tasklets" path="OpenSim/Region/ScriptEngine/XMREngine" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../../bin/</ReferencePath>
<Files>
<Match pattern="MonoTaskletsDummy.cs" recurse="true">
<Exclude name="obj" pattern="obj"/>
</Match>
</Files>
</Project>
<Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.XMREngine" path="OpenSim/Region/ScriptEngine/XMREngine" type="Library"> <Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.XMREngine" path="OpenSim/Region/ScriptEngine/XMREngine" type="Library">
<Configuration name="Debug"> <Configuration name="Debug">
<Options> <Options>