Browse Source

Use thread-safe version of .NET Random as the SDK class is not thread-safe.

As per http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx, the .NET Random class is not thread-safe.
If called by multiple threads at once, methods may return 0.
Except for llRand(), other OpenSimulator code did not lock before calling a shared Random instance.
This commit adds a ThreadSafeRandom class that extends Random but does internal locking so that it is thread-safe.
This change is invisible to existing callers and the explicit locking in the llFrand() implementation is now redundant.
Justin Clark-Casey (justincc) 10 years ago
parent
commit
0c8f3dddd8

+ 72 - 0
OpenSim/Framework/ThreadSafeRandom.cs

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+
+namespace OpenSim.Framework
+{
+    /// <summary>
+    /// A thread-safe Random since the .NET version is not.
+    /// See http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx
+    /// </summary>
+    public class ThreadSafeRandom : Random
+    {
+        public ThreadSafeRandom() : base() {}
+
+        public ThreadSafeRandom(int seed): base (seed) {}
+
+        public override int Next()
+        {
+            lock (this)
+                return base.Next();
+        }
+
+        public override int Next(int maxValue)
+        {
+            lock (this)
+                return base.Next(maxValue);
+        }
+
+        public override int Next(int minValue, int maxValue)
+        {
+            lock (this)
+                return base.Next(minValue, maxValue);
+        }
+
+        public override void NextBytes(byte[] buffer)
+        {
+            lock (this)
+                base.NextBytes(buffer);
+        }
+
+        public override double NextDouble()
+        {
+            lock (this)
+                return base.NextDouble();
+        }
+    }
+}

+ 1 - 1
OpenSim/Framework/Util.cs

@@ -138,7 +138,7 @@ namespace OpenSim.Framework
         }
 
         private static uint nextXferID = 5000;
-        private static Random randomClass = new Random();
+        private static Random randomClass = new ThreadSafeRandom();
 
         // Get a list of invalid file characters (OS dependent)
         private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";

+ 2 - 4
OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs

@@ -544,10 +544,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
         public LSL_Float llFrand(double mag)
         {
             m_host.AddScriptLPS(1);
-            lock (Util.RandomClass)
-            {
-                return Util.RandomClass.NextDouble() * mag;
-            }
+
+            return Util.RandomClass.NextDouble() * mag;
         }
 
         public LSL_Integer llFloor(double f)