1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2 
3 #if SILVERLIGHT
4 using System;
5 
6 namespace System.Threading
7 {
8     //Monitor based implementation of Semaphore
9     //that mimicks the .NET Semaphore class (System.Threading.Semaphore)
10 
11     internal sealed class Semaphore : IDisposable
12     {
13         private int m_currentCount;
14         private int m_maximumCount;
15         private object m_lockObject;
16         private bool m_disposed;
17 
Semaphore(int initialCount, int maximumCount)18         public Semaphore(int initialCount, int maximumCount)
19         {
20             if (initialCount < 0)
21             {
22                 throw new ArgumentOutOfRangeException("initialCount", "Non-negative number required.");
23             }
24             if (maximumCount < 1)
25             {
26                 throw new ArgumentOutOfRangeException("maximumCount", "Positive number required.");
27             }
28             if (initialCount > maximumCount)
29             {
30                 throw new ArgumentException("Initial count must be smaller than maximum");
31             }
32 
33             m_currentCount = initialCount;
34             m_maximumCount = maximumCount;
35             m_lockObject = new object();
36         }
37 
Release()38         public int Release()
39         {
40             return this.Release(1);
41         }
42 
Release(int releaseCount)43         public int Release(int releaseCount)
44         {
45             if (releaseCount < 1)
46             {
47                 throw new ArgumentOutOfRangeException("releaseCount", "Positive number required.");
48             }
49             if (m_disposed)
50             {
51                 throw new ObjectDisposedException("Semaphore");
52             }
53 
54             var oldCount = default(int);
55             lock (m_lockObject)
56             {
57                 oldCount = m_currentCount;
58                 if (releaseCount + m_currentCount > m_maximumCount)
59                 {
60                     throw new ArgumentOutOfRangeException("releaseCount", "Amount of releases would overflow maximum");
61                 }
62                 m_currentCount += releaseCount;
63                 //PulseAll makes sure all waiting threads get queued for acquiring the lock
64                 //Pulse would only queue one thread.
65 
66                 Monitor.PulseAll(m_lockObject);
67             }
68             return oldCount;
69         }
70 
WaitOne()71         public bool WaitOne()
72         {
73             return WaitOne(Timeout.Infinite);
74         }
75 
WaitOne(int millisecondsTimeout)76         public bool WaitOne(int millisecondsTimeout)
77         {
78             if (m_disposed)
79             {
80                 throw new ObjectDisposedException("Semaphore");
81             }
82 
83             lock (m_lockObject)
84             {
85                 while (m_currentCount == 0)
86                 {
87                     if (!Monitor.Wait(m_lockObject, millisecondsTimeout))
88                     {
89                         return false;
90                     }
91                 }
92                 m_currentCount--;
93                 return true;
94             }
95         }
96 
WaitOne(TimeSpan timeout)97         public bool WaitOne(TimeSpan timeout)
98         {
99             return WaitOne((int)timeout.TotalMilliseconds);
100         }
101 
Close()102         public void Close()
103         {
104             Dispose();
105         }
106 
Dispose()107         public void Dispose()
108         {
109             //the .NET CLR semaphore does not release waits upon dispose
110             //so we don't do that either.
111             m_disposed = true;
112             m_lockObject = null;
113         }
114     }
115 }
116 #endif