using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.Remoting;
using System.IO;
namespace OpenSim.Region.ScriptEngine.DotNetEngine
{
public class AppDomainManager
{
private int MaxScriptsPerAppDomain = 1;
///
/// List of all AppDomains
///
private List AppDomains = new List();
private struct 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)
{
m_scriptEngine = scriptEngine;
}
///
/// Find a free AppDomain, creating one if necessary
///
/// Free AppDomain
internal AppDomain GetFreeAppDomain()
{
FreeAppDomains();
lock(GetLock) {
// Current full?
if (CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain)
{
AppDomains.Add(CurrentAD);
CurrentAD = new AppDomainStructure();
}
// No current
if (CurrentAD.CurrentAppDomain == null)
{
// Create a new current AppDomain
CurrentAD = new AppDomainStructure();
CurrentAD.ScriptsWaitingUnload = 0; // to avoid compile warning for not in use
CurrentAD.CurrentAppDomain = PrepareNewAppDomain();
}
// Increase number of scripts loaded
CurrentAD.ScriptsLoaded++;
// Return AppDomain
return CurrentAD.CurrentAppDomain;
} // 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 and configuration match current appdomain
// Construct and initialize settings for a second AppDomain.
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
//Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ScriptEngines");
//ads.ApplicationName = "DotNetScriptEngine";
//ads.DynamicBase = ads.ApplicationBase;
//Console.WriteLine("AppDomain BaseDirectory: " + ads.ApplicationBase);
ads.DisallowBindingRedirects = false;
ads.DisallowCodeDownload = true;
ads.ShadowCopyFiles = "true";
ads.ConfigurationFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
//foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
//{
// //Console.WriteLine("Loading: " + a.GetName(true));
// try
// {
// //AD.Load(a.GetName(true));
// }
// catch (Exception e)
// {
// //Console.WriteLine("FAILED load");
// }
//}
//Console.WriteLine("Assembly file: " + this.GetType().Assembly.CodeBase);
//Console.WriteLine("Assembly name: " + this.GetType().ToString());
//AD.CreateInstanceFrom(this.GetType().Assembly.CodeBase, "OpenSim.Region.ScriptEngine.DotNetEngine.ScriptEngine");
//AD.Load(this.GetType().Assembly.CodeBase);
Console.WriteLine("Done preparing new AppDomain.");
return AD;
}
///
/// Unload appdomains that are full and have only dead scripts
///
private void FreeAppDomains()
{
lock (FreeLock)
{
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{
if (ads.CurrentAppDomain != CurrentAD.CurrentAppDomain)
{
// Not current AppDomain
if (ads.ScriptsLoaded == ads.ScriptsWaitingUnload)
{
AppDomains.Remove(ads);
AppDomain.Unload(ads.CurrentAppDomain);
}
}
} // foreach
} // lock
}
///
/// Increase "dead script" counter for an AppDomain
///
///
[Obsolete("Needs optimizing!!!")]
public void StopScriptInAppDomain(AppDomain ad)
{
lock (FreeLock)
{
if (CurrentAD.CurrentAppDomain == ad)
{
CurrentAD.ScriptsWaitingUnload++;
return;
}
foreach (AppDomainStructure ads in new System.Collections.ArrayList(AppDomains))
{
if (ads.CurrentAppDomain == ad)
{
AppDomainStructure ads2 = ads;
ads2.ScriptsWaitingUnload++;
AppDomains.Remove(ads);
AppDomains.Add(ads2);
return;
}
} // foreach
} // lock
}
}
}