[sgen] Don't reallocate mod_union at each major
[mono.git] / mcs / class / corlib / System.Threading / Monitor.cs
1 //
2 // System.Threading.Monitor.cs
3 //
4 // Author:
5 //   Dick Porter (dick@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Runtime.CompilerServices;
34 using System.Runtime.Remoting.Contexts;
35 using System.Runtime.ConstrainedExecution;
36 using System.Runtime.InteropServices;
37
38 namespace System.Threading
39 {
40         [ComVisible (true)]
41         public static class Monitor
42         {
43                 // Grabs the mutex on object 'obj', with a maximum
44                 // wait time 'ms' but doesn't block - if it can't get
45                 // the lock it returns false, true if it can
46                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
47                 private extern static bool Monitor_try_enter(object obj, int ms);
48
49                 // Enter/Exit are implemented directly as icalls for performance reasons
50
51                 // Acquires the mutex on object 'obj'
52                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
53                 public extern static void Enter(object obj);
54
55                 // Releases the mutex on object 'obj'
56                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
57                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
58                 public extern static void Exit(object obj);
59
60                 // Signals one of potentially many objects waiting on
61                 // object 'obj'
62                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
63                 private extern static void Monitor_pulse(object obj);
64
65                 // Checks whether object 'obj' is currently synchronised
66                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
67                 private extern static bool Monitor_test_synchronised(object obj);
68
69                 public static void Pulse(object obj) {
70                         if(obj==null) {
71                                 throw new ArgumentNullException("obj");
72                         }
73                         if(Monitor_test_synchronised(obj)==false) {
74                                 throw new SynchronizationLockException("Object is not synchronized");
75                         }
76
77                         Monitor_pulse(obj);
78                 }
79
80                 // Signals all of potentially many objects waiting on
81                 // object 'obj'
82                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
83                 private extern static void Monitor_pulse_all(object obj);
84
85                 public static void PulseAll(object obj) {
86                         if(obj==null) {
87                                 throw new ArgumentNullException("obj");
88                         }
89                         if(Monitor_test_synchronised(obj)==false) {
90                                 throw new SynchronizationLockException("Object is not synchronized");
91                         }
92
93                         Monitor_pulse_all(obj);
94                 }
95
96                 public static bool TryEnter (object obj)
97                 {
98                         return TryEnter (obj, 0);
99                 }
100
101                 public static bool TryEnter (object obj, int millisecondsTimeout)
102                 {
103                         if (obj == null)
104                                 throw new ArgumentNullException ("obj");
105
106                         if (millisecondsTimeout == Timeout.Infinite) {
107                                 Enter (obj);
108                                 return true;
109                         }
110
111                         if (millisecondsTimeout < 0)
112                                 throw new ArgumentException ("negative value for millisecondsTimeout", "millisecondsTimeout");
113                         
114                         return Monitor_try_enter (obj, millisecondsTimeout);
115                 }
116
117                 public static bool TryEnter (object obj, TimeSpan timeout)
118                 {
119                         long ms = (long) timeout.TotalMilliseconds;
120                         if (ms < Timeout.Infinite || ms > Int32.MaxValue)
121                                 throw new ArgumentOutOfRangeException ("timeout", "timeout out of range");
122                         
123                         return TryEnter (obj, (int) ms);
124                 }
125
126                 // Waits for a signal on object 'obj' with maximum
127                 // wait time 'ms'. Returns true if the object was
128                 // signalled, false if it timed out
129                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130                 private extern static bool Monitor_wait(object obj, int ms);
131
132                 public static bool Wait (object obj)
133                 {
134                         return Wait (obj, Timeout.Infinite);
135                 }
136
137                 public static bool Wait (object obj, int millisecondsTimeout)
138                 {
139                         if (obj == null)
140                                 throw new ArgumentNullException ("obj");
141
142                         if (millisecondsTimeout < Timeout.Infinite)
143                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout", "timeout out of range");
144
145                         if (!Monitor_test_synchronised (obj))
146                                 throw new SynchronizationLockException ("Object is not synchronized");
147
148                         return Monitor_wait (obj, millisecondsTimeout);
149                 }
150
151                 public static bool Wait (object obj, TimeSpan timeout)
152                 {
153                         long ms = (long) timeout.TotalMilliseconds;
154                         if (ms < Timeout.Infinite || ms > Int32.MaxValue)
155                                 throw new ArgumentOutOfRangeException ("timeout", "timeout out of range");
156
157                         return Wait (obj, (int) ms);
158                 }
159
160                 public static bool Wait(object obj, int millisecondsTimeout, bool exitContext) {
161                         try {
162                                 if (exitContext) {
163 #if MONOTOUCH
164                                         throw new NotSupportedException ("exitContext == true is not supported");
165 #else
166                                         SynchronizationAttribute.ExitContext ();
167 #endif
168                                 }
169                                 return Wait (obj, millisecondsTimeout);
170                         }
171                         finally {
172                                 if (exitContext) SynchronizationAttribute.EnterContext ();
173                         }
174                 }
175
176                 public static bool Wait(object obj, TimeSpan timeout, bool exitContext) {
177                         try {
178                                 if (exitContext) {
179 #if MONOTOUCH
180                                         throw new NotSupportedException ("exitContext == true is not supported");
181 #else
182                                         SynchronizationAttribute.ExitContext ();
183 #endif
184                                 }
185                                 return Wait (obj, timeout);
186                         }
187                         finally {
188                                 if (exitContext) SynchronizationAttribute.EnterContext ();
189                         }
190                 }
191
192                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
193                 extern static void try_enter_with_atomic_var (object obj, int millisecondsTimeout, ref bool lockTaken);
194
195                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
196                 extern static void enter_with_atomic_var (object obj, ref bool lockTaken);
197
198                 // Can't make this an icall since it has the same name as the other Enter method
199                 [MethodImpl(MethodImplOptions.AggressiveInlining)]
200                 public static void Enter (object obj, ref bool lockTaken)
201                 {
202                         enter_with_atomic_var (obj, ref lockTaken);
203                 }
204
205                 public static void TryEnter (object obj, ref bool lockTaken)
206                 {
207                         TryEnter (obj, 0, ref lockTaken);
208                 }
209
210                 public static void TryEnter (object obj, TimeSpan timeout, ref bool lockTaken)
211                 {
212                         long ms = (long) timeout.TotalMilliseconds;
213                         if (ms < Timeout.Infinite || ms > Int32.MaxValue)
214                                 throw new ArgumentOutOfRangeException ("timeout", "timeout out of range");
215                         TryEnter (obj, (int)ms, ref lockTaken);
216                 }
217
218                 public static void TryEnter (object obj, int millisecondsTimeout, ref bool lockTaken)
219                 {
220                         if (obj == null)
221                                 throw new ArgumentNullException ("obj");
222                         if (lockTaken)
223                                 throw new ArgumentException ("lockTaken");
224
225                         if (millisecondsTimeout < 0 && millisecondsTimeout != Timeout.Infinite)
226                                 throw new ArgumentException ("negative value for millisecondsTimeout", "millisecondsTimeout");
227
228                         try_enter_with_atomic_var (obj, millisecondsTimeout, ref lockTaken);
229                 }               
230
231
232                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
233                 extern static bool Monitor_test_owner (object obj);
234
235                 public
236                 static bool IsEntered (object obj)
237                 {
238                         return Monitor_test_owner(obj);
239                 }
240         }
241 }