List:Commits« Previous MessageNext Message »
From:rburnett Date:May 7 2008 7:25pm
Subject:Connector/NET commit: r1294 - in branches/1.0: . mysqlclient/common
View as plain text  
Modified:
   branches/1.0/CHANGES
   branches/1.0/mysqlclient/common/Semaphore.cs
Log:
Replaced semaphore class that used Win32 API calls with one that uses an AutoResetEvent object so it will work on Mono (bug # 33682)       


Modified: branches/1.0/CHANGES
===================================================================
--- branches/1.0/CHANGES	2008-05-07 19:12:00 UTC (rev 1293)
+++ branches/1.0/CHANGES	2008-05-07 19:25:21 UTC (rev 1294)
@@ -16,6 +16,8 @@
     the parameter marker after the connection had been assigned to a command but before
     the connection is opened can cause parameters to not be found (bug #13991)                
   - Fixed long standing problem with compression over a network.  It's now fast again. (bug #27865)    
+  - Replaced semaphore class that used Win32 API calls with one that uses an AutoResetEvent object
+    so it will work on Mono (bug # 33682)       
                 
 Version 1.0.10
     Bugs

Modified: branches/1.0/mysqlclient/common/Semaphore.cs
===================================================================
--- branches/1.0/mysqlclient/common/Semaphore.cs	2008-05-07 19:12:00 UTC (rev 1293)
+++ branches/1.0/mysqlclient/common/Semaphore.cs	2008-05-07 19:25:21 UTC (rev 1294)
@@ -26,57 +26,100 @@
 {
     internal class Semaphore : WaitHandle
     {
+        AutoResetEvent autoEvent = null;
+        object countLock = new object();
+
+        int availableCount = 0;
+        int capacityCount = 0;
+
+        /// <summary>
+        /// Initializes a new Semaphore
+        /// </summary>
+        /// <param name="initialCount">Initial tickets in this Semaphore instance</param>
+        /// <param name="maximumCount">Capacity of this Semaphore instance</param>
         public Semaphore(int initialCount, int maximumCount)
         {
-            SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
-            IntPtr handle = CreateSemaphore(ref sa, initialCount, 
-                maximumCount, null);
-            if (handle.Equals(IntPtr.Zero))
+            autoEvent = new AutoResetEvent(false);
+
+            availableCount = initialCount;
+            capacityCount = maximumCount;
+        }
+
+        /// <summary>
+        /// Releases one Semaphore ticket
+        /// </summary>
+        /// <returns>The count on the Semaphore before the Release method was called.</returns>
+        public int Release()
+        {
+            return Release(1);
+        }
+
+        /// <summary>
+        /// Releases a given number of Semaphore tickets
+        /// </summary>
+        /// <param name="releaseCount">Amount of tickets to release</param>
+        /// <returns>The count on the Semaphore before the Release method was called.</returns>
+        public int Release(int releaseCount)
+        {
+            if (releaseCount < 0)
+                throw new ArgumentException("Release count must be >= 0", "releaseCount");
+            
+            int previousCount = availableCount;
+            
+            if (releaseCount == 0) return previousCount;
+
+
+            if ((previousCount + releaseCount > capacityCount))
+                throw new InvalidOperationException("Unable to release Semaphore");
+
+            // Pulse the amount of threads for tickets we have released
+            for (int i = 0; i < releaseCount; i++)
             {
-                throw new Exception("Unable to create semaphore");
+                Interlocked.Increment(ref availableCount);
+                autoEvent.Set();
             }
-            base.Handle = handle;
+
+            return previousCount;
         }
 
-        public int Release()
+        /// <summary>
+        /// Attempt to take a ticket from the counter.
+        /// If we have a ticket available, take it.
+        /// </summary>
+        /// <returns>Whether a ticket was taken.</returns>
+        bool TryTakeTicket()
         {
-            IntPtr previous = IntPtr.Zero;
-            if (!ReleaseSemaphore(base.Handle, 1, previous))
-                throw new Exception("Unable to release semaphore");
-            return previous.ToInt32();
+            int currentCount = Interlocked.Decrement(ref availableCount);
+
+            if (currentCount >= 0) return true;
+
+            Interlocked.Increment(ref availableCount);
+            return false;
         }
 
         public override bool WaitOne(int millisecondsTimeout, bool exitContext)
         {
-            if ((millisecondsTimeout < 0) && (millisecondsTimeout != -1))
+            if ((millisecondsTimeout < 0) && (millisecondsTimeout != Timeout.Infinite))
                 throw new ArgumentOutOfRangeException("millisecondsTimeout");
 
             if (exitContext)
                 throw new ArgumentException(null, "exitContext");
 
-            int result = WaitForSingleObject(Handle, millisecondsTimeout);
-            if (0 == result) return true;
+            DateTime start = DateTime.Now;
+            int timeout = millisecondsTimeout;
+            while (timeout > 0)
+            {
+                // Is there a ticket free? Take one if there is and return.
+                if (TryTakeTicket())
+                    return true;
+
+                // We have no tickets right now, lets wait for one.
+                if (!autoEvent.WaitOne(timeout, false))
+                    return false;
+                timeout = millisecondsTimeout - (int)DateTime.Now.Subtract(start).TotalMilliseconds;
+            }
+
             return false;
         }
-
-        [DllImport("kernel32.dll")]
-        static extern bool ReleaseSemaphore(IntPtr hSemaphore, 
-            int lReleaseCount, IntPtr lpPreviousCount);
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        private static extern IntPtr CreateSemaphore(
-            ref SECURITY_ATTRIBUTES securityAttributes, int initialCount, 
-            int maximumCount, string name);
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        private static extern int WaitForSingleObject(IntPtr handle, int millis);
     }
-
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct SECURITY_ATTRIBUTES
-    {
-        public int nLength;
-        public IntPtr lpSecurityDescriptor;
-        public int bInheritHandle;
-    }
 }

Thread
Connector/NET commit: r1294 - in branches/1.0: . mysqlclient/commonrburnett7 May