From fdf8876e20e519e2c69f0bd0fed4aea7ff4bab8d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 5 Dec 2012 21:52:10 +0000 Subject: In BaseHttpServer.HandleRequest(), use Culture.SetCurrentCulture() rather than creating a new CultureInfo separately --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 2cd626f..8a0340f 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -436,7 +436,7 @@ namespace OpenSim.Framework.Servers.HttpServer // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); - Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); + Culture.SetCurrentCulture(); // // This is the REST agent interface. We require an agent to properly identify // // itself. If the REST handler recognizes the prefix it will attempt to -- cgit v1.1 From 2342d20a7e249bc3006e47e85e03de6d532a7d2d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 5 Dec 2012 21:53:25 +0000 Subject: minor: tidy up spacing at bottom of MundaneFrameworkTests --- OpenSim/Framework/Tests/MundaneFrameworkTests.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index 47fe599..1dc8053 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs @@ -303,10 +303,6 @@ namespace OpenSim.Framework.Tests Culture.SetCurrentCulture(); Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); - } - - - + } } -} - +} \ No newline at end of file -- cgit v1.1 From b60c6bc3f8936f3a152e0609daa1081216d34768 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 5 Dec 2012 22:01:47 +0000 Subject: Don't pointlessly set ExtraParams = byte[1] in PrimitiveBaseShape since this is ignored by the ExtraParams properly anyway --- OpenSim/Framework/PrimitiveBaseShape.cs | 3 --- 1 file changed, 3 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index 76dcfca..3dbdd0f 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -193,7 +193,6 @@ namespace OpenSim.Framework public PrimitiveBaseShape() { PCode = (byte) PCodeEnum.Primitive; - ExtraParams = new byte[1]; m_textureEntry = DEFAULT_TEXTURE; } @@ -203,7 +202,6 @@ namespace OpenSim.Framework return; PCode = (byte)PCodeEnum.Primitive; - ExtraParams = new byte[1]; m_textureEntry = DEFAULT_TEXTURE; } @@ -216,7 +214,6 @@ namespace OpenSim.Framework // m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID); PCode = (byte)prim.PrimData.PCode; - ExtraParams = new byte[1]; State = prim.PrimData.State; PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); -- cgit v1.1 From 0f3ebe09713cf67110ff24bf6cd10b9add5cc8c9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 5 Dec 2012 22:12:45 +0000 Subject: Remove very probably unused PrimitiveBaseShape(bool) constructor to reduce code complexity --- OpenSim/Framework/PrimitiveBaseShape.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index 3dbdd0f..4c36819 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -192,15 +192,6 @@ namespace OpenSim.Framework public PrimitiveBaseShape() { - PCode = (byte) PCodeEnum.Primitive; - m_textureEntry = DEFAULT_TEXTURE; - } - - public PrimitiveBaseShape(bool noShape) - { - if (noShape) - return; - PCode = (byte)PCodeEnum.Primitive; m_textureEntry = DEFAULT_TEXTURE; } @@ -245,7 +236,10 @@ namespace OpenSim.Framework SculptTexture = prim.Sculpt.SculptTexture; SculptType = (byte)prim.Sculpt.Type; } - else SculptType = (byte)OpenMetaverse.SculptType.None; + else + { + SculptType = (byte)OpenMetaverse.SculptType.None; + } } [XmlIgnore] @@ -337,9 +331,9 @@ namespace OpenSim.Framework _scale = new Vector3(side, side, side); } - public void SetHeigth(float heigth) + public void SetHeigth(float height) { - _scale.Z = heigth; + _scale.Z = height; } public void SetRadius(float radius) -- cgit v1.1 From 0568c76a8801408665730702c97717d3c05cfe4d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 7 Dec 2012 00:47:04 +0000 Subject: Use a thread abort safe version of OpenMetaverse.DoubleDictionary with the aim of avoiding OpenSimulator problems due to script thread aborts. When an object is removed, its scripts are stopped and then the thread running them is aborted if stop takes too long. However, it appears that aborting a thread at just the wrong moment when it is obtaining a ReaderWriterLockSlim lock can leave this lock in an inconsistent state. One symptom of this is that mono leaps to 100% cpu and a vm thread dump reveals lots of threads waiting for a ReaderWriterLockSlim lock without any thread actually holding it. This is probably the same problem as encountered originally in commit 12cebb12 This commit looks to plaster this problem by putting lock obtaining methods inside finally blocks which should be uninterruptible by thread aborts. --- .../Framework/DoubleDictionaryThreadAbortSafe.cs | 508 +++++++++++++++++++++ 1 file changed, 508 insertions(+) create mode 100644 OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs new file mode 100644 index 0000000..9056548 --- /dev/null +++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/ + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using System.Collections.Generic; + +namespace OpenSim.Framework +{ + /// + /// A double dictionary that is thread abort safe. + /// + /// + /// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within + /// a finally section (which can't be interrupted by Thread.Abort()). + /// + public class DoubleDictionaryThreadAbortSafe + { + Dictionary Dictionary1; + Dictionary Dictionary2; + ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(); + + public DoubleDictionaryThreadAbortSafe() + { + Dictionary1 = new Dictionary(); + Dictionary2 = new Dictionary(); + } + + public DoubleDictionaryThreadAbortSafe(int capacity) + { + Dictionary1 = new Dictionary(capacity); + Dictionary2 = new Dictionary(capacity); + } + + public void Add(TKey1 key1, TKey2 key2, TValue value) + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterWriteLock(); + gotLock = true; + } + + if (Dictionary1.ContainsKey(key1)) + { + if (!Dictionary2.ContainsKey(key2)) + throw new ArgumentException("key1 exists in the dictionary but not key2"); + } + else if (Dictionary2.ContainsKey(key2)) + { + if (!Dictionary1.ContainsKey(key1)) + throw new ArgumentException("key2 exists in the dictionary but not key1"); + } + + Dictionary1[key1] = value; + Dictionary2[key2] = value; + } + finally + { + if (gotLock) + rwLock.ExitWriteLock(); + } + } + + public bool Remove(TKey1 key1, TKey2 key2) + { + bool success; + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterWriteLock(); + gotLock = true; + } + + Dictionary1.Remove(key1); + success = Dictionary2.Remove(key2); + } + finally + { + if (gotLock) + rwLock.ExitWriteLock(); + } + + return success; + } + + public bool Remove(TKey1 key1) + { + bool found = false; + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterWriteLock(); + gotLock = true; + } + + // This is an O(n) operation! + TValue value; + if (Dictionary1.TryGetValue(key1, out value)) + { + foreach (KeyValuePair kvp in Dictionary2) + { + if (kvp.Value.Equals(value)) + { + Dictionary1.Remove(key1); + Dictionary2.Remove(kvp.Key); + found = true; + break; + } + } + } + } + finally + { + if (gotLock) + rwLock.ExitWriteLock(); + } + + return found; + } + + public bool Remove(TKey2 key2) + { + bool found = false; + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterWriteLock(); + gotLock = true; + } + + // This is an O(n) operation! + TValue value; + if (Dictionary2.TryGetValue(key2, out value)) + { + foreach (KeyValuePair kvp in Dictionary1) + { + if (kvp.Value.Equals(value)) + { + Dictionary2.Remove(key2); + Dictionary1.Remove(kvp.Key); + found = true; + break; + } + } + } + } + finally + { + if (gotLock) + rwLock.ExitWriteLock(); + } + + return found; + } + + public void Clear() + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterWriteLock(); + gotLock = true; + } + + Dictionary1.Clear(); + Dictionary2.Clear(); + } + finally + { + if (gotLock) + rwLock.ExitWriteLock(); + } + } + + public int Count + { + get { return Dictionary1.Count; } + } + + public bool ContainsKey(TKey1 key) + { + return Dictionary1.ContainsKey(key); + } + + public bool ContainsKey(TKey2 key) + { + return Dictionary2.ContainsKey(key); + } + + public bool TryGetValue(TKey1 key, out TValue value) + { + bool success; + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + success = Dictionary1.TryGetValue(key, out value); + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + + return success; + } + + public bool TryGetValue(TKey2 key, out TValue value) + { + bool success; + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + success = Dictionary2.TryGetValue(key, out value); + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + + return success; + } + + public void ForEach(Action action) + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + foreach (TValue value in Dictionary1.Values) + action(value); + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + } + + public void ForEach(Action> action) + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + foreach (KeyValuePair entry in Dictionary1) + action(entry); + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + } + + public void ForEach(Action> action) + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + foreach (KeyValuePair entry in Dictionary2) + action(entry); + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + } + + public TValue FindValue(Predicate predicate) + { + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + foreach (TValue value in Dictionary1.Values) + { + if (predicate(value)) + return value; + } + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + + return default(TValue); + } + + public IList FindAll(Predicate predicate) + { + IList list = new List(); + bool gotLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterReadLock(); + gotLock = true; + } + + foreach (TValue value in Dictionary1.Values) + { + if (predicate(value)) + list.Add(value); + } + } + finally + { + if (gotLock) + rwLock.ExitReadLock(); + } + + return list; + } + + public int RemoveAll(Predicate predicate) + { + IList list = new List(); + bool gotUpgradeableLock = false; + + try + { + // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing + // the acquision inside the main try. The inner finally block is needed because thread aborts cannot + // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). + try {} + finally + { + rwLock.EnterUpgradeableReadLock(); + gotUpgradeableLock = true; + } + + foreach (KeyValuePair kvp in Dictionary1) + { + if (predicate(kvp.Value)) + list.Add(kvp.Key); + } + + IList list2 = new List(list.Count); + foreach (KeyValuePair kvp in Dictionary2) + { + if (predicate(kvp.Value)) + list2.Add(kvp.Key); + } + + bool gotWriteLock = false; + + try + { + try {} + finally + { + rwLock.EnterUpgradeableReadLock(); + gotWriteLock = true; + } + + for (int i = 0; i < list.Count; i++) + Dictionary1.Remove(list[i]); + + for (int i = 0; i < list2.Count; i++) + Dictionary2.Remove(list2[i]); + } + finally + { + if (gotWriteLock) + rwLock.ExitWriteLock(); + } + } + finally + { + if (gotUpgradeableLock) + rwLock.ExitUpgradeableReadLock(); + } + + return list.Count; + } + } +} \ No newline at end of file -- cgit v1.1