[corlib] Import System.Threading.Monitor
[mono.git] / mcs / class / referencesource / mscorlib / system / threading / monitor.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 //
7 // <OWNER>[....]</OWNER>
8 /*=============================================================================
9 **
10 ** Class: Monitor
11 **
12 **
13 ** Purpose: Synchronizes access to a shared resource or region of code in a multi-threaded 
14 **             program.
15 **
16 **
17 =============================================================================*/
18
19
20 namespace System.Threading {
21
22     using System;
23     using System.Security.Permissions;
24     using System.Runtime;
25     using System.Runtime.Remoting;
26     using System.Threading;
27     using System.Runtime.CompilerServices;
28     using System.Runtime.ConstrainedExecution;
29     using System.Runtime.Versioning;
30     using System.Diagnostics.Contracts;
31
32     [HostProtection(Synchronization=true, ExternalThreading=true)]
33     [System.Runtime.InteropServices.ComVisible(true)]
34     public static partial class Monitor
35     {
36         /*=========================================================================
37         ** Obtain the monitor lock of obj. Will block if another thread holds the lock
38         ** Will not block if the current thread holds the lock,
39         ** however the caller must ensure that the same number of Exit
40         ** calls are made as there were Enter calls.
41         **
42         ** Exceptions: ArgumentNullException if object is null.
43         =========================================================================*/
44         [System.Security.SecuritySafeCritical]
45         [ResourceExposure(ResourceScope.None)]
46         [MethodImplAttribute(MethodImplOptions.InternalCall)]
47         public static extern void Enter(Object obj);
48
49
50         // Use a ref bool instead of out to ensure that unverifiable code must
51         // initialize this value to something.  If we used out, the value 
52         // could be uninitialized if we threw an exception in our prolog.
53         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
54         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
55         public static void Enter(Object obj, ref bool lockTaken)
56         {
57             if (lockTaken)
58                 ThrowLockTakenException();
59
60             ReliableEnter(obj, ref lockTaken);
61             Contract.Assert(lockTaken);
62         }
63
64         private static void ThrowLockTakenException()
65         {
66             throw new ArgumentException(Environment.GetResourceString("Argument_MustBeFalse"), "lockTaken");
67         }
68
69 #if !MONO
70         [System.Security.SecuritySafeCritical]
71         [ResourceExposure(ResourceScope.None)]
72         [MethodImplAttribute(MethodImplOptions.InternalCall)]
73         private static extern void ReliableEnter(Object obj, ref bool lockTaken);
74 #endif
75
76
77         /*=========================================================================
78         ** Release the monitor lock. If one or more threads are waiting to acquire the
79         ** lock, and the current thread has executed as many Exits as
80         ** Enters, one of the threads will be unblocked and allowed to proceed.
81         **
82         ** Exceptions: ArgumentNullException if object is null.
83         **             SynchronizationLockException if the current thread does not
84         **             own the lock.
85         =========================================================================*/
86         [System.Security.SecuritySafeCritical]
87         [ResourceExposure(ResourceScope.None)]
88         [MethodImplAttribute(MethodImplOptions.InternalCall)]
89         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
90         public static extern void Exit(Object obj);
91     
92         /*=========================================================================
93         ** Similar to Enter, but will never block. That is, if the current thread can
94         ** acquire the monitor lock without blocking, it will do so and TRUE will
95         ** be returned. Otherwise FALSE will be returned.
96         **
97         ** Exceptions: ArgumentNullException if object is null.
98         =========================================================================*/
99         public static bool TryEnter(Object obj)
100         {
101             bool lockTaken = false;
102             TryEnter(obj, 0, ref lockTaken);
103             return lockTaken;
104         }
105
106         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
107         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
108         public static void TryEnter(Object obj, ref bool lockTaken)
109         {
110             if (lockTaken)
111                 ThrowLockTakenException();
112
113             ReliableEnterTimeout(obj, 0, ref lockTaken);
114         }
115     
116         /*=========================================================================
117         ** Version of TryEnter that will block, but only up to a timeout period
118         ** expressed in milliseconds. If timeout == Timeout.Infinite the method
119         ** becomes equivalent to Enter.
120         **
121         ** Exceptions: ArgumentNullException if object is null.
122         **             ArgumentException if timeout < 0.
123         =========================================================================*/
124         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
125         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
126         public static bool TryEnter(Object obj, int millisecondsTimeout)
127         {
128             bool lockTaken = false;
129             TryEnter(obj, millisecondsTimeout, ref lockTaken);
130             return lockTaken;
131         }
132
133         private static int MillisecondsTimeoutFromTimeSpan(TimeSpan timeout)
134         {
135             long tm = (long)timeout.TotalMilliseconds;
136             if (tm < -1 || tm > (long)Int32.MaxValue)
137                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
138             return (int)tm;
139         }
140
141         public static bool TryEnter(Object obj, TimeSpan timeout)
142         {
143             return TryEnter(obj, MillisecondsTimeoutFromTimeSpan(timeout));
144         }
145
146         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
147         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
148         public static void TryEnter(Object obj, int millisecondsTimeout, ref bool lockTaken)
149         {
150             if (lockTaken)
151                 ThrowLockTakenException();
152
153             ReliableEnterTimeout(obj, millisecondsTimeout, ref lockTaken);
154         }
155
156         public static void TryEnter(Object obj, TimeSpan timeout, ref bool lockTaken)
157         {
158             if (lockTaken)
159                 ThrowLockTakenException();
160
161             ReliableEnterTimeout(obj, MillisecondsTimeoutFromTimeSpan(timeout), ref lockTaken);
162         }
163
164 #if !MONO
165         [System.Security.SecuritySafeCritical]
166         [ResourceExposure(ResourceScope.None)]
167         [MethodImplAttribute(MethodImplOptions.InternalCall)]
168         private static extern void ReliableEnterTimeout(Object obj, int timeout, ref bool lockTaken);
169 #endif
170
171         [System.Security.SecuritySafeCritical]
172         public static bool IsEntered(object obj)
173         {
174             if (obj == null)
175                 throw new ArgumentNullException("obj");
176
177             return IsEnteredNative(obj);
178         }
179
180 #if !MONO
181         [System.Security.SecurityCritical]
182         [ResourceExposure(ResourceScope.None)]
183         [MethodImplAttribute(MethodImplOptions.InternalCall)]
184         private static extern bool IsEnteredNative(Object obj);
185 #endif
186
187         /*========================================================================
188     ** Waits for notification from the object (via a Pulse/PulseAll). 
189     ** timeout indicates how long to wait before the method returns.
190     ** This method acquires the monitor waithandle for the object 
191     ** If this thread holds the monitor lock for the object, it releases it. 
192     ** On exit from the method, it obtains the monitor lock back. 
193     ** If exitContext is true then the synchronization domain for the context 
194     ** (if in a synchronized context) is exited before the wait and reacquired 
195     **
196         ** Exceptions: ArgumentNullException if object is null.
197     ========================================================================*/
198 #if !MONO
199         [System.Security.SecurityCritical]  // auto-generated
200         [ResourceExposure(ResourceScope.None)]
201         [MethodImplAttribute(MethodImplOptions.InternalCall)]
202         private static extern bool ObjWait(bool exitContext, int millisecondsTimeout, Object obj);
203 #endif
204
205         [System.Security.SecuritySafeCritical]  // auto-generated
206         public static bool Wait(Object obj, int millisecondsTimeout, bool exitContext)
207         {
208             if (obj == null)
209                 throw (new ArgumentNullException("obj"));
210             return ObjWait(exitContext, millisecondsTimeout, obj);
211         }
212
213         public static bool Wait(Object obj, TimeSpan timeout, bool exitContext)
214         {
215             return Wait(obj, MillisecondsTimeoutFromTimeSpan(timeout), exitContext);
216         }
217
218         public static bool Wait(Object obj, int millisecondsTimeout)
219         {
220             return Wait(obj, millisecondsTimeout, false);
221         }
222
223         public static bool Wait(Object obj, TimeSpan timeout)
224         {
225             return Wait(obj, MillisecondsTimeoutFromTimeSpan(timeout), false);
226         }
227
228         public static bool Wait(Object obj)
229         {
230             return Wait(obj, Timeout.Infinite, false);
231         }
232
233         /*========================================================================
234         ** Sends a notification to a single waiting object. 
235         * Exceptions: SynchronizationLockException if this method is not called inside
236         * a synchronized block of code.
237         ========================================================================*/
238 #if !MONO
239         [System.Security.SecurityCritical]  // auto-generated
240         [ResourceExposure(ResourceScope.None)]
241         [MethodImplAttribute(MethodImplOptions.InternalCall)]
242         private static extern void ObjPulse(Object obj);
243 #endif
244
245         [System.Security.SecuritySafeCritical]  // auto-generated
246         public static void Pulse(Object obj)
247         {
248             if (obj == null)
249             {
250                 throw new ArgumentNullException("obj");
251             }
252             Contract.EndContractBlock();
253
254             ObjPulse(obj);
255         }
256         /*========================================================================
257         ** Sends a notification to all waiting objects. 
258         ========================================================================*/
259 #if !MONO
260         [System.Security.SecurityCritical]  // auto-generated
261         [ResourceExposure(ResourceScope.None)]
262         [MethodImplAttribute(MethodImplOptions.InternalCall)]
263         private static extern void ObjPulseAll(Object obj);
264 #endif
265
266         [System.Security.SecuritySafeCritical]  // auto-generated
267         public static void PulseAll(Object obj)
268         {
269             if (obj == null)
270             {
271                 throw new ArgumentNullException("obj");
272             }
273             Contract.EndContractBlock();
274
275             ObjPulseAll(obj);
276         }
277     }
278 }