* Patched fixed merge from trunk

ThreadPoolClientBranch
Teravus Ovares 2008-02-24 15:21:08 +00:00
parent 882566a32f
commit ce1bbc0ae4
30 changed files with 1018 additions and 635 deletions

View File

@ -95,7 +95,6 @@ namespace OpenSim.Framework
tryGetRet = m_clients.TryGetValue(circuitCode, out client);
if (tryGetRet)
{
//m_log.Debug("[ClientManager]: Processing IN packet " + packet.Type.ToString());
client.InPacket(packet);
}
else

View File

@ -250,7 +250,9 @@ namespace OpenSim.Framework.Communications.Cache
}
else
{
m_log.DebugFormat("[ASSET CACHE]: Adding request for {0} {1}", isTexture ? "texture" : "asset", assetId);
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: Adding request for {0} {1}", isTexture ? "texture" : "asset", assetId);
#endif
NewAssetRequest req = new NewAssetRequest(assetId, callback);
@ -384,14 +386,17 @@ namespace OpenSim.Framework.Communications.Cache
}
}
}
m_log.DebugFormat("[ASSET CACHE]: Adding {0} {1} [{2}]: {3}.", temporary, type, asset.FullID, result);
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: Adding {0} {1} [{2}]: {3}.", temporary, type, asset.FullID, result);
#endif
}
// See IAssetReceiver
public void AssetReceived(AssetBase asset, bool IsTexture)
{
m_log.DebugFormat("[ASSET CACHE]: Recieved {0} [{1}]", IsTexture ? "texture" : "asset", asset.FullID);
#if DEBUG
m_log.DebugFormat("[ASSET CACHE]: Received {0} [{1}]", IsTexture ? "texture" : "asset", asset.FullID);
#endif
if (asset.FullID != LLUUID.Zero) // if it is set to zero then the asset wasn't found by the server
{
@ -405,7 +410,9 @@ namespace OpenSim.Framework.Communications.Cache
TextureImage image = new TextureImage(asset);
if (Textures.ContainsKey(image.FullID))
{
m_log.DebugFormat("[ASSET CACHE]: There's already an texture {0} in memory. Skipping.", asset.FullID);
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: There's already an texture {0} in memory. Skipping.", asset.FullID);
#endif
}
else
{
@ -422,7 +429,9 @@ namespace OpenSim.Framework.Communications.Cache
AssetInfo assetInf = new AssetInfo(asset);
if (Assets.ContainsKey(assetInf.FullID))
{
m_log.DebugFormat("[ASSET CACHE]: There's already an asset {0} in memory. Skipping.", asset.FullID);
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: There's already an asset {0} in memory. Skipping.", asset.FullID);
#endif
}
else
{
@ -435,7 +444,9 @@ namespace OpenSim.Framework.Communications.Cache
if (RequestedAssets.ContainsKey(assetInf.FullID))
{
m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID);
#if DEBUG
//m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID);
#endif
AssetRequest req = RequestedAssets[assetInf.FullID];
req.AssetInf = assetInf;

View File

@ -137,7 +137,9 @@ namespace OpenSim.Framework.Communications.Cache
req.IsTexture = isTexture;
m_assetRequests.Enqueue(req);
#if DEBUG
m_log.InfoFormat("[ASSET SERVER]: Added {0} to request queue", assetID);
#endif
}
public virtual void UpdateAsset(AssetBase asset)

View File

@ -52,7 +52,9 @@ namespace OpenSim.Framework.Communications.Cache
Stream s = null;
try
{
m_log.DebugFormat("[ASSETCACHE]: Querying for {0}", req.AssetID.ToString());
#if DEBUG
//m_log.DebugFormat("[GRID ASSET CLIENT]: Querying for {0}", req.AssetID.ToString());
#endif
RestClient rc = new RestClient(_assetServerUrl);
rc.AddResourcePath("assets");
@ -72,9 +74,9 @@ namespace OpenSim.Framework.Communications.Cache
}
catch (Exception e)
{
m_log.Error("[ASSETCACHE]: " + e.Message);
m_log.DebugFormat("[ASSETCACHE]: Getting asset {0}", req.AssetID.ToString());
m_log.Error("[ASSETCACHE]: " + e.StackTrace);
m_log.Error("[GRID ASSET CLIENT]: " + e.Message);
m_log.DebugFormat("[GRID ASSET CLIENT]: Getting asset {0}", req.AssetID.ToString());
m_log.Error("[GRID ASSET CLIENT]: " + e.StackTrace);
}
return null;
@ -95,19 +97,19 @@ namespace OpenSim.Framework.Communications.Cache
// XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
// xs.Serialize(s, asset);
// RestClient rc = new RestClient(_assetServerUrl);
m_log.Info("[ASSET]: Storing asset");
m_log.Info("[GRID ASSET CLIENT]: Storing asset");
//rc.AddResourcePath("assets");
// rc.RequestMethod = "POST";
// rc.Request(s);
//m_log.InfoFormat("[ASSET]: Stored {0}", rc);
m_log.Info("[ASSET]: Sending to " + _assetServerUrl + "/assets/");
m_log.Info("[GRID ASSET CLIENT]: Sending to " + _assetServerUrl + "/assets/");
RestObjectPoster.BeginPostObject<AssetBase>(_assetServerUrl + "/assets/", asset);
}
catch (Exception e)
{
m_log.Error("[ASSETS]: " + e.Message);
m_log.Error("[GRID ASSET CLIENT]: " + e.Message);
}
}

View File

@ -26,7 +26,14 @@
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Framework;
using OpenSim.Framework.Statistics.Interfaces;
using libsecondlife;
namespace OpenSim.Framework.Statistics
{
@ -42,6 +49,12 @@ namespace OpenSim.Framework.Statistics
public long AssetCacheMemoryUsage { get { return assetCacheMemoryUsage; } }
public long TextureCacheMemoryUsage { get { return textureCacheMemoryUsage; } }
/// <summary>
/// Retain a dictionary of all packet queues stats reporters
/// </summary>
private IDictionary<LLUUID, PacketQueueStatsReporter> packetQueueStatsReporters
= new Dictionary<LLUUID, PacketQueueStatsReporter>();
public void AddAsset(AssetBase asset)
{
assetsInCache++;
@ -58,17 +71,87 @@ namespace OpenSim.Framework.Statistics
}
}
/// <summary>
/// Register as a packet queue stats provider
/// </summary>
/// <param name="uuid">An agent LLUUID</param>
/// <param name="provider"></param>
public void RegisterPacketQueueStatsProvider(LLUUID uuid, IPullStatsProvider provider)
{
lock (packetQueueStatsReporters)
{
packetQueueStatsReporters[uuid] = new PacketQueueStatsReporter(provider);
}
}
/// <summary>
/// Deregister a packet queue stats provider
/// </summary>
/// <param name="uuid">An agent LLUUID</param>
public void DeregisterPacketQueueStatsProvider(LLUUID uuid)
{
lock (packetQueueStatsReporters)
{
packetQueueStatsReporters.Remove(uuid);
}
}
/// <summary>
/// Report back collected statistical information.
/// </summary>
/// <returns></returns>
public string Report()
{
return string.Format(
StringBuilder sb = new StringBuilder(Environment.NewLine);
sb.Append("ASSET CACHE STATISTICS");
sb.Append(Environment.NewLine);
sb.Append(
string.Format(
@"Asset cache contains {0,6} assets using {1,10:0.000}K
Texture cache contains {2,6} textures using {3,10:0.000}K",
AssetsInCache, AssetCacheMemoryUsage / 1024.0,
TexturesInCache, TextureCacheMemoryUsage / 1024.0);
Texture cache contains {2,6} textures using {3,10:0.000}K" + Environment.NewLine,
AssetsInCache, AssetCacheMemoryUsage / 1024.0,
TexturesInCache, TextureCacheMemoryUsage / 1024.0));
sb.Append(Environment.NewLine);
sb.Append("PACKET QUEUE STATISTICS");
sb.Append(Environment.NewLine);
sb.Append("Agent UUID ");
sb.Append(
string.Format(
" {0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
"Send", "In", "Out", "Resend", "Land", "Wind", "Cloud", "Task", "Texture", "Asset"));
sb.Append(Environment.NewLine);
foreach (LLUUID key in packetQueueStatsReporters.Keys)
{
sb.Append(string.Format("{0}: ", key));
sb.Append(packetQueueStatsReporters[key].Report());
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
}
/// <summary>
/// Pull packet queue stats from packet queues and report
/// </summary>
public class PacketQueueStatsReporter
{
private IPullStatsProvider m_statsProvider;
public PacketQueueStatsReporter(IPullStatsProvider provider)
{
m_statsProvider = provider;
}
/// <summary>
/// Report back collected statistical information.
/// </summary>
/// <returns></returns>
public string Report()
{
return m_statsProvider.GetStats();
}
}
}

View File

@ -224,6 +224,7 @@ namespace OpenSim.Region.ClientStack
private UpdateVector handler089 = null; //OnUpdatePrimGroupPosition;
private UpdatePrimRotation handler090 = null; //OnUpdatePrimGroupRotation;
private UpdatePrimGroupRotation handler091 = null; //OnUpdatePrimGroupMouseRotation;
private PacketStats handler093 = null; // OnPacketStats;
/* Properties */
@ -346,6 +347,7 @@ namespace OpenSim.Region.ClientStack
ack_pack(usePacket);
m_log.Debug("[ClientView]: Dealing with " + PausedPackets.Count.ToString() + " packets backlogged.");
ReadyForPackets = true;
// stuff the paused packets BACK into the thread queue. :)
while (PausedPackets.Count > 0)
{
@ -2065,7 +2067,11 @@ namespace OpenSim.Region.ClientStack
SetDefaultPrimPacketValues(objupdate);
objupdate.UpdateFlags = flags;
SetPrimPacketShapeData(objupdate, primShape);
if ((primShape.PCode == 111) || (primShape.PCode == 255))
{
objupdate.Data = new byte[1];
objupdate.Data[0] = primShape.State;
}
return objupdate;
}
@ -2655,7 +2661,7 @@ namespace OpenSim.Region.ClientStack
PausedPackets.Enqueue(NewPack);
return;
}
m_packetsReceived++;
// lock (m_packetQueue)
{
// Handle appended ACKs
@ -2833,9 +2839,10 @@ namespace OpenSim.Region.ClientStack
protected void SendPacketStats()
{
if (OnPacketStats != null)
handler093 = OnPacketStats;
if (handler093 != null)
{
OnPacketStats(m_packetsReceived - m_lastPacketsReceivedSentToScene, m_packetsSent - m_lastPacketsSentSentToScene, m_unAckedBytes);
handler093(m_packetsReceived - m_lastPacketsReceivedSentToScene, m_packetsSent - m_lastPacketsSentSentToScene, m_unAckedBytes);
m_lastPacketsReceivedSentToScene = m_packetsReceived;
m_lastPacketsSentSentToScene = m_packetsSent;
}

View File

@ -29,13 +29,16 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Timers;
using libsecondlife;
using libsecondlife.Packets;
using OpenSim.Framework;
using OpenSim.Framework.Statistics;
using OpenSim.Framework.Statistics.Interfaces;
using Timer=System.Timers.Timer;
namespace OpenSim.Region.ClientStack
{
public class PacketQueue
public class PacketQueue : IPullStatsProvider
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -129,6 +132,11 @@ namespace OpenSim.Region.ClientStack
// TIMERS needed for this
// LastThrottle = DateTime.Now.Ticks;
// ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
if (StatsManager.SimExtraStats != null)
{
StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(client.AgentId, this);
}
}
/* STANDARD QUEUE MANIPULATION INTERFACES */
@ -136,49 +144,37 @@ namespace OpenSim.Region.ClientStack
public void Enqueue(QueItem item)
{
// We could micro lock, but that will tend to actually
// probably be worse than just synchronizing on SendQueue
// enqueue inbound right away. forget throttle checking inbound!
if (item.Incoming)
lock (this)
{
SendQueue.Enqueue(item);
}
else
{
lock (this)
switch (item.throttleType)
{
switch (item.throttleType)
{
case ThrottleOutPacketType.Resend:
ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Texture:
ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Task:
ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Land:
ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Asset:
ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Cloud:
ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Wind:
ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Resend:
ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Texture:
ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Task:
ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Land:
ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Asset:
ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Cloud:
ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
break;
case ThrottleOutPacketType.Wind:
ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
break;
default:
// Acknowledgements and other such stuff should go directly to the blocking Queue
// Throttling them may and likely 'will' be problematic
Client.ProcessOutPacket(item.Packet);
break;
}
default:
// Acknowledgements and other such stuff should go directly to the blocking Queue
// Throttling them may and likely 'will' be problematic
Client.ProcessOutPacket(item.Packet);
break;
}
}
}
@ -227,6 +223,11 @@ namespace OpenSim.Region.ClientStack
{
m_enabled = false;
throttleTimer.Stop();
if (StatsManager.SimExtraStats != null)
{
StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(Client.AgentId);
}
}
private void ResetCounters()
@ -277,9 +278,6 @@ namespace OpenSim.Region.ClientStack
if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0)
{
QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
ResendThrottle.Add(qpack.Packet.ToBytes().Length);
@ -287,9 +285,6 @@ namespace OpenSim.Region.ClientStack
if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0)
{
QueItem qpack = LandOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
LandThrottle.Add(qpack.Packet.ToBytes().Length);
@ -297,9 +292,6 @@ namespace OpenSim.Region.ClientStack
if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0)
{
QueItem qpack = WindOutgoingPacketQueue.Dequeue();
// SendQueue.Enqueue(qpack);
//m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
WindThrottle.Add(qpack.Packet.ToBytes().Length);
@ -307,9 +299,6 @@ namespace OpenSim.Region.ClientStack
if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0)
{
QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
CloudThrottle.Add(qpack.Packet.ToBytes().Length);
@ -317,20 +306,13 @@ namespace OpenSim.Region.ClientStack
if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0)
{
QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
TaskThrottle.Add(qpack.Packet.ToBytes().Length);
}
if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0)
{
QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
TextureThrottle.Add(qpack.Packet.ToBytes().Length);
@ -338,9 +320,6 @@ namespace OpenSim.Region.ClientStack
if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0)
{
QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
//SendQueue.Enqueue(qpack);
// m_log.Debug("[PacketQueue]: ThrottleCheck Sending " + qpack.Incoming.ToString() + " packet " + qpack.Packet.Type.ToString());
Client.ProcessOutPacket(qpack.Packet);
TotalThrottle.Add(qpack.Packet.ToBytes().Length);
AssetThrottle.Add(qpack.Packet.ToBytes().Length);
@ -512,5 +491,21 @@ namespace OpenSim.Region.ClientStack
// effectively wiggling the slider causes things reset
ResetCounters();
}
// See IPullStatsProvider
public string GetStats()
{
return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
SendQueue.Count(),
IncomingPacketQueue.Count,
OutgoingPacketQueue.Count,
ResendOutgoingPacketQueue.Count,
LandOutgoingPacketQueue.Count,
WindOutgoingPacketQueue.Count,
CloudOutgoingPacketQueue.Count,
TaskOutgoingPacketQueue.Count,
TextureOutgoingPacketQueue.Count,
AssetOutgoingPacketQueue.Count);
}
}
}

View File

@ -88,9 +88,8 @@ namespace OpenSim.Region.ClientStack
public void Enqueue(uint CircuitCode, Packet packet)
{
//m_log.Debug("[PacketServer]: Enquing " + packet.Type.ToString() + " from " + CircuitCode.ToString());
//lock(PacketQueue)
PacketQueue.Enqueue(new QueuePacket(packet, CircuitCode));
IClientAPI client;
PacketQueue.Enqueue(new QueuePacket(packet, CircuitCode));
}
public IScene LocalScene

View File

@ -388,10 +388,10 @@ namespace OpenSim.Region.ClientStack
Server.SendTo(buffer, size, flags, sendto);
}
else
{
m_log.Debug("[UDPServer]: Failed to find person to send packet to!");
}
//else
//{
// m_log.Debug("[UDPServer]: Failed to find person to send packet to!");
//}
}
}

View File

@ -42,8 +42,8 @@ namespace OpenSim.Region.Environment.Modules
/// </summary>
public class UserTextureDownloadService
{
//private static readonly log4net.ILog m_log
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Holds texture senders before they have received the appropriate texture from the asset cache.
@ -138,7 +138,6 @@ namespace OpenSim.Region.Environment.Modules
// this texture could not be found
// TODO Send packet back to the client telling it not to expect the texture
// The absence of this packet doesn't appear to be causing it a problem right now
//m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Removing download stat for {0}", textureID);
m_scene.AddPendingDownloads(-1);
@ -150,7 +149,9 @@ namespace OpenSim.Region.Environment.Modules
}
else
{
throw new Exception("Got a texture with no sender object to handle it, this shouldn't happen");
m_log.WarnFormat(
"Got a texture uuid {0} with no sender object to handle it, this shouldn't happen",
textureID);
}
}
}

View File

@ -104,11 +104,16 @@ namespace OpenSim.Region.Environment.Scenes
{
if (ent is SceneObjectGroup)
{
if (((SceneObjectGroup) ent).LocalId == primLocalID)
{
((SceneObjectGroup) ent).GetProperties(remoteClient);
((SceneObjectGroup) ent).IsSelected = true;
LandManager.setPrimsTainted();
// A prim is only tainted if it's allowed to be edited by the person clicking it.
if (m_permissionManager.CanEditObjectPosition(remoteClient.AgentId, ((SceneObjectGroup)ent).UUID) || m_permissionManager.CanEditObject(remoteClient.AgentId, ((SceneObjectGroup)ent).UUID))
{
((SceneObjectGroup) ent).GetProperties(remoteClient);
((SceneObjectGroup) ent).IsSelected = true;
LandManager.setPrimsTainted();
}
break;
}
}
@ -130,9 +135,12 @@ namespace OpenSim.Region.Environment.Scenes
{
if (((SceneObjectGroup) ent).LocalId == primLocalID)
{
((SceneObjectGroup) ent).IsSelected = false;
LandManager.setPrimsTainted();
break;
if (m_permissionManager.CanEditObjectPosition(remoteClient.AgentId, ((SceneObjectGroup)ent).UUID) || m_permissionManager.CanEditObject(remoteClient.AgentId, ((SceneObjectGroup)ent).UUID))
{
((SceneObjectGroup) ent).IsSelected = false;
LandManager.setPrimsTainted();
break;
}
}
}
}

View File

@ -203,6 +203,14 @@ namespace OpenSim.Region.Environment.Scenes
if (m_rootPart.PhysActor != null)
{
m_rootPart.PhysActor.Selected = value;
// Pass it on to the children.
foreach (SceneObjectPart child in Children.Values)
{
if (child.PhysActor != null)
{
child.PhysActor.Selected = value;
}
}
}
}
}

View File

@ -228,6 +228,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }

View File

@ -895,6 +895,11 @@ namespace OpenSim.Region.Physics.BulletXPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }

View File

@ -124,6 +124,8 @@ namespace OpenSim.Region.Physics.Manager
public abstract PrimitiveBaseShape Shape { set; }
public abstract uint LocalID { set; }
public abstract bool Grabbed { set; }
public abstract bool Selected { set; }
@ -228,6 +230,11 @@ namespace OpenSim.Region.Physics.Manager
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }

View File

@ -87,6 +87,8 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool m_hackSentFall = false;
private bool m_hackSentFly = false;
private bool m_foundDebian = false;
public uint m_localID = 0;
private CollisionLocker ode;
private string m_name = String.Empty;
@ -94,6 +96,15 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool[] m_colliderarr = new bool[11];
private bool[] m_colliderGroundarr = new bool[11];
// Default we're a Character
private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
// Default, Collide with Other Geometries, spaces, bodies and characters.
private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
| CollisionCategories.Space
| CollisionCategories.Body
| CollisionCategories.Character
| CollisionCategories.Land);
private bool jumping = false;
//private float gravityAccel;
@ -157,6 +168,11 @@ namespace OpenSim.Region.Physics.OdePlugin
set { m_alwaysRun = value; }
}
public override uint LocalID
{
set { m_localID = value; }
}
public override bool Grabbed
{
set { return; }
@ -404,6 +420,10 @@ namespace OpenSim.Region.Physics.OdePlugin
int dAMotorEuler = 1;
_parent_scene.waitForSpaceUnlock(_parent_scene.space);
Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
Body = d.BodyCreate(_parent_scene.world);
d.BodySetPosition(Body, npositionX, npositionY, npositionZ);

View File

@ -52,12 +52,30 @@ namespace OpenSim.Region.Physics.OdePlugin
private PhysicsVector m_taintsize;
private PhysicsVector m_taintVelocity = PhysicsVector.Zero;
private Quaternion m_taintrot;
private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
| CollisionCategories.Space
| CollisionCategories.Body
| CollisionCategories.Character);
private bool m_taintshape = false;
private bool m_taintPhysics = false;
private bool m_collidesLand = true;
private bool m_collidesWater = false;
// Default we're a Geometry
private CollisionCategories m_collisionCategories = (CollisionCategories.Geom );
// Default, Collide with Other Geometries, spaces and Bodies
private CollisionCategories m_collisionFlags = m_default_collisionFlags;
public bool m_taintremove = false;
public bool m_taintdisable = false;
public bool m_disabled = false;
public bool m_taintadd = false;
public bool m_taintselected = false;
public uint m_localID = 0;
public GCHandle gc;
private CollisionLocker ode;
@ -74,6 +92,8 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool iscolliding = false;
private bool m_isphysical = false;
private bool m_isSelected = false;
private bool m_throttleUpdates = false;
private int throttleCounter = 0;
public int m_interpenetrationcount = 0;
@ -172,6 +192,11 @@ namespace OpenSim.Region.Physics.OdePlugin
set { return; }
}
public override uint LocalID
{
set { m_localID = value; }
}
public override bool Grabbed
{
set { return; }
@ -179,17 +204,59 @@ namespace OpenSim.Region.Physics.OdePlugin
public override bool Selected
{
set { return; }
set {
// This only makes the object not collidable if the object
// is physical or the object is modified somehow *IN THE FUTURE*
// without this, if an avatar selects prim, they can walk right
// through it while it's selected
if ((m_isphysical && !_zeroFlag) || !value)
{
m_taintselected = value;
_parent_scene.AddPhysicsActorTaint(this);
}
else
{
m_taintselected = value;
m_isSelected = value;
}
}
}
public void SetGeom(IntPtr geom)
{
prev_geom = prim_geom;
prim_geom = geom;
if (prim_geom != (IntPtr)0)
{
d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
}
//m_log.Warn("Setting Geom to: " + prim_geom);
}
public void enableBodySoft()
{
if (m_isphysical)
if (Body != (IntPtr)0)
d.BodyEnable(Body);
m_disabled = false;
}
public void disableBodySoft()
{
m_disabled = true;
if (m_isphysical)
if (Body != (IntPtr)0)
d.BodyDisable(Body);
}
public void enableBody()
{
// Sets the geom to a body
@ -204,6 +271,13 @@ namespace OpenSim.Region.Physics.OdePlugin
myrot.Z = _orientation.z;
d.BodySetQuaternion(Body, ref myrot);
d.GeomSetBody(prim_geom, Body);
m_collisionCategories |= CollisionCategories.Body;
m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
d.BodySetAutoDisableFlag(Body, true);
d.BodySetAutoDisableSteps(Body, 20);
@ -332,6 +406,15 @@ namespace OpenSim.Region.Physics.OdePlugin
//this kills the body so things like 'mesh' can re-create it.
if (Body != (IntPtr) 0)
{
m_collisionCategories &= ~CollisionCategories.Body;
m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
if (prim_geom != (IntPtr)0)
{
d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
}
_parent_scene.remActivePrim(this);
d.BodyDestroy(Body);
Body = (IntPtr) 0;
@ -425,10 +508,81 @@ namespace OpenSim.Region.Physics.OdePlugin
if (m_taintdisable)
changedisable(timestep);
if (m_taintselected != m_isSelected)
changeSelectedStatus(timestep);
if (m_taintVelocity != PhysicsVector.Zero)
changevelocity(timestep);
}
private void changeSelectedStatus(float timestep)
{
while (ode.lockquery())
{
}
ode.dlock(_parent_scene.world);
if (m_taintselected)
{
m_collisionCategories = CollisionCategories.Selected;
m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
// We do the body disable soft twice because 'in theory' a collision could have happened
// in between the disabling and the collision properties setting
// which would wake the physical body up from a soft disabling and potentially cause it to fall
// through the ground.
if (m_isphysical)
{
disableBodySoft();
}
if (prim_geom != (IntPtr)0)
{
d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
}
if (m_isphysical)
{
disableBodySoft();
}
}
else
{
m_collisionCategories = CollisionCategories.Geom;
if (m_isphysical)
m_collisionCategories |= CollisionCategories.Body;
m_collisionFlags = m_default_collisionFlags;
if (m_collidesLand)
m_collisionFlags |= CollisionCategories.Land;
if (m_collidesWater)
m_collisionFlags |= CollisionCategories.Water;
if (prim_geom != (IntPtr)0)
{
d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
}
if (m_isphysical)
enableBodySoft();
}
ode.dunlock(_parent_scene.world);
resetCollisionAccounting();
m_isSelected = m_taintselected;
}
public void ResetTaints()
{
@ -438,6 +592,8 @@ namespace OpenSim.Region.Physics.OdePlugin
m_taintPhysics = m_isphysical;
m_taintselected = m_isSelected;
m_taintsize = _size;
@ -586,6 +742,9 @@ namespace OpenSim.Region.Physics.OdePlugin
ode.dunlock(_parent_scene.world);
_parent_scene.geom_name_map[prim_geom] = this.m_primName;
_parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
changeSelectedStatus(timestep);
m_taintadd = false;
@ -630,6 +789,8 @@ namespace OpenSim.Region.Physics.OdePlugin
}
ode.dunlock(_parent_scene.world);
changeSelectedStatus(timestep);
resetCollisionAccounting();
m_taintposition = _position;
}
@ -682,7 +843,7 @@ namespace OpenSim.Region.Physics.OdePlugin
m_taintdisable = false;
}
public void changePhysicsStatus(float timestap)
public void changePhysicsStatus(float timestep)
{
lock (ode)
{
@ -709,6 +870,8 @@ namespace OpenSim.Region.Physics.OdePlugin
ode.dunlock(_parent_scene.world);
}
changeSelectedStatus(timestep);
resetCollisionAccounting();
m_taintPhysics = m_isphysical;
}
@ -880,6 +1043,8 @@ namespace OpenSim.Region.Physics.OdePlugin
ode.dunlock(_parent_scene.world);
changeSelectedStatus(timestamp);
resetCollisionAccounting();
m_taintsize = _size;
}
@ -927,7 +1092,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// Re creates body on size.
// EnableBody also does setMass()
enableBody();
d.BodyEnable(Body);
}
}
else
@ -1032,66 +1197,76 @@ namespace OpenSim.Region.Physics.OdePlugin
d.BodyEnable(Body);
}
}
_parent_scene.geom_name_map[prim_geom] = oldname;
ode.dunlock(_parent_scene.world);
changeSelectedStatus(timestamp);
resetCollisionAccounting();
m_taintshape = false;
}
public void changeAddForce(float timestamp)
{
while (ode.lockquery())
{
}
ode.dlock(_parent_scene.world);
lock (m_forcelist)
{
//m_log.Info("[PHYSICS]: dequeing forcelist");
if (IsPhysical)
{
PhysicsVector iforce = new PhysicsVector();
for (int i = 0; i < m_forcelist.Count; i++)
{
iforce = iforce + (m_forcelist[i]*100);
}
d.BodyEnable(Body);
d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
}
m_forcelist.Clear();
}
ode.dunlock(_parent_scene.world);
m_collisionscore = 0;
m_interpenetrationcount = 0;
m_taintforce = false;
}
private void changevelocity(float timestep)
{
lock (ode)
if (!m_isSelected)
{
while (ode.lockquery())
{
}
ode.dlock(_parent_scene.world);
System.Threading.Thread.Sleep(20);
if (IsPhysical)
lock (m_forcelist)
{
if (Body != (IntPtr)0)
//m_log.Info("[PHYSICS]: dequeing forcelist");
if (IsPhysical)
{
d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
PhysicsVector iforce = new PhysicsVector();
for (int i = 0; i < m_forcelist.Count; i++)
{
iforce = iforce + (m_forcelist[i] * 100);
}
d.BodyEnable(Body);
d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
}
m_forcelist.Clear();
}
ode.dunlock(_parent_scene.world);
m_collisionscore = 0;
m_interpenetrationcount = 0;
}
m_taintforce = false;
}
private void changevelocity(float timestep)
{
if (!m_isSelected)
{
lock (ode)
{
while (ode.lockquery())
{
}
ode.dlock(_parent_scene.world);
System.Threading.Thread.Sleep(20);
if (IsPhysical)
{
if (Body != (IntPtr)0)
{
d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
}
}
ode.dunlock(_parent_scene.world);
}
//resetCollisionAccounting();
}
//resetCollisionAccounting();
m_taintVelocity = PhysicsVector.Zero;
}
public override bool IsPhysical
@ -1275,6 +1450,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{
// no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
PhysicsVector pv = new PhysicsVector(0, 0, 0);
bool lastZeroFlag = _zeroFlag;
if (Body != (IntPtr) 0)
{
d.Vector3 vec = d.BodyGetPosition(Body);
@ -1371,6 +1547,9 @@ namespace OpenSim.Region.Physics.OdePlugin
}
else
{
if (lastZeroFlag != _zeroFlag)
base.RequestPhysicsterseUpdate();
m_lastVelocity = _velocity;
_position = l_position;

View File

@ -78,6 +78,21 @@ namespace OpenSim.Region.Physics.OdePlugin
}
}
[Flags]
public enum CollisionCategories : int
{
Disabled = 0,
Geom = 0x00000001,
Body = 0x00000002,
Space = 0x00000004,
Character = 0x00000008,
Land = 0x00000010,
Water = 0x00000020,
Wind = 0x00000040,
Sensor = 0x00000080,
Selected = 0x00000100
}
public class OdeScene : PhysicsScene
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -997,6 +1012,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{
// creating a new space for prim and inserting it into main space.
staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
waitForSpaceUnlock(space);
d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
@ -1656,6 +1672,12 @@ namespace OpenSim.Region.Physics.OdePlugin
offset, thickness, wrap);
d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
LandGeom = d.CreateHeightfield(space, HeightmapData, 1);
if (LandGeom != (IntPtr)0)
{
d.GeomSetCategoryBits(LandGeom, (int)(CollisionCategories.Land));
d.GeomSetCollideBits(LandGeom, (int)(CollisionCategories.Space));
}
geom_name_map[LandGeom] = "Terrain";
d.Matrix3 R = new d.Matrix3();

View File

@ -357,6 +357,11 @@ namespace OpenSim.Region.Physics.POSPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }
@ -645,6 +650,11 @@ namespace OpenSim.Region.Physics.POSPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }

View File

@ -227,6 +227,11 @@ namespace OpenSim.Region.Physics.PhysXPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }
@ -437,6 +442,11 @@ namespace OpenSim.Region.Physics.PhysXPlugin
set { return; }
}
public override uint LocalID
{
set { return; }
}
public override bool Grabbed
{
set { return; }

View File

@ -41,8 +41,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// </summary>
public class AsyncLSLCommandManager : iScriptEngineFunctionModule
{
private Thread cmdHandlerThread;
private int cmdHandlerThreadCycleSleepms;
private static Thread cmdHandlerThread;
private static int cmdHandlerThreadCycleSleepms;
private ScriptEngine m_ScriptEngine;
@ -51,18 +51,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
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();
OpenSim.Framework.ThreadTracker.Add(cmdHandlerThread);
StartThread();
}
private void StartThread()
{
if (cmdHandlerThread == null)
{
// Start the thread that will be doing the work
cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
cmdHandlerThread.Name = "AsyncLSLCmdHandlerThread";
cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
cmdHandlerThread.IsBackground = true;
cmdHandlerThread.Start();
OpenSim.Framework.ThreadTracker.Add(cmdHandlerThread);
}
}
public void ReadConfig()
{
cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50);
cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 100);
}
~AsyncLSLCommandManager()
@ -84,33 +92,49 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
private void CmdHandlerThreadLoop()
private static 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);
try
{
while (true)
{
Thread.Sleep(cmdHandlerThreadCycleSleepms);
//lock (ScriptEngine.ScriptEngines)
//{
foreach (ScriptEngine se in new ArrayList(ScriptEngine.ScriptEngines))
{
se.m_ASYNCLSLCommandManager.DoOneCmdHandlerPass();
}
//}
// Sleep before next cycle
//Thread.Sleep(cmdHandlerThreadCycleSleepms);
}
}
catch
{
}
}
}
internal void DoOneCmdHandlerPass()
{
// Check timers
CheckTimerEvents();
// Check HttpRequests
CheckHttpRequests();
// Check XMLRPCRequests
CheckXMLRPCRequests();
// Check Listeners
CheckListeners();
}
/// <summary>
/// Remove a specific script (and all its pending commands)
/// </summary>
/// <param name="m_localID"></param>
/// <param name="m_itemID"></param>
/// <param name="localID"></param>
/// <param name="itemID"></param>
public void RemoveScript(uint localID, LLUUID itemID)
{
// Remove a specific script

View File

@ -45,7 +45,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public class EventQueueManager : iScriptEngineFunctionModule
{
//
// Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
// Class is instanced in "ScriptEngine" and used by "EventManager" which is also instanced in "ScriptEngine".
//
// Class purpose is to queue and execute functions that are received by "EventManager":
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
@ -68,25 +68,25 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// List of threads (classes) processing event queue
/// Note that this may or may not be a reference to a static object depending on PrivateRegionThreads config setting.
/// </summary>
internal List<EventQueueThreadClass> eventQueueThreads; // Thread pool that we work on
internal static List<EventQueueThreadClass> eventQueueThreads = new List<EventQueueThreadClass>(); // Thread pool that we work on
/// <summary>
/// Locking access to eventQueueThreads AND staticGlobalEventQueueThreads.
/// </summary>
// private object eventQueueThreadsLock = new object();
// Static objects for referencing the objects above if we don't have private threads:
internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
//internal static List<EventQueueThreadClass> staticEventQueueThreads; // A static reference used if we don't use private threads
// internal static object staticEventQueueThreadsLock; // Statick lock object reference for same reason
/// <summary>
/// Global static list of all threads (classes) processing event queue -- used by max enforcment thread
/// </summary>
private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
//private List<EventQueueThreadClass> staticGlobalEventQueueThreads = new List<EventQueueThreadClass>();
/// <summary>
/// Used internally to specify how many threads should exit gracefully
/// </summary>
public int ThreadsToExit;
public object ThreadsToExitLock = new object();
public static int ThreadsToExit;
public static object ThreadsToExitLock = new object();
//public object queueLock = new object(); // Mutex lock object
@ -94,14 +94,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// <summary>
/// How many threads to process queue with
/// </summary>
internal int numberOfThreads;
internal static int numberOfThreads;
internal static int EventExecutionMaxQueueSize;
/// <summary>
/// Maximum time one function can use for execution before we perform a thread kill.
/// </summary>
private int maxFunctionExecutionTimems
private static int maxFunctionExecutionTimems
{
get { return (int)(maxFunctionExecutionTimens / 10000); }
set { maxFunctionExecutionTimens = value * 10000; }
@ -111,15 +111,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// Contains nanoseconds version of maxFunctionExecutionTimems so that it matches time calculations better (performance reasons).
/// WARNING! ONLY UPDATE maxFunctionExecutionTimems, NEVER THIS DIRECTLY.
/// </summary>
public long maxFunctionExecutionTimens;
public static long maxFunctionExecutionTimens;
/// <summary>
/// Enforce max execution time
/// </summary>
public bool EnforceMaxExecutionTime;
public static bool EnforceMaxExecutionTime;
/// <summary>
/// Kill script (unload) when it exceeds execution time
/// </summary>
private bool KillScriptOnMaxFunctionExecutionTime;
private static bool KillScriptOnMaxFunctionExecutionTime;
/// <summary>
/// List of localID locks for mutex processing of script events
@ -172,33 +172,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
m_ScriptEngine = _ScriptEngine;
// TODO: We need to move from single EventQueueManager to list of it in to share threads
bool PrivateRegionThreads = true; // m_ScriptEngine.ScriptConfigSource.GetBoolean("PrivateRegionThreads", false);
// Create thread pool list and lock object
// Determine from config if threads should be dedicated to regions or shared
if (PrivateRegionThreads)
{
// PRIVATE THREAD POOL PER REGION
eventQueueThreads = new List<EventQueueThreadClass>();
// eventQueueThreadsLock = new object();
}
else
{
// SHARED THREAD POOL
// Crate the static objects
if (staticEventQueueThreads == null)
staticEventQueueThreads = new List<EventQueueThreadClass>();
// if (staticEventQueueThreadsLock == null)
// staticEventQueueThreadsLock = new object();
// Now reference our locals to them
eventQueueThreads = staticEventQueueThreads;
//eventQueueThreadsLock = staticEventQueueThreadsLock;
}
ReadConfig();
AdjustNumberOfScriptThreads();
}
public void ReadConfig()
@ -230,18 +205,18 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
private void Stop()
{
if (eventQueueThreads != null && eventQueueThreads != null)
if (eventQueueThreads != null)
{
// Kill worker threads
//lock (eventQueueThreads)
//{
lock (eventQueueThreads)
{
foreach (EventQueueThreadClass EventQueueThread in new ArrayList(eventQueueThreads))
{
AbortThreadClass(EventQueueThread);
}
//eventQueueThreads.Clear();
//staticGlobalEventQueueThreads.Clear();
//}
}
}
// Remove all entries from our event queue
@ -256,9 +231,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#region " Start / stop script execution threads (ThreadClasses) "
private void StartNewThreadClass()
{
EventQueueThreadClass eqtc = new EventQueueThreadClass(this);
EventQueueThreadClass eqtc = new EventQueueThreadClass();
eventQueueThreads.Add(eqtc);
staticGlobalEventQueueThreads.Add(eqtc);
m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started new script execution thread. Current thread count: " + eventQueueThreads.Count);
}
@ -266,8 +240,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
if (eventQueueThreads.Contains(threadClass))
eventQueueThreads.Remove(threadClass);
if (staticGlobalEventQueueThreads.Contains(threadClass))
staticGlobalEventQueueThreads.Remove(threadClass);
try
{
@ -426,7 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// Iterate through all ScriptThreadClasses and check how long their current function has been executing
lock (eventQueueThreads)
{
foreach (EventQueueThreadClass EventQueueThread in staticGlobalEventQueueThreads)
foreach (EventQueueThreadClass EventQueueThread in eventQueueThreads)
{
// Is thread currently executing anything?
if (EventQueueThread.InExecution)
@ -452,14 +424,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
#endregion
/// <summary>
/// If set to true then threads and stuff should try to make a graceful exit
/// </summary>
public bool PleaseShutdown
{
get { return _PleaseShutdown; }
set { _PleaseShutdown = value; }
}
private bool _PleaseShutdown = false;
///// <summary>
///// If set to true then threads and stuff should try to make a graceful exit
///// </summary>
//public bool PleaseShutdown
//{
// get { return _PleaseShutdown; }
// set { _PleaseShutdown = value; }
//}
//private bool _PleaseShutdown = false;
}
}

View File

@ -27,6 +27,7 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
@ -40,27 +41,27 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// <summary>
/// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class
/// </summary>
public class EventQueueThreadClass: iScriptEngineFunctionModule
public class EventQueueThreadClass : iScriptEngineFunctionModule
{
/// <summary>
/// How many ms to sleep if queue is empty
/// </summary>
private int nothingToDoSleepms;// = 50;
private ThreadPriority MyThreadPriority;
private static int nothingToDoSleepms;// = 50;
private static ThreadPriority MyThreadPriority;
public long LastExecutionStarted;
public bool InExecution = false;
public bool KillCurrentScript = false;
private EventQueueManager eventQueueManager;
//private EventQueueManager eventQueueManager;
public Thread EventQueueThread;
private static int ThreadCount = 0;
private string ScriptEngineName = "ScriptEngine.Common";
public EventQueueThreadClass(EventQueueManager eqm)
public EventQueueThreadClass()//EventQueueManager eqm
{
eventQueueManager = eqm;
//eventQueueManager = eqm;
ReadConfig();
Start();
}
@ -72,34 +73,40 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
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())
lock (ScriptEngine.ScriptEngines)
{
case "lowest":
MyThreadPriority = ThreadPriority.Lowest;
break;
case "belownormal":
MyThreadPriority = ThreadPriority.BelowNormal;
break;
case "normal":
MyThreadPriority = ThreadPriority.Normal;
break;
case "abovenormal":
MyThreadPriority = ThreadPriority.AboveNormal;
break;
case "highest":
MyThreadPriority = ThreadPriority.Highest;
break;
default:
MyThreadPriority = ThreadPriority.BelowNormal; // Default
eventQueueManager.m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri + "\" in config file. Defaulting to \"BelowNormal\".");
break;
}
foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
{
ScriptEngineName = m_ScriptEngine.ScriptEngineName;
nothingToDoSleepms = 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 = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal");
switch (pri.ToLower())
{
case "lowest":
MyThreadPriority = ThreadPriority.Lowest;
break;
case "belownormal":
MyThreadPriority = ThreadPriority.BelowNormal;
break;
case "normal":
MyThreadPriority = ThreadPriority.Normal;
break;
case "abovenormal":
MyThreadPriority = ThreadPriority.AboveNormal;
break;
case "highest":
MyThreadPriority = ThreadPriority.Highest;
break;
default:
MyThreadPriority = ThreadPriority.BelowNormal; // Default
m_ScriptEngine.Log.Error("[ScriptEngineBase]: Unknown priority type \"" + pri +
"\" in config file. Defaulting to \"BelowNormal\".");
break;
}
}
}
// Now set that priority
if (EventQueueThread != null)
if (EventQueueThread.IsAlive)
@ -127,8 +134,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public void Stop()
{
PleaseShutdown = true; // Set shutdown flag
Thread.Sleep(100); // Wait a bit
//PleaseShutdown = true; // Set shutdown flag
//Thread.Sleep(100); // Wait a bit
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
{
try
@ -143,6 +150,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
private ScriptEngine lastScriptEngine;
/// <summary>
/// Queue processing thread loop
/// </summary>
@ -151,171 +160,24 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
//myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned");
try
{
while (true)
while (true)
{
try
{
EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct();
while (true)
{
// Every now and then check if we should shut down
if (PleaseShutdown || eventQueueManager.ThreadsToExit > 0)
{
// Someone should shut down, lets get exclusive lock
lock (eventQueueManager.ThreadsToExitLock)
{
// Lets re-check in case someone grabbed it
if (eventQueueManager.ThreadsToExit > 0)
{
// Its crowded here so we'll shut down
eventQueueManager.ThreadsToExit--;
Stop();
return;
}
else
{
// We have been asked to shut down
Stop();
return;
}
}
}
//try
// {
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
Thread.Sleep(nothingToDoSleepms);
}
else
{
// Something in queue, process
//myScriptEngine.Log.Info("[" + 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.eventQueue)
{
GotItem = false;
for (int qc = 0; qc < eventQueueManager.eventQueue.Count; qc++)
{
// Get queue item
QIS = eventQueueManager.eventQueue.Dequeue();
// Check if object is being processed by someone else
if (eventQueueManager.TryLock(QIS.localID) == false)
{
// Object is already being processed, requeue it
eventQueueManager.eventQueue.Enqueue(QIS);
}
else
{
// We have lock on an object and can process it
GotItem = true;
break;
}
}
}
if (GotItem == true)
{
// Execute function
try
{
///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
#if DEBUG
//eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
// "Executing event:\r\n"
// + "QIS.localID: " + QIS.localID
// + ", QIS.itemID: " + QIS.itemID
// + ", QIS.functionName: " +
// QIS.functionName);
#endif
LastExecutionStarted = DateTime.Now.Ticks;
KillCurrentScript = false;
InExecution = true;
eventQueueManager.m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
QIS.itemID,
QIS.functionName,
QIS.llDetectParams,
QIS.param);
InExecution = false;
}
catch (Exception e)
{
InExecution = false;
// DISPLAY ERROR INWORLD
string text = "Error executing script function \"" + QIS.functionName +
"\":\r\n";
if (e.InnerException != null)
{
// Send inner exception
text += e.InnerException.Message.ToString();
}
else
{
text += "\r\n";
// Send normal
text += e.Message.ToString();
}
if (KillCurrentScript)
text += "\r\nScript will be deactivated!";
try
{
if (text.Length > 1500)
text = text.Substring(0, 1500);
IScriptHost m_host =
eventQueueManager.m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
//if (m_host != null)
//{
eventQueueManager.m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
ChatTypeEnum.Say, 0,
m_host.AbsolutePosition,
m_host.Name, m_host.UUID);
}
catch
{
//}
//else
//{
// T oconsole
eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: " +
"Unable to send text in-world:\r\n" +
text);
}
finally
{
// So we are done sending message in-world
if (KillCurrentScript)
{
eventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
QIS.localID, QIS.itemID);
}
}
}
finally
{
InExecution = false;
eventQueueManager.ReleaseLock(QIS.localID);
}
}
}
DoProcessQueue();
}
}
catch (ThreadAbortException tae)
{
eventQueueManager.m_ScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
if (lastScriptEngine != null)
lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function.");
}
catch (Exception e)
{
eventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
if (lastScriptEngine != null)
lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString());
}
}
}
@ -325,14 +187,178 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
/// <summary>
/// If set to true then threads and stuff should try to make a graceful exit
/// </summary>
public bool PleaseShutdown
public void DoProcessQueue()
{
get { return _PleaseShutdown; }
set { _PleaseShutdown = value; }
//lock (ScriptEngine.ScriptEngines)
//{
foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines))
{
lastScriptEngine = m_ScriptEngine;
// Every now and then check if we should shut down
//if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0)
//{
// // Someone should shut down, lets get exclusive lock
// lock (EventQueueManager.ThreadsToExitLock)
// {
// // Lets re-check in case someone grabbed it
// if (EventQueueManager.ThreadsToExit > 0)
// {
// // Its crowded here so we'll shut down
// EventQueueManager.ThreadsToExit--;
// Stop();
// return;
// }
// else
// {
// // We have been asked to shut down
// Stop();
// return;
// }
// }
//}
//try
// {
EventQueueManager.QueueItemStruct QIS = BlankQIS;
bool GotItem = false;
//if (PleaseShutdown)
// return;
if (m_ScriptEngine.m_EventQueueManager == null || m_ScriptEngine.m_EventQueueManager.eventQueue == null)
continue;
if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0)
{
// Nothing to do? Sleep a bit waiting for something to do
Thread.Sleep(nothingToDoSleepms);
}
else
{
// Something in queue, process
//myScriptEngine.Log.Info("[" + 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 (m_ScriptEngine.m_EventQueueManager.eventQueue)
{
GotItem = false;
for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++)
{
// Get queue item
QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue();
// Check if object is being processed by someone else
if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false)
{
// Object is already being processed, requeue it
m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS);
}
else
{
// We have lock on an object and can process it
GotItem = true;
break;
}
}
}
if (GotItem == true)
{
// Execute function
try
{
///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
#if DEBUG
//eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " +
// "Executing event:\r\n"
// + "QIS.localID: " + QIS.localID
// + ", QIS.itemID: " + QIS.itemID
// + ", QIS.functionName: " +
// QIS.functionName);
#endif
LastExecutionStarted = DateTime.Now.Ticks;
KillCurrentScript = false;
InExecution = true;
m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID,
QIS.itemID,
QIS.functionName,
QIS.llDetectParams,
QIS.param);
InExecution = false;
}
catch (Exception e)
{
InExecution = false;
// DISPLAY ERROR INWORLD
string text = "Error executing script function \"" + QIS.functionName +
"\":\r\n";
if (e.InnerException != null)
{
// Send inner exception
text += e.InnerException.Message.ToString();
}
else
{
text += "\r\n";
// Send normal
text += e.Message.ToString();
}
if (KillCurrentScript)
text += "\r\nScript will be deactivated!";
try
{
if (text.Length > 1500)
text = text.Substring(0, 1500);
IScriptHost m_host =
m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
//if (m_host != null)
//{
m_ScriptEngine.World.SimChat(Helpers.StringToField(text),
ChatTypeEnum.Say, 0,
m_host.AbsolutePosition,
m_host.Name, m_host.UUID);
}
catch
{
//}
//else
//{
// T oconsole
m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName +
"]: " +
"Unable to send text in-world:\r\n" +
text);
}
finally
{
// So we are done sending message in-world
if (KillCurrentScript)
{
m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript(
QIS.localID, QIS.itemID);
}
}
}
finally
{
InExecution = false;
m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID);
}
}
}
}
// }
}
private bool _PleaseShutdown = false;
///// <summary>
///// If set to true then threads and stuff should try to make a graceful exit
///// </summary>
//public bool PleaseShutdown
//{
// get { return _PleaseShutdown; }
// set { _PleaseShutdown = value; }
//}
//private bool _PleaseShutdown = false;
}
}

View File

@ -27,6 +27,7 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
@ -38,12 +39,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// </summary>
public class MaintenanceThread : iScriptEngineFunctionModule
{
public ScriptEngine m_ScriptEngine;
//public ScriptEngine m_ScriptEngine;
private int MaintenanceLoopms;
private int MaintenanceLoopTicks_ScriptLoadUnload;
private int MaintenanceLoopTicks_Other;
public MaintenanceThread(ScriptEngine _ScriptEngine)
public MaintenanceThread()
{
m_ScriptEngine = _ScriptEngine;
//m_ScriptEngine = _ScriptEngine;
ReadConfig();
@ -58,7 +62,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public void ReadConfig()
{
MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
// Bad hack, but we need a m_ScriptEngine :)
lock (ScriptEngine.ScriptEngines)
{
foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines)
{
MaintenanceLoopms = m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopms", 50);
MaintenanceLoopTicks_ScriptLoadUnload =
m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_ScriptLoadUnload", 1);
MaintenanceLoopTicks_Other =
m_ScriptEngine.ScriptConfigSource.GetInt("MaintenanceLoopTicks_Other", 10);
return;
}
}
}
#region " Maintenance thread "
@ -90,14 +107,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#if DEBUG
//m_ScriptEngine.Log.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: StopMaintenanceThread() called");
#endif
PleaseShutdown = true;
//PleaseShutdown = true;
Thread.Sleep(100);
try
{
if (MaintenanceThreadThread != null && MaintenanceThreadThread.IsAlive)
{
MaintenanceThreadThread.Abort();
}
{
MaintenanceThreadThread.Abort();
}
}
catch (Exception ex)
{
@ -105,17 +122,23 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
private ScriptEngine lastScriptEngine; // Keep track of what ScriptEngine instance we are at so we can give exception
/// <summary>
/// A thread should run in this loop and check all running scripts
/// </summary>
public void MaintenanceLoop()
{
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.");
//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.");
long Last_maxFunctionExecutionTimens = 0; // DateTime.Now.Ticks;
long Last_ReReadConfigFilens = DateTime.Now.Ticks;
int MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
int MaintenanceLoopTicks_Other_Count = 0;
bool MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
bool MaintenanceLoopTicks_Other_ResetCount = false;
while (true)
{
try
@ -123,60 +146,93 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
while (true)
{
System.Threading.Thread.Sleep(MaintenanceLoopms); // Sleep before next pass
if (PleaseShutdown)
return;
if (m_ScriptEngine != null)
// Reset counters?
if (MaintenanceLoopTicks_ScriptLoadUnload_ResetCount)
{
// Re-reading config every x seconds
if (m_ScriptEngine.RefreshConfigFilens > 0)
{
// Check if its time to re-read config
if (DateTime.Now.Ticks - Last_ReReadConfigFilens > m_ScriptEngine.RefreshConfigFilens)
{
//Console.WriteLine("Time passed: " + (DateTime.Now.Ticks - Last_ReReadConfigFilens) + ">" + m_ScriptEngine.RefreshConfigFilens );
// Its time to re-read config file
m_ScriptEngine.ReadConfig();
Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
}
}
// Adjust number of running script threads if not correct
if (m_ScriptEngine.m_EventQueueManager != null)
m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
// Check if any script has exceeded its max execution time
if (m_ScriptEngine.m_EventQueueManager != null && m_ScriptEngine.m_EventQueueManager.EnforceMaxExecutionTime)
{
// 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
}
}
MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = false;
MaintenanceLoopTicks_ScriptLoadUnload_Count = 0;
}
if (MaintenanceLoopTicks_Other_ResetCount)
{
MaintenanceLoopTicks_Other_ResetCount = false;
MaintenanceLoopTicks_Other_Count = 0;
}
// Increase our counters
MaintenanceLoopTicks_ScriptLoadUnload_Count++;
MaintenanceLoopTicks_Other_Count++;
//lock (ScriptEngine.ScriptEngines)
//{
foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines))
{
lastScriptEngine = m_ScriptEngine;
// Re-reading config every x seconds
if (MaintenanceLoopTicks_Other_Count >= MaintenanceLoopTicks_Other)
{
MaintenanceLoopTicks_Other_ResetCount = true;
if (m_ScriptEngine.RefreshConfigFilens > 0)
{
// Check if its time to re-read config
if (DateTime.Now.Ticks - Last_ReReadConfigFilens >
m_ScriptEngine.RefreshConfigFilens)
{
//Console.WriteLine("Time passed: " + (DateTime.Now.Ticks - Last_ReReadConfigFilens) + ">" + m_ScriptEngine.RefreshConfigFilens );
// Its time to re-read config file
m_ScriptEngine.ReadConfig();
Last_ReReadConfigFilens = DateTime.Now.Ticks; // Reset time
}
// Adjust number of running script threads if not correct
if (m_ScriptEngine.m_EventQueueManager != null)
m_ScriptEngine.m_EventQueueManager.AdjustNumberOfScriptThreads();
// Check if any script has exceeded its max execution time
if (EventQueueManager.EnforceMaxExecutionTime)
{
// We are enforcing execution time
if (DateTime.Now.Ticks - Last_maxFunctionExecutionTimens >
EventQueueManager.maxFunctionExecutionTimens)
{
// Its time to check again
m_ScriptEngine.m_EventQueueManager.CheckScriptMaxExecTime(); // Do check
Last_maxFunctionExecutionTimens = DateTime.Now.Ticks; // Reset time
}
}
}
}
if (MaintenanceLoopTicks_ScriptLoadUnload_Count >= MaintenanceLoopTicks_ScriptLoadUnload)
{
MaintenanceLoopTicks_ScriptLoadUnload_ResetCount = true;
// LOAD / UNLOAD SCRIPTS
if (m_ScriptEngine.m_ScriptManager != null)
m_ScriptEngine.m_ScriptManager.DoScriptLoadUnload();
}
}
//}
}
}
catch (Exception ex)
{
m_ScriptEngine.Log.Error("[" + m_ScriptEngine.ScriptEngineName + "]: Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: " + ex.ToString());
if (lastScriptEngine != null)
lastScriptEngine.Log.Error("[" + lastScriptEngine.ScriptEngineName + "]: Exception in MaintenanceLoopThread. Thread will recover after 5 sec throttle. Exception: " + ex.ToString());
Thread.Sleep(5000);
}
}
}
#endregion
/// <summary>
/// If set to true then threads and stuff should try to make a graceful exit
/// </summary>
public bool PleaseShutdown
{
get { return _PleaseShutdown; }
set { _PleaseShutdown = value; }
}
private bool _PleaseShutdown = false;
///// <summary>
///// If set to true then threads and stuff should try to make a graceful exit
///// </summary>
//public bool PleaseShutdown
//{
// get { return _PleaseShutdown; }
// set { _PleaseShutdown = value; }
//}
//private bool _PleaseShutdown = false;
}
}

View File

@ -27,6 +27,7 @@
*/
using System;
using System.Collections.Generic;
using System.IO;
using Nini.Config;
using OpenSim.Framework.Console;
@ -44,15 +45,16 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
[Serializable]
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine, iScriptEngineFunctionModule
{
private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static List<ScriptEngine> ScriptEngines = new List<ScriptEngine>();
public Scene World;
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 static 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;
@ -81,8 +83,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public ScriptEngine()
{
//Common.SendToDebug("ScriptEngine Object Initialized");
Common.mySE = this;
Common.mySE = this; // For logging, just need any instance, doesn't matter
lock (ScriptEngines)
{
ScriptEngines.Add(this); // Keep a list of ScriptEngines for shared threads to process all instances
}
}
public void InitializeEngine(Scene Sceneworld, IConfigSource config, bool HookUpToServer, ScriptManager newScriptManager)
@ -106,7 +111,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
m_ScriptManager = newScriptManager;
m_AppDomainManager = new AppDomainManager(this);
m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this);
m_MaintenanceThread = new MaintenanceThread(this);
if (m_MaintenanceThread == null)
m_MaintenanceThread = new MaintenanceThread();
m_log.Info("[" + ScriptEngineName + "]: Reading configuration from config section \"" + ScriptEngineName + "\"");
ReadConfig();
@ -118,6 +124,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public void Shutdown()
{
// We are shutting down
lock (ScriptEngines)
{
ScriptEngines.Remove(this);
}
}
ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager()
@ -128,17 +138,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public void ReadConfig()
{
#if DEBUG
m_log.Debug("[" + ScriptEngineName + "]: Refreshing configuration for all modules");
//m_log.Debug("[" + ScriptEngineName + "]: Refreshing configuration for all modules");
#endif
RefreshConfigFileSeconds = ScriptConfigSource.GetInt("RefreshConfig", 30);
// Reload from disk? No!
//ConfigSource.Reload();
//if (File.Exists(OpenSim.Application.iniFilePath))
//{
// //ConfigSource.Merge(new IniConfigSource(OpenSim.Application.iniFilePath));
//}
// Create a new object (probably not necessary?)
// ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
@ -175,15 +178,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#endregion
/// <summary>
/// If set to true then threads and stuff should try to make a graceful exit
/// </summary>
public bool PleaseShutdown
{
get { return _PleaseShutdown; }
set { _PleaseShutdown = value; }
}
private bool _PleaseShutdown = false;
}
}

View File

@ -129,14 +129,14 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
if (PrivateThread)
{
// Assign one thread per region
scriptLoadUnloadThread = StartScriptLoadUnloadThread();
//scriptLoadUnloadThread = StartScriptLoadUnloadThread();
}
else
{
// Shared thread - make sure one exist, then assign it to the private
if (staticScriptLoadUnloadThread == null)
{
staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
//staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
}
scriptLoadUnloadThread = staticScriptLoadUnloadThread;
}
@ -169,15 +169,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
// Abort load/unload thread
try
{
PleaseShutdown = true;
Thread.Sleep(100);
if (scriptLoadUnloadThread != null)
//PleaseShutdown = true;
//Thread.Sleep(100);
if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
{
if (scriptLoadUnloadThread.IsAlive == true)
{
scriptLoadUnloadThread.Abort();
scriptLoadUnloadThread.Join();
}
scriptLoadUnloadThread.Abort();
//scriptLoadUnloadThread.Join();
}
}
catch
@ -197,23 +194,9 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
if (LUQueue.Count == 0)
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
if (PleaseShutdown)
return;
if (LUQueue.Count > 0)
{
LUStruct item = LUQueue.Dequeue();
lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts
{
if (item.Action == LUType.Unload)
{
_StopScript(item.localID, item.itemID);
}
if (item.Action == LUType.Load)
{
_StartScript(item.localID, item.itemID, item.script);
}
}
}
//if (PleaseShutdown)
// return;
DoScriptLoadUnload();
}
}
catch (ThreadAbortException tae)
@ -224,6 +207,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
}
}
public void DoScriptLoadUnload()
{
if (LUQueue.Count > 0)
{
LUStruct item = LUQueue.Dequeue();
lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts
{
if (item.Action == LUType.Unload)
{
_StopScript(item.localID, item.itemID);
}
if (item.Action == LUType.Load)
{
_StartScript(item.localID, item.itemID, item.script);
}
}
}
}
#endregion
#region Helper functions
@ -297,10 +300,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
/// <param name="args">Arguments to pass to function</param>
internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, EventQueueManager.Queue_llDetectParams_Struct qParams, object[] args)
{
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
///#if DEBUG
/// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
///#endif
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
///#if DEBUG
/// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
///#endif
// Execute a function in the script
//m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
@ -309,10 +312,10 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
{
return;
}
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
///#if DEBUG
/// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
///#endif
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
///#if DEBUG
/// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
///#endif
// Must be done in correct AppDomain, so leaving it up to the script itself
Script.llDetectParams = qParams;
Script.Exec.ExecuteEvent(FunctionName, args);
@ -418,15 +421,15 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
#endregion
/// <summary>
/// If set to true then threads and stuff should try to make a graceful exit
/// </summary>
public bool PleaseShutdown
{
get { return _PleaseShutdown; }
set { _PleaseShutdown = value; }
}
private bool _PleaseShutdown = false;
///// <summary>
///// If set to true then threads and stuff should try to make a graceful exit
///// </summary>
//public bool PleaseShutdown
//{
// get { return _PleaseShutdown; }
// set { _PleaseShutdown = value; }
//}
//private bool _PleaseShutdown = false;
}
}

View File

@ -35,6 +35,6 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
public interface iScriptEngineFunctionModule
{
void ReadConfig();
bool PleaseShutdown { get; set; }
// bool PleaseShutdown { get; set; }
}
}

View File

@ -171,8 +171,8 @@ msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
; Refresh ScriptEngine config options (these settings) every xx seconds
; 0 = Do not refresh
; Set it to number of seconds between refresh, for example 30.
; Will allow you to change ScriptEngine settings while server is running just by editing this file.
; For example to increase or decrease number of threads.
; Will allow you to change ScriptEngine settings while server is running just by using "CONFIG SET" on console
; For example to increase or decrease number of threads: CONFIG SET NumberOfScriptThreads 10
; NOTE! Disabled for now. Feature does not work.
RefreshConfig=0
@ -184,14 +184,6 @@ NumberOfScriptThreads=2
; Valid values: Lowest, BelowNormal, Normal, AboveNormal, Highest
ScriptThreadPriority=BelowNormal
; Should the script threads be private for each region?
; true: Each region will get <NumberOfScriptThreads> dedicated to scripts within that region
; Number of threads will be <NumberOfScriptThreads>*<NumberOfRegions>
; false: All regions share <NumberOfScriptThreads> for all their scripts
; Note! If you run multiple script engines based on "OpenSim.Region.ScriptEngine.Common" then all of them will share the same threads.
; *** This setting will not work until you restart OpenSim
PrivateRegionThreads=false
; How long MAX should a script event be allowed to run (per event execution)?
; Do not set this too low (like 50ms) as there are some time wasted in simply executing a function
; There is also a small speed penalty for every kill that is made
@ -218,15 +210,24 @@ SleepTimeIfNoScriptExecutionMs=50
; Each AppDomain has some memory overhead. But leaving dead scripts in memory also has memory overhead.
ScriptsPerAppDomain=1
; Script loading / unloading sleep
; MaintenanceLoop
; How often to run maintenance loop
; Maintenance loop is doing: script compile/load, script unload, reload config, adjust running config and enforce max execution time
MaintenanceLoopms=50
; How many maintenanceloops between each of these.
; (if 2 then function will be executed every MaintenanceLoopms*2 ms)
; Script loading/unloading
; How long load/unload thread should sleep if there is nothing to do
; Higher value makes it respond slower when scripts are added/removed from prims
; But once active it will process all in queue before sleeping again
ScriptLoadUnloadLoopms=30
MaintenanceLoopTicks_ScriptLoadUnload=1
; Other tasks
; check if we need to reload config, adjust running config and enforce max execution time
MaintenanceLoopTicks_Other=10
; Loading and unloading of scripts is queued and processed by a separate thread.
; This thread can either be shared among all regions, or private (one thread per region)
PrivateScriptLoadUnloadThread=false
; Maximum number of items in load/unload queue before we start rejecting loads
; Note that we will only be rejecting load. Unloads will still be able to queue.

View File

@ -1,41 +1 @@
### ###
####### #### #######
############################
############################
###########################
#########################
#####################
###### ###### #######
##### #### ######
##### #### ######
###### ###### #######
######################
#######################
#########################
###########################
###########################
###########################
###########################
##########################
#########################
#######################
#####################
##################
#############
### ##### ### ## ### ###
####### ###### ## ### ###
### ## ## ## ## #### ####
## ### ## ### ### ## ### ## ## #### ####
### ## ####### ##### ###### #### ## #### ####
### ## ## ## ## # ## ## ###### ## ## # # ##
### ## ## ## ####### ## ## ### ## ## ### ##
## ### ## ## ## ## ## ## ## ## ## ### ##
### ### ### ## ## ## ## ## ### ### ## ## ### ##
####### ###### ##### ## ## ###### ## ## # ##
### ## ## ### ###
##
## STARTUP COMPLETE
http://opensimulator.org/wiki/FAQ
STARTUP COMPLETE

View File

@ -147,6 +147,7 @@
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="libsecondlife.dll"/>
<Reference name="OpenSim.Framework"/>
<Files>
@ -380,6 +381,7 @@
<Reference name="Axiom.MathLib.dll" localCopy="false"/>
<Reference name="OpenSim.Framework" localCopy="false"/>
<Reference name="OpenSim.Framework.Console" localCopy="false"/>
<Reference name="nunit.framework.dll" />
<Reference name="Nini.dll" />
<Reference name="log4net"/>
@ -478,6 +480,7 @@
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Region.Physics.Manager" localCopy="false"/>
<Reference name="Ode.NET.dll" localCopy="false" />
<Reference name="nunit.framework.dll" />
<Reference name="log4net"/>
<Files>
@ -752,6 +755,7 @@
<Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Communications"/>
<Reference name="OpenSim.Framework.Statistics"/>
<Reference name="OpenSim.Region.Communications.Local"/>
<Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="XMLRPC.dll"/>
@ -1506,36 +1510,6 @@
</Files>
</Project>
<Project name="LaunchSLClient" path="OpenSim/Tools/LaunchSLClient" type="Exe">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System" localCopy="false"/>
<Reference name="System.IO" localCopy="false"/>
<Reference name="System.Collections" localCopy="false"/>
<Reference name="System.Collections.Generic" localCopy="false"/>
<Reference name="System.ComponentModel" localCopy="false"/>
<Reference name="System.Data" localCopy="false"/>
<Reference name="System.Diagnostics" localCopy="false"/>
<Reference name="System.Drawing" localCopy="false"/>
<Reference name="System.Text" localCopy="false"/>
<Reference name="System.Text.RegularExpressions" localCopy="false"/>
<Reference name="System.Windows.Forms" localCopy="false"/>
<Reference name="Microsoft.Win32" localCopy="false"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
</Solution>
<!-- Prebuild tool -->