Update Reference Sources to .NET Framework 4.6.1
[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 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         [System.Security.SecuritySafeCritical]
70         [ResourceExposure(ResourceScope.None)]
71         [MethodImplAttribute(MethodImplOptions.InternalCall)]
72         private static extern void ReliableEnter(Object obj, ref bool lockTaken);
73
74
75
76         /*=========================================================================
77         ** Release the monitor lock. If one or more threads are waiting to acquire the
78         ** lock, and the current thread has executed as many Exits as
79         ** Enters, one of the threads will be unblocked and allowed to proceed.
80         **
81         ** Exceptions: ArgumentNullException if object is null.
82         **             SynchronizationLockException if the current thread does not
83         **             own the lock.
84         =========================================================================*/
85         [System.Security.SecuritySafeCritical]
86         [ResourceExposure(ResourceScope.None)]
87         [MethodImplAttribute(MethodImplOptions.InternalCall)]
88         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
89         public static extern void Exit(Object obj);
90     
91         /*=========================================================================
92         ** Similar to Enter, but will never block. That is, if the current thread can
93         ** acquire the monitor lock without blocking, it will do so and TRUE will
94         ** be returned. Otherwise FALSE will be returned.
95         **
96         ** Exceptions: ArgumentNullException if object is null.
97         =========================================================================*/
98         public static bool TryEnter(Object obj)
99         {
100             bool lockTaken = false;
101             TryEnter(obj, 0, ref lockTaken);
102             return lockTaken;
103         }
104
105         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
106         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
107         public static void TryEnter(Object obj, ref bool lockTaken)
108         {
109             if (lockTaken)
110                 ThrowLockTakenException();
111
112             ReliableEnterTimeout(obj, 0, ref lockTaken);
113         }
114     
115         /*=========================================================================
116         ** Version of TryEnter that will block, but only up to a timeout period
117         ** expressed in milliseconds. If timeout == Timeout.Infinite the method
118         ** becomes equivalent to Enter.
119         **
120         ** Exceptions: ArgumentNullException if object is null.
121         **             ArgumentException if timeout < 0.
122         =========================================================================*/
123         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
124         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
125         public static bool TryEnter(Object obj, int millisecondsTimeout)
126         {
127             bool lockTaken = false;
128             TryEnter(obj, millisecondsTimeout, ref lockTaken);
129             return lockTaken;
130         }
131
132         private static int MillisecondsTimeoutFromTimeSpan(TimeSpan timeout)
133         {
134             long tm = (long)timeout.TotalMilliseconds;
135             if (tm < -1 || tm > (long)Int32.MaxValue)
136                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
137             return (int)tm;
138         }
139
140         public static bool TryEnter(Object obj, TimeSpan timeout)
141         {
142             return TryEnter(obj, MillisecondsTimeoutFromTimeSpan(timeout));
143         }
144
145         // The JIT should inline this method to allow check of lockTaken argument to be optimized out
146         // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
147         public static void TryEnter(Object obj, int millisecondsTimeout, ref bool lockTaken)
148         {
149             if (lockTaken)
150                 ThrowLockTakenException();
151
152             ReliableEnterTimeout(obj, millisecondsTimeout, ref lockTaken);
153         }
154
155         public static void TryEnter(Object obj, TimeSpan timeout, ref bool lockTaken)
156         {
157             if (lockTaken)
158                 ThrowLockTakenException();
159
160             ReliableEnterTimeout(obj, MillisecondsTimeoutFromTimeSpan(timeout), ref lockTaken);
161         }
162
163         [System.Security.SecuritySafeCritical]
164         [ResourceExposure(ResourceScope.None)]
165         [MethodImplAttribute(MethodImplOptions.InternalCall)]
166         private static extern void ReliableEnterTimeout(Object obj, int timeout, ref bool lockTaken);
167
168         [System.Security.SecuritySafeCritical]
169         public static bool IsEntered(object obj)
170         {
171             if (obj == null)
172                 throw new ArgumentNullException("obj");
173
174             return IsEnteredNative(obj);
175         }
176
177         [System.Security.SecurityCritical]
178         [ResourceExposure(ResourceScope.None)]
179         [MethodImplAttribute(MethodImplOptions.InternalCall)]
180         private static extern bool IsEnteredNative(Object obj);
181
182         /*========================================================================
183     ** Waits for notification from the object (via a Pulse/PulseAll). 
184     ** timeout indicates how long to wait before the method returns.
185     ** This method acquires the monitor waithandle for the object 
186     ** If this thread holds the monitor lock for the object, it releases it. 
187     ** On exit from the method, it obtains the monitor lock back. 
188     ** If exitContext is true then the synchronization domain for the context 
189     ** (if in a synchronized context) is exited before the wait and reacquired 
190     **
191         ** Exceptions: ArgumentNullException if object is null.
192     ========================================================================*/
193         [System.Security.SecurityCritical]  // auto-generated
194         [ResourceExposure(ResourceScope.None)]
195         [MethodImplAttribute(MethodImplOptions.InternalCall)]
196         private static extern bool ObjWait(bool exitContext, int millisecondsTimeout, Object obj);
197
198         [System.Security.SecuritySafeCritical]  // auto-generated
199         public static bool Wait(Object obj, int millisecondsTimeout, bool exitContext)
200         {
201             if (obj == null)
202                 throw (new ArgumentNullException("obj"));
203             return ObjWait(exitContext, millisecondsTimeout, obj);
204         }
205
206         public static bool Wait(Object obj, TimeSpan timeout, bool exitContext)
207         {
208             return Wait(obj, MillisecondsTimeoutFromTimeSpan(timeout), exitContext);
209         }
210
211         public static bool Wait(Object obj, int millisecondsTimeout)
212         {
213             return Wait(obj, millisecondsTimeout, false);
214         }
215
216         public static bool Wait(Object obj, TimeSpan timeout)
217         {
218             return Wait(obj, MillisecondsTimeoutFromTimeSpan(timeout), false);
219         }
220
221         public static bool Wait(Object obj)
222         {
223             return Wait(obj, Timeout.Infinite, false);
224         }
225
226         /*========================================================================
227         ** Sends a notification to a single waiting object. 
228         * Exceptions: SynchronizationLockException if this method is not called inside
229         * a synchronized block of code.
230         ========================================================================*/
231         [System.Security.SecurityCritical]  // auto-generated
232         [ResourceExposure(ResourceScope.None)]
233         [MethodImplAttribute(MethodImplOptions.InternalCall)]
234         private static extern void ObjPulse(Object obj);
235
236         [System.Security.SecuritySafeCritical]  // auto-generated
237         public static void Pulse(Object obj)
238         {
239             if (obj == null)
240             {
241                 throw new ArgumentNullException("obj");
242             }
243             Contract.EndContractBlock();
244
245             ObjPulse(obj);
246         }
247         /*========================================================================
248         ** Sends a notification to all waiting objects. 
249         ========================================================================*/
250         [System.Security.SecurityCritical]  // auto-generated
251         [ResourceExposure(ResourceScope.None)]
252         [MethodImplAttribute(MethodImplOptions.InternalCall)]
253         private static extern void ObjPulseAll(Object obj);
254
255         [System.Security.SecuritySafeCritical]  // auto-generated
256         public static void PulseAll(Object obj)
257         {
258             if (obj == null)
259             {
260                 throw new ArgumentNullException("obj");
261             }
262             Contract.EndContractBlock();
263
264             ObjPulseAll(obj);
265         }
266     }
267 }