File: WaitHandle.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (193 lines) | stat: -rw-r--r-- 6,998 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//
// System.Threading.WaitHandle.cs
//
// Author:
// 	Dick Porter (dick@ximian.com)
// 	Gonzalo Paniagua Javier (gonzalo@ximian.com
//
// (C) 2002,2003 Ximian, Inc.	(http://www.ximian.com)
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
#if FEATURE_REMOTING
using System.Runtime.Remoting.Contexts;
#endif
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;

namespace System.Threading
{
	[StructLayout (LayoutKind.Sequential)]
	public abstract partial class WaitHandle
	{
		protected static readonly IntPtr InvalidHandle = (IntPtr) (-1);

		internal const int MaxWaitHandles = 64;

		// We rely on the reference source implementation of WaitHandle, and it delegates to a function named
		//  WaitOneNative to perform the actual operation of waiting on a handle.
		// This native operation actually has to call back into managed code and invoke .Wait
		//  on the current SynchronizationContext. As such, our implementation of this "native" method
		//  is actually managed code, and the real native icall being used is Wait_internal.
		static int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
		{
			bool release = false;
#if !MONODROID
			var context = SynchronizationContext.Current;
#endif
			try {
				waitableSafeHandle.DangerousAddRef (ref release);

#if FEATURE_REMOTING
				if (exitContext)
					SynchronizationAttribute.ExitContext ();
#endif

#if !MONODROID
				// HACK: Documentation (and public posts by experts like Joe Duffy) suggests that
				//  users must first call SetWaitNotificationRequired to flag that a given synchronization
				//  context overrides .Wait. Because invoking the Wait method is somewhat expensive, we use
				//  the notification-required flag to determine whether or not we should invoke the managed
				//  wait method.
				// Another option would be to check whether this context uses the default Wait implementation,
				//  but I don't know of a cheap way to do this that handles derived types correctly.
				// If the thread does not have a synchronization context set at all, we can safely just
				//  jump directly to invoking Wait_internal.
				if ((context != null) && context.IsWaitNotificationRequired ()) {
					return context.Wait (
						new IntPtr[] { waitableSafeHandle.DangerousGetHandle () },
						false, 
						(int)millisecondsTimeout
					);
				} else
#endif
				{
					unsafe {
						IntPtr handle = waitableSafeHandle.DangerousGetHandle ();
						return Wait_internal (&handle, 1, false, (int)millisecondsTimeout);
					}
				}
			} finally {
				if (release)
					waitableSafeHandle.DangerousRelease ();

#if FEATURE_REMOTING
				if (exitContext)
					SynchronizationAttribute.EnterContext ();
#endif
			}

		}

		static int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll)
		{
			if (waitHandles.Length > MaxWaitHandles)
				return WAIT_FAILED;

			int release_last = -1;
			var context = SynchronizationContext.Current;

			try {
#if FEATURE_REMOTING
				if (exitContext)
					SynchronizationAttribute.ExitContext ();
#endif

				for (int i = 0; i < waitHandles.Length; ++i) {
					try {} finally {
						/* we have to put it in a finally block, to avoid having a ThreadAbortException
						 * between the return from DangerousAddRef and the assignement to release_last */
						bool release = false;
						waitHandles [i].SafeWaitHandle.DangerousAddRef (ref release);
						release_last = i;
					}
				}

				if ((context != null) && context.IsWaitNotificationRequired ()) {
					IntPtr[] handles = new IntPtr[waitHandles.Length];
					for (int i = 0; i < waitHandles.Length; ++i)
						handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();

					return context.Wait (
						handles,
						false, 
						(int)millisecondsTimeout
					);
				} else {
					unsafe {
						IntPtr* handles = stackalloc IntPtr[waitHandles.Length];

						for (int i = 0; i < waitHandles.Length; ++i)
							handles[i] = waitHandles[i].SafeWaitHandle.DangerousGetHandle ();

						return Wait_internal (handles, waitHandles.Length, WaitAll, millisecondsTimeout);
					}
				}
			} finally {
				for (int i = release_last; i >= 0; --i) {
					waitHandles [i].SafeWaitHandle.DangerousRelease ();
				}

#if FEATURE_REMOTING
				if (exitContext)
					SynchronizationAttribute.EnterContext ();
#endif
			}
		}

		[MethodImplAttribute(MethodImplOptions.InternalCall)]
		internal unsafe static extern int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms);

		static int SignalAndWaitOne (SafeWaitHandle waitHandleToSignal,SafeWaitHandle waitHandleToWaitOn, int millisecondsTimeout, bool hasThreadAffinity,  bool exitContext)
		{
			bool releaseHandleToSignal = false, releaseHandleToWaitOn = false;
			try {
				waitHandleToSignal.DangerousAddRef (ref releaseHandleToSignal);
				waitHandleToWaitOn.DangerousAddRef (ref releaseHandleToWaitOn);

				return SignalAndWait_Internal (waitHandleToSignal.DangerousGetHandle (), waitHandleToWaitOn.DangerousGetHandle (), millisecondsTimeout);
			} finally {
				if (releaseHandleToSignal)
					waitHandleToSignal.DangerousRelease ();
				if (releaseHandleToWaitOn)
					waitHandleToWaitOn.DangerousRelease ();
			}
		}

		[MethodImplAttribute(MethodImplOptions.InternalCall)]
		static extern int SignalAndWait_Internal (IntPtr toSignal, IntPtr toWaitOn, int ms);

		internal static int ToTimeoutMilliseconds(TimeSpan timeout)
		{
			var timeoutMilliseconds = (long)timeout.TotalMilliseconds;
			if (timeoutMilliseconds < -1 || timeoutMilliseconds > int.MaxValue)
			{
				throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
			}
			return (int)timeoutMilliseconds;
		}
	}
}