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/common | rburnett | 7 May |