[Monodevelop-patches-list] r2057 - in trunk/MonoDevelop/Core/src/Main/Base: . Services/DispatchService

commit-watcher at mono-cvs.ximian.com commit-watcher at mono-cvs.ximian.com
Mon Dec 6 15:40:46 EST 2004


Author: lluis
Date: 2004-12-06 15:40:45 -0500 (Mon, 06 Dec 2004)
New Revision: 2057

Added:
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/AsyncDispatchAttribute.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/FreeDispatchAttribute.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncContext.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncObject.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContext.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContextAttribute.cs
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncObject.cs
Modified:
   trunk/MonoDevelop/Core/src/Main/Base/ChangeLog
   trunk/MonoDevelop/Core/src/Main/Base/Makefile.am
   trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/DispatchService.cs
Log:
	* Services/DispatchService/DispatchService.cs: Added support for
	synchronous dispatch to the gui thread.
	* Services/DispatchService/AsyncDispatchAttribute.cs:
	* Services/DispatchService/SyncContext.cs:
	* Services/DispatchService/SyncObject.cs:
	* Services/DispatchService/FreeDispatchAttribute.cs:
	* Services/DispatchService/SyncContextAttribute.cs:
	* Services/DispatchService/GuiSyncContext.cs:
	* Services/DispatchService/GuiSyncObject.cs: New classes that support
	some new dispatch features.

2004-12-06  Lluis Sanchez Gual  <lluis at novell.com>



Modified: trunk/MonoDevelop/Core/src/Main/Base/ChangeLog
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/ChangeLog	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/ChangeLog	2004-12-06 20:40:45 UTC (rev 2057)
@@ -1,5 +1,18 @@
 2004-12-06  Lluis Sanchez Gual  <lluis at novell.com>
 
+	* Services/DispatchService/DispatchService.cs: Added support for
+	synchronous dispatch to the gui thread.
+	* Services/DispatchService/AsyncDispatchAttribute.cs:
+	* Services/DispatchService/SyncContext.cs:
+	* Services/DispatchService/SyncObject.cs:
+	* Services/DispatchService/FreeDispatchAttribute.cs:
+	* Services/DispatchService/SyncContextAttribute.cs:
+	* Services/DispatchService/GuiSyncContext.cs:
+	* Services/DispatchService/GuiSyncObject.cs: New classes that support
+	some new dispatch features.
+
+2004-12-06  Lluis Sanchez Gual  <lluis at novell.com>
+
 	* *.cs: Removed remaining calls to ServiceManager.GetService.
 
 2004-12-06  Lluis Sanchez Gual  <lluis at novell.com>

Modified: trunk/MonoDevelop/Core/src/Main/Base/Makefile.am
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Makefile.am	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Makefile.am	2004-12-06 20:40:45 UTC (rev 2057)
@@ -209,7 +209,14 @@
 Services/MonodocService.cs \
 Services/IDebuggerService.cs \
 Services/SystemAssemblyService.cs \
+Services/DispatchService/AsyncDispatchAttribute.cs \
 Services/DispatchService/DispatchService.cs \
+Services/DispatchService/FreeDispatchAttribute.cs \
+Services/DispatchService/GuiSyncContext.cs \
+Services/DispatchService/GuiSyncObject.cs \
+Services/DispatchService/SyncContext.cs \
+Services/DispatchService/SyncContextAttribute.cs \
+Services/DispatchService/SyncObject.cs \
 Services/Runtime.cs \
 Internal/Undo/IUndoableOperation.cs \
 Internal/Undo/UndoStack.cs \

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/AsyncDispatchAttribute.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/AsyncDispatchAttribute.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/AsyncDispatchAttribute.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,15 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public class AsyncDispatchAttribute: Attribute
+	{
+	}
+}

Modified: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/DispatchService.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/DispatchService.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/DispatchService.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -13,33 +13,69 @@
 		ArrayList arrGuiQueue;
 		Thread thrBackground;
 		uint iIdle = 0;
+		GLib.IdleHandler handler;
+		static int guiThreadId;
+		static GuiSyncContext guiContext;
+		const string errormsg = "An exception was thrown while dispatching a method call in the UI thread.";
+		internal static bool DispatchDebug;
 
 		public override void InitializeService ()
 		{
+			guiContext = new GuiSyncContext ();
+			SyncContext.SetContext (guiContext);
+			
+			guiThreadId = AppDomain.GetCurrentThreadId();
+			
+			handler = new GLib.IdleHandler (guiDispatcher);
 			arrBackgroundQueue = new ArrayList ();
 			arrGuiQueue = new ArrayList ();
 			thrBackground = new Thread (new ThreadStart (backgroundDispatcher));
 			thrBackground.IsBackground = true;
 			thrBackground.Priority = ThreadPriority.Lowest;
 			thrBackground.Start ();
+			DispatchDebug = Environment.GetEnvironmentVariable ("MONODEVELOP_DISPATCH_DEBUG") != null;
 		}
 
 		public void GuiDispatch (MessageHandler cb)
 		{
-			arrGuiQueue.Add (new GenericMessageContainer (cb));
+			arrGuiQueue.Add (new GenericMessageContainer (cb, false));
 			UpdateIdle ();
 		}
 
 		public void GuiDispatch (StatefulMessageHandler cb, object state)
 		{
-			arrGuiQueue.Add (new StatefulMessageContainer (cb, state));
+			arrGuiQueue.Add (new StatefulMessageContainer (cb, state, false));
 			UpdateIdle ();
 		}
 
+		public void GuiSyncDispatch (MessageHandler cb)
+		{
+			GenericMessageContainer mc = new GenericMessageContainer (cb, true);
+			lock (mc) {
+				arrGuiQueue.Add (mc);
+				UpdateIdle ();
+				Monitor.Wait (mc);
+			}
+			if (mc.Exception != null)
+				throw new Exception (errormsg, mc.Exception);
+		}
+		
+		public void GuiSyncDispatch (StatefulMessageHandler cb, object state)
+		{
+			StatefulMessageContainer mc = new StatefulMessageContainer (cb, state, true);
+			lock (mc) {
+				arrGuiQueue.Add (mc);
+				UpdateIdle ();
+				Monitor.Wait (mc);
+			}
+			if (mc.Exception != null)
+				throw new Exception (errormsg, mc.Exception);
+		}
+
 		void UpdateIdle ()
 		{
 			if (iIdle == 0) {
-				iIdle = GLib.Idle.Add (new GLib.IdleHandler (guiDispatcher));
+				iIdle = GLib.Idle.Add (handler);
 				/* This code is required because for some
 				 * reason the idle handler is run once
 				 * before being set, so you get a idle
@@ -50,15 +86,31 @@
 					iIdle = 0;
 			}
 		}
-
+		
+		public static bool IsGuiThread
+		{
+			get { return guiThreadId == AppDomain.GetCurrentThreadId(); }
+		}
+		
+		public static void AssertGuiThread ()
+		{
+			if (guiThreadId != AppDomain.GetCurrentThreadId())
+				throw new InvalidOperationException ("This method can only be called in the GUI thread");
+		}
+		
+		public static Delegate GuiDispatch (Delegate del)
+		{
+			return guiContext.CreateSynchronizedDelegate (del);
+		}
+		
 		public void BackgroundDispatch (MessageHandler cb)
 		{
-			arrBackgroundQueue.Add (new GenericMessageContainer (cb));
+			arrBackgroundQueue.Add (new GenericMessageContainer (cb, false));
 		}
 
 		public void BackgroundDispatch (StatefulMessageHandler cb, object state)
 		{
-			arrBackgroundQueue.Add (new StatefulMessageContainer (cb, state));
+			arrBackgroundQueue.Add (new StatefulMessageContainer (cb, state, false));
 			//thrBackground.Resume ();
 		}
 
@@ -73,8 +125,14 @@
 				msg = (GenericMessageContainer)arrGuiQueue[0];
 				arrGuiQueue.RemoveAt (0);
 			}
-			if (msg != null)
+			if (msg != null) {
 				msg.Run ();
+				if (msg.IsSynchronous)
+					lock (msg) Monitor.PulseAll (msg);
+				else if (msg.Exception != null)
+					HandlerError (msg);
+			}
+			
 			if (arrGuiQueue.Count == 0) {
 				iIdle = 0;
 				return false;
@@ -95,10 +153,25 @@
 					msg = (GenericMessageContainer)arrBackgroundQueue[0];
 					arrBackgroundQueue.RemoveAt (0);
 				}
-				if (msg != null)
+				if (msg != null) {
 					msg.Run ();
+					if (msg.Exception != null)
+						HandlerError (msg);
+				}
 			}
 		}
+		
+		private void HandlerError (GenericMessageContainer msg)
+		{
+			Console.WriteLine (errormsg);
+			Console.WriteLine (msg.Exception);
+			if (msg.CallerStack != null) {
+				Console.WriteLine ("\nCaller stack:");
+				Console.WriteLine (msg.CallerStack);
+			}
+			else
+				Console.WriteLine ("\n\nCaller stack not available. Define the environment variable MONODEVELOP_DISPATCH_DEBUG to enable caller stack capture.");
+		}
 	}
 
 	public delegate void MessageHandler ();
@@ -107,18 +180,43 @@
 	class GenericMessageContainer
 	{
 		MessageHandler callback;
+		protected Exception ex;
+		protected bool isSynchronous;
+		protected string callerStack;
 
 		protected GenericMessageContainer () { }
 
-		public GenericMessageContainer (MessageHandler cb)
+		public GenericMessageContainer (MessageHandler cb, bool isSynchronous)
 		{
 			callback = cb;
+			this.isSynchronous = isSynchronous;
+			if (DispatchService.DispatchDebug) callerStack = Environment.StackTrace;
 		}
 
 		public virtual void Run ()
 		{
-			callback ();
+			try {
+				callback ();
+			}
+			catch (Exception e) {
+				ex = e;
+			}
 		}
+		
+		public Exception Exception
+		{
+			get { return ex; }
+		}
+		
+		public bool IsSynchronous
+		{
+			get { return isSynchronous; }
+		}
+		
+		public string CallerStack
+		{
+			get { return callerStack; }
+		}
 	}
 
 	class StatefulMessageContainer : GenericMessageContainer
@@ -126,15 +224,23 @@
 		object data;
 		StatefulMessageHandler callback;
 
-		public StatefulMessageContainer (StatefulMessageHandler cb, object state)
+		public StatefulMessageContainer (StatefulMessageHandler cb, object state, bool isSynchronous)
 		{
 			data = state;
 			callback = cb;
+			this.isSynchronous = isSynchronous;
+			if (DispatchService.DispatchDebug) callerStack = Environment.StackTrace;
 		}
 		
 		public override void Run ()
 		{
-			callback (data);
+			try {
+				callback (data);
+			}
+			catch (Exception e) {
+				ex = e;
+			}
 		}
 	}
+
 }

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/FreeDispatchAttribute.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/FreeDispatchAttribute.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/FreeDispatchAttribute.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,15 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public class FreeDispatchAttribute: Attribute
+	{
+	}
+}

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncContext.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncContext.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncContext.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,36 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public class GuiSyncContext: SyncContext
+	{
+		DispatchService dispatcher;
+		
+		public override void Dispatch (StatefulMessageHandler cb, object ob)
+		{
+			if (dispatcher == null)
+				dispatcher = Runtime.DispatchService;
+				
+			if (DispatchService.IsGuiThread)
+				cb (ob);
+			else {
+				dispatcher.GuiSyncDispatch (cb, ob);
+			}
+		}
+		
+		public override void AsyncDispatch (StatefulMessageHandler cb, object ob)
+		{
+			if (dispatcher == null)
+				dispatcher = Runtime.DispatchService;
+				
+			dispatcher.GuiDispatch (cb, ob);
+		}
+	}
+}

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncObject.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncObject.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/GuiSyncObject.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,16 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	[SyncContext (typeof(GuiSyncContext))]
+	public class GuiSyncObject: SyncObject
+	{
+	}
+}

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContext.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContext.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContext.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,188 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.Remoting.Contexts;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Activation;
+
+namespace MonoDevelop.Services
+{
+	public class SyncContext
+	{
+		[ThreadStatic]
+		static SyncContext context;
+		
+		static Hashtable delegateFactories = new Hashtable ();
+		static ModuleBuilder module;
+		static AssemblyBuilder asmBuilder;
+	
+		public static void SetContext (SyncContext ctx)
+		{
+			context = ctx;
+		}
+		
+		public static SyncContext GetContext ()
+		{
+			return context;
+		}
+		
+		public virtual void Dispatch (StatefulMessageHandler cb, object ob)
+		{
+			cb (ob);
+		}
+		
+		public virtual void AsyncDispatch (StatefulMessageHandler cb, object ob)
+		{
+			cb.BeginInvoke (ob, null, null);
+		}
+		
+		public Delegate CreateSynchronizedDelegate (Delegate del)
+		{
+			lock (delegateFactories.SyncRoot)
+			{
+				Type delType = del.GetType();
+				IDelegateFactory factory = delegateFactories [delType] as IDelegateFactory;
+				if (factory == null)
+				{
+					Type t = GetDelegateFactoryType (delType);
+					factory = Activator.CreateInstance (t) as IDelegateFactory;
+					delegateFactories [delType] = factory;
+				}
+				return factory.Create (del, this);
+			}
+		}
+			
+		Type GetDelegateFactoryType (Type delegateType)
+		{
+			MethodInfo invoke = delegateType.GetMethod ("Invoke");
+			ModuleBuilder module = GetModuleBuilder ();
+			TypeBuilder typeBuilder = module.DefineType ("__" + delegateType.Name + "_DelegateFactory", TypeAttributes.Public, typeof(object), new Type[] {typeof(IDelegateFactory)});
+			
+			// Context and target delegate field
+			
+			FieldBuilder contextField = typeBuilder.DefineField ("context", typeof(SyncContext), FieldAttributes.Public);
+			FieldBuilder targetField = typeBuilder.DefineField ("target", delegateType, FieldAttributes.Public);
+			
+			// Parameters
+			
+			ParameterInfo[] pars = invoke.GetParameters ();
+			FieldBuilder[] paramFields = new FieldBuilder [pars.Length];
+			Type[] paramTypes = new Type[pars.Length];
+			for (int n=0; n<pars.Length; n++)
+			{
+				ParameterInfo pi = pars [n];
+				paramFields [n] = typeBuilder.DefineField ("p" + n, pi.ParameterType, FieldAttributes.Public);
+				paramTypes [n] = pi.ParameterType;
+			}
+			
+			// Return value
+			
+			FieldBuilder returnField = null;
+			if (invoke.ReturnType != typeof(void))
+				returnField = typeBuilder.DefineField ("ret", invoke.ReturnType, FieldAttributes.Public);
+			
+			// Constructor
+			
+			ConstructorBuilder ctor = typeBuilder.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
+			ConstructorInfo baseCtor = typeof(object).GetConstructor (Type.EmptyTypes);
+			ILGenerator gen = ctor.GetILGenerator();
+			gen.Emit (OpCodes.Ldarg_0);
+			gen.Emit (OpCodes.Call, baseCtor);
+			gen.Emit (OpCodes.Ret);
+			
+			// Dispatch method
+			
+			MethodBuilder methodDispatch = typeBuilder.DefineMethod ("Dispatch", MethodAttributes.Public, typeof(void), new Type[] {typeof(object)});
+			gen = methodDispatch.GetILGenerator();
+			if (returnField != null)
+				gen.Emit (OpCodes.Ldarg_0);
+			gen.Emit (OpCodes.Ldarg_0);
+			gen.Emit (OpCodes.Ldfld, targetField);
+			
+			for (int n=0; n<pars.Length; n++)
+			{
+				gen.Emit (OpCodes.Ldarg_0);
+				gen.Emit (OpCodes.Ldfld, paramFields[n]);
+			}
+			gen.Emit (OpCodes.Callvirt, invoke);
+			
+			if (returnField != null)
+				gen.Emit (OpCodes.Stfld, returnField);
+	
+			gen.Emit (OpCodes.Ret);
+			
+			// ProxyCall method
+			
+			MethodBuilder methodProxyCall = typeBuilder.DefineMethod ("ProxyCall", MethodAttributes.Public, invoke.ReturnType, paramTypes);
+			gen = methodProxyCall.GetILGenerator();
+			for (int n=0; n<paramFields.Length; n++) {
+				gen.Emit (OpCodes.Ldarg_0);
+				gen.Emit (OpCodes.Ldarg, n+1);
+				gen.Emit (OpCodes.Stfld, paramFields[n]);
+			}
+			gen.Emit (OpCodes.Ldarg_0);
+			gen.Emit (OpCodes.Ldfld, contextField);
+			gen.Emit (OpCodes.Ldarg_0);
+			gen.Emit (OpCodes.Ldftn, methodDispatch);
+			gen.Emit (OpCodes.Newobj, typeof(StatefulMessageHandler).GetConstructor (new Type[] {typeof(object), typeof(IntPtr)} ));
+			gen.Emit (OpCodes.Ldnull);
+			gen.Emit (OpCodes.Callvirt, typeof(SyncContext).GetMethod ("Dispatch"));
+			
+			if (returnField != null) {
+				gen.Emit (OpCodes.Ldarg_0);
+				gen.Emit (OpCodes.Ldfld, returnField);
+			}
+			gen.Emit (OpCodes.Ret);
+			
+			// Create method
+			
+			MethodBuilder methodCreate = typeBuilder.DefineMethod ("Create", MethodAttributes.Public, typeof(Delegate), new Type[] {typeof(Delegate), typeof(SyncContext)});
+			gen = methodCreate.GetILGenerator();
+			LocalBuilder vthis = gen.DeclareLocal (typeBuilder);
+			gen.Emit (OpCodes.Newobj, ctor);
+			gen.Emit (OpCodes.Stloc, vthis);
+			gen.Emit (OpCodes.Ldloc, vthis);
+			gen.Emit (OpCodes.Ldarg_1);
+			gen.Emit (OpCodes.Castclass, delegateType);
+			gen.Emit (OpCodes.Stfld, targetField);
+			gen.Emit (OpCodes.Ldloc, vthis);
+			gen.Emit (OpCodes.Ldarg_2);
+			gen.Emit (OpCodes.Stfld, contextField);
+			gen.Emit (OpCodes.Ldloc, vthis);
+			gen.Emit (OpCodes.Ldftn, methodProxyCall);
+			gen.Emit (OpCodes.Newobj, delegateType.GetConstructor (new Type[] {typeof(object), typeof(IntPtr)} ));
+			gen.Emit (OpCodes.Ret);
+			typeBuilder.DefineMethodOverride (methodCreate, typeof(IDelegateFactory).GetMethod ("Create"));
+			
+			return typeBuilder.CreateType ();
+		}
+		
+		static ModuleBuilder GetModuleBuilder ()
+		{
+			if (module == null)
+			{
+				AppDomain myDomain = System.Threading.Thread.GetDomain();
+				AssemblyName myAsmName = new AssemblyName();
+				myAsmName.Name = "MonoDevelop.DelegateGenerator.GeneratedAssembly";
+	
+				asmBuilder = myDomain.DefineDynamicAssembly (myAsmName, AssemblyBuilderAccess.RunAndSave);
+				module = asmBuilder.DefineDynamicModule ("MonoDevelop.DelegateGenerator.GeneratedAssembly", "MonoDevelop.DelegateGenerator.GeneratedAssembly.dll");
+			}
+			return module;
+		}
+	}
+	
+	public interface IDelegateFactory
+	{
+		Delegate Create (Delegate del, SyncContext ctx);
+	}
+}

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContextAttribute.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContextAttribute.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncContextAttribute.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,140 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.Remoting.Contexts;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Activation;
+
+namespace MonoDevelop.Services
+{
+	public class SyncContextAttribute: ContextAttribute, IContributeObjectSink
+	{
+		Type contextType;
+		SyncContext syncContext;
+		
+		public SyncContextAttribute (Type contextType): base ("syncContextProperty")
+		{
+			this.contextType = contextType;
+		}
+		
+		public override bool IsContextOK (Context ctx, IConstructionCallMessage msg)
+		{
+			SyncContext sctx = SyncContext.GetContext ();
+			if (sctx == null || (sctx.GetType() != contextType)) {
+				syncContext = (SyncContext) Activator.CreateInstance (contextType);
+				return false;
+			}
+			else {
+				syncContext = sctx;
+				return true;
+			}
+		}
+		
+		public IMessageSink GetObjectSink (MarshalByRefObject ob, IMessageSink nextSink)
+		{
+			return new SyncContextDispatchSink (nextSink, syncContext);
+		}
+		
+		public Type ConextType
+		{
+			get { return contextType; }
+		}
+	}
+	
+	internal class SyncContextDispatchSink: IMessageSink
+	{
+		IMessageSink nextSink;
+		SyncContext syncContext;
+		
+		class MsgData
+		{
+			public IMessage InMessage;
+			public IMessage OutMessage;
+			public IMessageSink ReplySink;
+		}
+		
+		public SyncContextDispatchSink (IMessageSink nextSink, SyncContext syncContext)
+		{
+			this.nextSink = nextSink;
+			this.syncContext = syncContext;
+		}
+		
+        public IMessage SyncProcessMessage (IMessage msg)
+		{
+			if (syncContext == null) return nextSink.SyncProcessMessage (msg);
+			
+			IMethodMessage mm = (IMethodMessage)msg;
+			if (mm.MethodBase.IsDefined (typeof(FreeDispatchAttribute), true))
+				return nextSink.SyncProcessMessage (msg);
+
+			if (mm.MethodBase.IsDefined (typeof(AsyncDispatchAttribute), true)) {
+				AsyncProcessMessage (msg, DummySink.Instance);
+				return new ReturnMessage (null, null, 0, null, (IMethodCallMessage)mm);
+			}
+
+			MsgData md = new MsgData ();
+			md.InMessage = msg;
+			syncContext.Dispatch (new StatefulMessageHandler (DispatchMessage), md);
+			return md.OutMessage;
+		}
+		
+		void DispatchMessage (object data)
+		{
+			MsgData md = (MsgData)data;
+			md.OutMessage = nextSink.SyncProcessMessage (md.InMessage);
+		}
+		
+        public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
+		{
+			if (syncContext == null) return nextSink.AsyncProcessMessage (msg, replySink);
+
+			MsgData md = new MsgData ();
+			md.InMessage = msg;
+			md.ReplySink = replySink;
+			syncContext.AsyncDispatch (new StatefulMessageHandler (AsyncDispatchMessage), md);
+			return null;
+		}
+		
+		void AsyncDispatchMessage (object data)
+		{
+			MsgData md = (MsgData)data;
+			md.ReplySink.SyncProcessMessage (nextSink.SyncProcessMessage (md.InMessage));
+		}
+		
+        public IMessageSink NextSink
+		{
+			get { return nextSink; }
+		}
+	}
+	
+	internal class DummySink: IMessageSink
+	{
+		public static DummySink Instance = new DummySink();
+		
+        public IMessage SyncProcessMessage (IMessage msg)
+		{
+			// Ignore
+			return null;
+		}
+		
+        public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
+		{
+			// Ignore
+			return null;
+		}
+		
+        public IMessageSink NextSink
+		{
+			get { return null; }
+		}
+	}
+}

Added: trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncObject.cs
===================================================================
--- trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncObject.cs	2004-12-06 17:00:46 UTC (rev 2056)
+++ trunk/MonoDevelop/Core/src/Main/Base/Services/DispatchService/SyncObject.cs	2004-12-06 20:40:45 UTC (rev 2057)
@@ -0,0 +1,15 @@
+// <file>
+//     <copyright see="prj:///doc/copyright.txt"/>
+//     <license see="prj:///doc/license.txt"/>
+//     <owner name="Lluis Sanchez Gual" email="lluis at ximian.com"/>
+//     <version value="$version"/>
+// </file>
+
+using System;
+
+namespace MonoDevelop.Services
+{
+	public class SyncObject: ContextBoundObject
+	{
+	}
+}




More information about the Monodevelop-patches-list mailing list