using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.Remoting;
using System.IO;
using OpenSim.Region.Environment.Scenes;
using OpenSim.Region.Environment.Scenes.Scripting;
using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL;
using OpenSim.Region.ScriptEngine.Common;
using libsecondlife;
namespace OpenSim.Region.ScriptEngine.DotNetEngine
{
public class AppDomainManager
{
private int MaxScriptsPerAppDomain = 3;
///
/// Internal list of all AppDomains
///
private List AppDomains = new List();
///
/// Structure to keep track of data around AppDomain
///
private class AppDomainStructure
{
///
/// The AppDomain itself
///
public AppDomain CurrentAppDomain;
///
/// Number of scripts loaded into AppDomain
///
public int ScriptsLoaded;
///
/// Number of dead scripts
///
public int ScriptsWaitingUnload;
}
///
/// Current AppDomain
///
private AppDomainStructure CurrentAD;
private object GetLock = new object(); // Mutex
private object FreeLock = new object(); // Mutex
//private ScriptEngine m_scriptEngine;
//public AppDomainManager(ScriptEngine scriptEngine)
public AppDomainManager()
{
//m_scriptEngine = scriptEngine;
}
///
/// Find a free AppDomain, creating one if necessary
///
/// Free AppDomain
private AppDomainStructure GetFreeAppDomain()
{
Console.WriteLine("Finding free AppDomain");
FreeAppDomains(); // Outsite lock, has its own GetLock
lock (GetLock)
{
// Current full?
if (CurrentAD != null && CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain)
{
// Add it to AppDomains list and empty current
AppDomains.Add(CurrentAD);
CurrentAD = null;
}
// No current
if (CurrentAD == null)
{
// Create a new current AppDomain
CurrentAD = new AppDomainStructure();
CurrentAD.CurrentAppDomain = PrepareNewAppDomain();
}
Console.WriteLine("Scripts loaded in this Appdomain: " + CurrentAD.ScriptsLoaded);
return CurrentAD;
} // lock
}
private int AppDomainNameCount;
///
/// Create and prepare a new AppDomain for scripts
///
/// The new AppDomain
private AppDomain PrepareNewAppDomain()
{
// Create and prepare a new AppDomain
AppDomainNameCount++;
// TODO: Currently security match current appdomain
// Construct and initialize settings for a second AppDomain.
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true;
ads.ShadowCopyFiles = "true"; // Enabled shadowing
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
// Return the new AppDomain
return AD;
}
///
/// Unload appdomains that are full and have only dead scripts
///
private void FreeAppDomains()
{
lock (FreeLock)
{
// Go through all
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{
// Don't process current AppDomain
if (ads.CurrentAppDomain != CurrentAD.CurrentAppDomain)
{
// Not current AppDomain
// Is number of unloaded bigger or equal to number of loaded?
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
{
// Remove from internal list
AppDomains.Remove(ads);
// Unload
AppDomain.Unload(ads.CurrentAppDomain);
}
}
} // foreach
} // lock
}
public OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass LoadScript(string FileName)
{
// Find next available AppDomain to put it in
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
//if (FreeAppDomain == null) Console.WriteLine("FreeAppDomain == null");
//if (FreeAppDomain.CurrentAppDomain == null) Console.WriteLine("FreeAppDomain.CurrentAppDomain == null");
Console.WriteLine("Loading into AppDomain: " + FileName);
LSL_BaseClass mbrt = (LSL_BaseClass)FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
//Type mytype = mbrt.GetType();
Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
// Increase script count in tihs AppDomain
FreeAppDomain.ScriptsLoaded++;
//mbrt.Start();
return mbrt;
//return (LSL_BaseClass)mbrt;
}
///
/// Increase "dead script" counter for an AppDomain
///
///
//[Obsolete("Needs fixing, needs a real purpose in life!!!")]
public void StopScript(AppDomain ad)
{
lock (FreeLock)
{
// Check if it is current AppDomain
if (CurrentAD.CurrentAppDomain == ad)
{
// Yes - increase
CurrentAD.ScriptsWaitingUnload++;
return;
}
// Lopp through all AppDomains
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{
if (ads.CurrentAppDomain == ad)
{
// Found it - messy code to increase structure
//AppDomainStructure ads2 = ads;
ads.ScriptsWaitingUnload++;
//AppDomains.Remove(ads);
//AppDomains.Add(ads2);
return;
}
} // foreach
} // lock
}
}
}