Selaa lähdekoodia

Implemenent v4 Monitor::TryEnter overloads.

	* Monitor.cs (TryEnter): Implement v4 overloads that take
	a "ref book lookTaken" var. Setting this flag must be done
	in the runtime to avoid async exceptions.

	* Monitor.cs (Enter): Fix v4 overload to be async exception
	safe.

	* monitor.c: New icall for the above.

	Fixes #649159
Rodrigo Kumpera 15 vuotta sitten
vanhempi
sitoutus
e07d43896e

+ 27 - 4
mcs/class/corlib/System.Threading/Monitor.cs

@@ -178,17 +178,40 @@ namespace System.Threading
 		}
 
 #if NET_4_0 || MOONLIGHT
+		[MethodImplAttribute(MethodImplOptions.InternalCall)]
+		extern static void try_enter_with_atomic_var (object obj, int millisecondsTimeout, ref bool lockTaken);
+
 		public static void Enter (object obj, ref bool lockTaken)
+		{
+			TryEnter (obj, Timeout.Infinite, ref lockTaken);
+		}
+
+		public static void TryEnter (object obj, ref bool lockTaken)
+		{
+			TryEnter (obj, 0, ref lockTaken);
+		}
+
+		public static void TryEnter (object obj, TimeSpan timeout, ref bool lockTaken)
+		{
+			long ms = (long) timeout.TotalMilliseconds;
+			if (ms < Timeout.Infinite || ms > Int32.MaxValue)
+				throw new ArgumentOutOfRangeException ("timeout", "timeout out of range");
+			TryEnter (obj, (int)ms, ref lockTaken);
+		}
+
+		public static void TryEnter (object obj, int millisecondsTimeout, ref bool lockTaken)
 		{
 			if (obj == null)
 				throw new ArgumentNullException ("obj");
 			if (lockTaken)
 				throw new ArgumentException ("lockTaken");
 
-			Enter (obj);
-			// if Enter throws then lockTaken will be false
-			lockTaken = true;
-		}
+			if (millisecondsTimeout < 0 && millisecondsTimeout != Timeout.Infinite)
+				throw new ArgumentException ("negative value for millisecondsTimeout", "millisecondsTimeout");
+
+			try_enter_with_atomic_var (obj, millisecondsTimeout, ref lockTaken);
+		}		
+
 #endif
 	}
 }

+ 1 - 0
mono/metadata/icall-def.h

@@ -839,6 +839,7 @@ ICALL(MONIT_4, "Monitor_test_owner", ves_icall_System_Threading_Monitor_Monitor_
 ICALL(MONIT_5, "Monitor_test_synchronised", ves_icall_System_Threading_Monitor_Monitor_test_synchronised)
 ICALL(MONIT_6, "Monitor_try_enter", ves_icall_System_Threading_Monitor_Monitor_try_enter)
 ICALL(MONIT_7, "Monitor_wait", ves_icall_System_Threading_Monitor_Monitor_wait)
+ICALL(MONIT_9, "try_enter_with_atomic_var", ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var)
 
 ICALL_TYPE(MUTEX, "System.Threading.Mutex", MUTEX_1)
 ICALL(MUTEX_1, "CreateMutex_internal(bool,string,bool&)", ves_icall_System_Threading_Mutex_CreateMutex_internal)

+ 14 - 0
mono/metadata/monitor.c

@@ -1158,6 +1158,20 @@ ves_icall_System_Threading_Monitor_Monitor_try_enter (MonoObject *obj, guint32 m
 	return res == 1;
 }
 
+void
+ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken)
+{
+	gint32 res;
+	do {
+		res = mono_monitor_try_enter_internal (obj, ms, TRUE);
+		/*This means we got interrupted during the wait and didn't got the monitor.*/
+		if (res == -1)
+			mono_thread_interruption_checkpoint ();
+	} while (res == -1);
+	/*It's safe to do it from here since interruption would happen only on the wrapper.*/
+	*lockTaken = TRUE;
+}
+
 gboolean 
 ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
 {

+ 1 - 0
mono/metadata/monitor.h

@@ -37,6 +37,7 @@ extern gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(Mon
 extern void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj) MONO_INTERNAL;
 extern void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj) MONO_INTERNAL;
 extern gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj, guint32 ms) MONO_INTERNAL;
+extern void ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken) MONO_INTERNAL;
 
 G_END_DECLS