Re: Release status.



On Tue, 2003-12-09 at 08:28, Jim McDonald wrote:
> I've had a quick look at this issue and hacked (*really* hacked)
> together what appears to be a quick fix, centered around RunQuery(). 
> Whenever RunQuery() is called it attempts to EndInvoke() all threads
> that were BeginInvoke()d the last time RunQuery() ran.  This seems to
> do the trick.
> 
>    The patch is ugly, though.  Ideally it would keep proper track of
> what backends were active and which had finished and maintain the list
> properly, but I don't have time to do that until at least this
> weekend.
> 
>    If anyone wants to look at the fix I've made my replacement
> cluepacket-manager.cs available at
> http://www.devzero.net/downloads/cluepacket-manager.cs

I patched this a bit, here's my new version.

It's still not working for me, though, I get a hang in EndInvoke at some
point.  Also, lots of this:
        
        Killing: Bookmarks
        Exception: System.InvalidOperationException: The requested
        operation cannot be performed
        (null)
        Exception Rethrown at:
        in (unmanaged) /usr/lib/libmono.so.0(mono_raise_exception+0x1b)
        [0x40093087]
        in (unmanaged) /usr/lib/libmono.so.0 [0x400a32dd]
        in <0x0003b> (wrapper delegate-end-invoke)
        System.MulticastDelegate:end_invoke_void_IAsyncResult
        (System.IAsyncResult)
        in [0x00085] (at
        /home/nat/cvs/dashboard/engine/cluepacket-manager.cs:89)
        Dashboard.CluePacketManager:RunQuery (Dashboard.CluePacket)
        
Best,
Nat

//
// GNOME Dashboard
//
// cluepacket-manager.cs: Dispatches clues to backends as they come in
// from frontends.
//
// Authors:
//    Nat Friedman <nat nat org>
//    Miguel de Icaza <miguel ximian com>
//    Joe Shaw <joe assbarn com>
//

using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace Dashboard {

	public delegate void QueryBackendHandler (Backend b, CluePacket cp);

	public class RunningQuery {
		public IAsyncResult iar;
		public QueryBackendHandler qbh;
		public string name;

		public RunningQuery (QueryBackendHandler q, IAsyncResult i, string n)
		{
			iar = i;
			qbh = q;
			name = n;
		}
	}

	public class CluePacketManager {
		// A list of all the loaded Dashboard.Backend objects.
		ArrayList   backends      = new ArrayList ();

		// Where to look for backend DLLs.
		string backends_dir;

		// Keep track of backend handlers that are currently running
		ArrayList running_queries = new ArrayList();

		// The MatchFilter object, to which we send the
		// matches when they come in from the backends.
		MatchFilter match_filter;

		// Our callback invoked when a backend query is done,
		// to check for errors.
		AsyncCallback query_backend_done;

		public CluePacketManager (MatchFilter filter)
		{
			this.match_filter = filter;
			query_backend_done = new AsyncCallback (QueryBackendDone);
		}


		// This function gets called whenever a new cluepacket
		// comes in from a frontend.
		public void ProcessFrontendCluePacket (CluePacket cp)
		{
			// Let the MatchFilter know that we just got a fresh
			// cluepacket, so that it knows what the most current
			// cluepacket is, and can avoid displaying matches
			// from old cludepackets.
			this.match_filter.NotifyNewCluePacket (cp);

			this.RunQuery (cp);
		}

		public void RunQuery (CluePacket cp)
		{
			if (cp == null || cp.Clues.Count == 0)
				return;

			lock (this.running_queries)
			{
				Console.WriteLine ("Killing handlers from previous requests");
				foreach (RunningQuery q in running_queries)
				{
					Console.WriteLine ("Killing: " + q.name);
					try
					{
						q.qbh.EndInvoke (q.iar);
					}
					catch (Exception ex)
					{
						Console.WriteLine ("Exception: " + ex);
						// The item has probably already finished
					}
			  	}

				running_queries = new ArrayList ();
			}

			Console.WriteLine ("\n\nRunning Query:\n------\n{0}", cp.ToString ());

			lock (this.backends) {
				foreach (Backend backend in this.backends) {
					if (! backend.Initialized)
						continue;

					if (! backend.AcceptCluePacket (cp))
						continue;

					lock (this.running_queries) {
						// Process each of the backends in a new thread.
						QueryBackendHandler query_backend = new QueryBackendHandler (this.QueryBackend);
						IAsyncResult query_ar = query_backend.BeginInvoke (backend, cp, query_backend_done, null);
						running_queries.Add (new RunningQuery (query_backend, query_ar, backend.Name));
					}
				}
			}
		}

		// Ask the backend for matches and new clues based on
		// the current cluepacket.
		private void QueryBackend (Backend backend, CluePacket cp)
		{
			BackendResult result;

			Console.WriteLine ("--sending--> {0}", backend.Name);

			// Send the cluepacket to the backend.
			try {
				result = backend.ProcessCluePacket (cp);
				if (result == null) {
					Console.WriteLine ("<--done (no match)-- " + backend.Name);
					return;
				}
			} catch (Exception e) {
				Console.WriteLine ("ERROR in '{0}': {1}", backend.Name, e);
				Console.WriteLine ("<--done (ERROR)-- " + backend.Name);
				return;
			}

			int nmatches = result.Matches != null ? result.Matches.Count : 0;
			int nclues = result.NewClues != null ? result.NewClues.Count : 0;

			if (nmatches == 0 && nclues == 0)
				Console.WriteLine ("<--nothing-- {2}", nmatches, nclues, backend.Name);
			else
				Console.WriteLine ("<--[m{0}:c{1}]-- {2}", nmatches, nclues, backend.Name);

			// Send the matches to the match filter.
			if (nmatches > 0) {
				foreach (Match m in result.Matches) {
					Console.WriteLine( "Sending matches to the match filter." );
					match_filter.NotifyMatch (cp, m);
				}
			}

			// Cluechain.
			if (nclues > 0) {
				CluePacket new_cp = new CluePacket (cp);
				// Have an array of "Text:Type" to track what we've already seen.
				// Use IndexOf to search it?
				foreach (Clue new_clue in result.NewClues) {
					new_cp.AddClue (new_clue);
				}

				if (new_cp != cp) {
					Console.WriteLine( "Have a new CluePacket, time to do more work!");
					RunQuery (new_cp);
				} else {
					Console.WriteLine( "This CluePacket is the same as the last one, why do more work?");
				}
				
			}
		}

		// Called back by the runtime, when the QueryBackend
		// async method terminates
		void QueryBackendDone (IAsyncResult ar)
		{
			QueryBackendHandler query_backend = (QueryBackendHandler) (((AsyncResult)ar).AsyncDelegate);

			try {
				query_backend.EndInvoke (ar);
			} catch (Exception e) {
				Console.WriteLine ("Exception inside QueryBackend");
//				Console.WriteLine (e);
			}
		}

		// Search the backends directory for DLLs that are
		// Dashboard backends and start them up.
		public void LoadBackends ()
		{

			backends_dir = Environment.GetEnvironmentVariable ("DASHBOARD_BACKEND_PATH");
			if (backends_dir == null || backends_dir == "")
				backends_dir = "../backends";

			string [] files = Directory.GetFiles (backends_dir, "*.dll");

			foreach (string file in files) {
				try {

					Console.WriteLine ("Checking backend " + file);

					Assembly a = Assembly.LoadFrom (file);
					Type [] types = a.GetTypes ();

					foreach (Type t in types) {
						if (!t.IsSubclassOf (typeof (Backend)))
							continue;

						Console.WriteLine ("Loading backend " + file);

						Backend backend = (Backend) Activator.CreateInstance (t);

						ThreadPool.QueueUserWorkItem (new WaitCallback (this.LaunchBackend), backend);
					}
				} catch {
					//
					// Ignore an error if the file is not really an assembly
					//
				}
			}
		}

		// In a separate thread
		void LaunchBackend (object o)
		{
			try {
				Backend b = (Backend) o;
				
				if (b.Startup ()) {
					Console.WriteLine ("{0} successfully loaded", b.Name);
					lock (backends){
						backends.Add (b);
					}
				} else {
					Console.WriteLine ("{0} NOT loaded", b.Name);
				}
			} catch (Exception e) {
				Console.WriteLine ("Received exception while loading Backend:");
				Console.WriteLine ("   Backend type: {0}\n" + o.GetType ().ToString ());
				Console.WriteLine ("Exception is:\n{0}", e);
			}
		}

		// FIXME: This should not be here.  It's only in the
		// CPM because that's where we're keeping the backend
		// list.
		public void NotifyBackendLinkClicked (string url)
		{
			string backend_name = null;
			string[] split;

			try {
				split = url.Split (':');
				backend_name = split [1];
			} catch {
				Console.WriteLine ("Could not get backend name from link URL");
				return;
			}

			if (backend_name == null || backend_name == "") {
				Console.WriteLine ("Could not get backend name from link URL");
				return;
			}

			string user_data = url.Substring (backend_name.Length + "backend::".Length);

			Console.WriteLine ("LinkClicked [{0}] [{1}]", backend_name, user_data);

			lock (backends) {
				foreach (Backend b in this.backends)
					if (b.Name == backend_name) {
						b.LinkClicked (user_data);
						return;
					}
			}
		}
	}
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]