From: Date: May 7 2008 9:25pm Subject: Connector/NET commit: r1294 - in branches/1.0: . mysqlclient/common List-Archive: http://lists.mysql.com/commits/46479 X-Bug: 33682 Message-Id: <200805071925.m47JPLqQ032527@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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; + + /// + /// Initializes a new Semaphore + /// + /// Initial tickets in this Semaphore instance + /// Capacity of this Semaphore instance 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; + } + + /// + /// Releases one Semaphore ticket + /// + /// The count on the Semaphore before the Release method was called. + public int Release() + { + return Release(1); + } + + /// + /// Releases a given number of Semaphore tickets + /// + /// Amount of tickets to release + /// The count on the Semaphore before the Release method was called. + 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() + /// + /// Attempt to take a ticket from the counter. + /// If we have a ticket available, take it. + /// + /// Whether a ticket was taken. + 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; - } }