From 41b611dacbae902f2a0a52107c9237226511fa60 Mon Sep 17 00:00:00 2001 From: dbera Date: Fri, 4 Aug 2006 07:16:54 +0000 Subject: [PATCH] Sorry for the combined patch. The changes became too inter-dependent. * Gtk-to-Glib: Beagle isnt a Gtk app anymore, but a Glib app. * Try to cover all possible cases of signal handling: even those during startup. --- ChangeLog | 15 ++++ Makefile.am | 2 + Util/Inotify.cs | 86 +++++++++++--------- Util/Scheduler.cs | 28 ++++--- Util/SystemInformation.cs | 92 ++++++++++++--------- beagled/BeagleDaemon.cs | 93 ++++++++++------------ .../EvolutionDataServerQueryable.cs | 9 +++ beagled/ExtractContent.cs | 6 +- beagled/IndexHelper/IndexHelper.cs | 79 ++++++++---------- .../IndexingServiceQueryable.cs | 8 ++ beagled/QueryDriver.cs | 12 ++- beagled/Queryable.cs | 3 +- beagled/Server.cs | 23 ++++-- beagled/Shutdown.cs | 57 ++++++++++--- bludgeon/Bludgeon.cs | 11 +-- configure.in | 13 ++- glue/screensaver-glue.c | 41 ++++++---- tools/Config.cs | 5 +- tools/Query.cs | 53 ++++++------ 19 files changed, 378 insertions(+), 258 deletions(-) diff --git a/ChangeLog b/ChangeLog index e55f2c7d..e64dc4b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-08-04 Debajyoti Bera + + * ContactViewer, beagled/ThunderbirdQueryable: Added .cvsignore files. + * configure.in: Build ContactViewer only if + gui building is enabled. + * configure.in, beagled/BeagleDaemon.cs, IndexHelper.cs, Config.cs, + glue/screensaver-glue.c, SystemInformation.cs etc.: Move from Gtk to Glib. + * BeagleDaemon.cs, Shutdown.cs, QueryDriver.cs, Inotify.cs, + Scheduler.cs etc.: Fix signal handling and starting threads to handle + termination signals properly, even during startup. + * EDS/EvolutionDataServerQueryable.cs, + IndexingServiceQueryable/IndexingServiceQueryable.cs: Start the actual + work in a separate thread or little later, without blocking + QueryDriver. + 2006-07-12 Guntupalli Karunakar * configure.in: Added 'hi' to ALL_LINGUAS. diff --git a/Makefile.am b/Makefile.am index 511711d4..33d6d2f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,8 +37,10 @@ SUBDIRS += bludgeon endif if ENABLE_THUNDERBIRD +if ENABLE_GUI SUBDIRS += ContactViewer endif +endif # When the chooser work has been fixed up to use libbeagle, we can # reenable this directory. diff --git a/Util/Inotify.cs b/Util/Inotify.cs index 6e161c6e..78ce1229 100644 --- a/Util/Inotify.cs +++ b/Util/Inotify.cs @@ -75,13 +75,13 @@ namespace Beagle.Util { } // Events that we want internally, even if the handlers do not - static private EventType base_mask = EventType.MovedFrom | EventType.MovedTo; + private static EventType base_mask = EventType.MovedFrom | EventType.MovedTo; ///////////////////////////////////////////////////////////////////////////////////// - static private Logger log; + private static Logger log; - static public Logger Log { + public static Logger Log { get { return log; } } @@ -114,8 +114,8 @@ namespace Beagle.Util { ///////////////////////////////////////////////////////////////////////////////////// - static public bool Verbose = false; - static private int inotify_fd = -1; + public static bool Verbose = false; + private static int inotify_fd = -1; static Inotify () { @@ -140,7 +140,7 @@ namespace Beagle.Util { Logger.Log.Warn ("Could not initialize inotify"); } - static public bool Enabled { + public static bool Enabled { get { return inotify_fd >= 0; } } @@ -150,17 +150,17 @@ namespace Beagle.Util { // Stubs for systems where inotify is unavailable - static public Watch Subscribe (string path, InotifyCallback callback, EventType mask) + public static Watch Subscribe (string path, InotifyCallback callback, EventType mask) { return null; } - static public void Start () + public static void Start () { return; } - static public void Stop () + public static void Stop () { return; } @@ -168,7 +168,7 @@ namespace Beagle.Util { #else // ENABLE_INOTIFY ///////////////////////////////////////////////////////////////////////////////////// - static private ArrayList event_queue = new ArrayList (); + private static ArrayList event_queue = new ArrayList (); private class QueuedEvent { public int Wd; @@ -266,9 +266,9 @@ namespace Beagle.Util { public ArrayList Subscribers; } - static Hashtable watched_by_wd = new Hashtable (); - static Hashtable watched_by_path = new Hashtable (); - static WatchInfo last_watched = null; + private static Hashtable watched_by_wd = new Hashtable (); + private static Hashtable watched_by_path = new Hashtable (); + private static WatchInfo last_watched = null; private class PendingMove { public WatchInfo Watch; @@ -284,11 +284,11 @@ namespace Beagle.Util { } } - static public int WatchCount { + public static int WatchCount { get { return watched_by_wd.Count; } } - static public bool IsWatching (string path) + public static bool IsWatching (string path) { path = Path.GetFullPath (path); return watched_by_path.Contains (path); @@ -297,7 +297,7 @@ namespace Beagle.Util { // Filter WatchInfo items when we do the Lookup. // We do the filtering here to avoid having to acquire // the watched_by_wd lock yet again. - static private WatchInfo Lookup (int wd, EventType event_type) + private static WatchInfo Lookup (int wd, EventType event_type) { lock (watched_by_wd) { WatchInfo watched; @@ -319,7 +319,7 @@ namespace Beagle.Util { } // The caller has to handle all locking itself - static private void Forget (WatchInfo watched) + private static void Forget (WatchInfo watched) { if (last_watched == watched) last_watched = null; @@ -329,7 +329,7 @@ namespace Beagle.Util { watched_by_path.Remove (watched.Path); } - static public Watch Subscribe (string path, InotifyCallback callback, EventType mask, EventType initial_filter) + public static Watch Subscribe (string path, InotifyCallback callback, EventType mask, EventType initial_filter) { WatchInternal watch; WatchInfo watched; @@ -375,12 +375,12 @@ namespace Beagle.Util { return watch; } - static public Watch Subscribe (string path, InotifyCallback callback, EventType mask) + public static Watch Subscribe (string path, InotifyCallback callback, EventType mask) { return Subscribe (path, callback, mask, 0); } - static public EventType Filter (string path, EventType mask) + public static EventType Filter (string path, EventType mask) { EventType seen = 0; @@ -398,7 +398,7 @@ namespace Beagle.Util { return seen; } - static private void Unsubscribe (WatchInfo watched, WatchInternal watch) + private static void Unsubscribe (WatchInfo watched, WatchInternal watch) { watched.Subscribers.Remove (watch); @@ -421,7 +421,7 @@ namespace Beagle.Util { // Ensure our watch exists, meets all the subscribers requirements, // and isn't matching any other events that we don't care about. - static private void CreateOrModifyWatch (WatchInfo watched) + private static void CreateOrModifyWatch (WatchInfo watched) { EventType new_mask = base_mask; foreach (WatchInternal watch in watched.Subscribers) @@ -451,10 +451,17 @@ namespace Beagle.Util { ///////////////////////////////////////////////////////////////////////////////////// - static Thread snarf_thread = null; - static bool running = false; + private static Thread snarf_thread = null; + private static bool running = false; + private static bool shutdown_requested = false; - static public void Start () + public static void ShutdownRequested () { + lock (event_queue) { + shutdown_requested = true; + } + } + + public static void Start () { if (! Enabled) return; @@ -462,7 +469,7 @@ namespace Beagle.Util { Logger.Log.Debug("Starting Inotify threads"); lock (event_queue) { - if (snarf_thread != null) + if (shutdown_requested || snarf_thread != null) return; running = true; @@ -472,12 +479,19 @@ namespace Beagle.Util { } } - static public void Stop () + public static void Stop () { if (! Enabled) return; + Log.Debug ("Stopping inotify threads"); + lock (event_queue) { + shutdown_requested = true; + + if (! running) + return; + running = false; Monitor.Pulse (event_queue); } @@ -485,7 +499,7 @@ namespace Beagle.Util { inotify_snarf_cancel (); } - static unsafe void SnarfWorker () + private static unsafe void SnarfWorker () { Encoding filename_encoding = Encoding.UTF8; int event_size = Marshal.SizeOf (typeof (inotify_event)); @@ -558,7 +572,7 @@ namespace Beagle.Util { // Update the watched_by_path hash and the path stored inside the watch // in response to a move event. - static private void MoveWatch (WatchInfo watch, string name) + private static void MoveWatch (WatchInfo watch, string name) { lock (watched_by_wd) { @@ -573,7 +587,7 @@ namespace Beagle.Util { // A directory we are watching has moved. We need to fix up its path, and the path of // all of its subdirectories, their subdirectories, and so on. - static private void HandleMove (string srcpath, string dstparent, string dstname) + private static void HandleMove (string srcpath, string dstparent, string dstname) { string dstpath = Path.Combine (dstparent, dstname); lock (watched_by_wd) { @@ -610,7 +624,7 @@ namespace Beagle.Util { } } - static private void SendEvent (WatchInfo watched, string filename, string srcpath, EventType mask) + private static void SendEvent (WatchInfo watched, string filename, string srcpath, EventType mask) { // Does the watch care about this event? if ((watched.Mask & mask) == 0) @@ -645,11 +659,11 @@ namespace Beagle.Util { // Dispatch-time operations on the event queue - static Hashtable pending_move_cookies = new Hashtable (); + private static Hashtable pending_move_cookies = new Hashtable (); // Clean up the queue, removing dispatched objects. // We assume that the called holds the event_queue lock. - static void CleanQueue_Unlocked () + private static void CleanQueue_Unlocked () { int first_undispatched = 0; while (first_undispatched < event_queue.Count) { @@ -671,7 +685,7 @@ namespace Beagle.Util { // Apply high-level processing to the queue. Pair moves, // coalesce events, etc. // We assume that the caller holds the event_queue lock. - static void AnalyzeQueue_Unlocked () + private static void AnalyzeQueue_Unlocked () { int first_unanalyzed = event_queue.Count; while (first_unanalyzed > 0) { @@ -711,7 +725,7 @@ namespace Beagle.Util { } } - static void DispatchWorker () + private static void DispatchWorker () { while (running) { QueuedEvent next_event = null; @@ -805,7 +819,7 @@ namespace Beagle.Util { ///////////////////////////////////////////////////////////////////////////////// #if INOTIFY_TEST - static void Main (string [] args) + private static void Main (string [] args) { Queue to_watch = new Queue (); bool recursive = false; diff --git a/Util/Scheduler.cs b/Util/Scheduler.cs index 8baaf9cc..7dbf7034 100644 --- a/Util/Scheduler.cs +++ b/Util/Scheduler.cs @@ -39,7 +39,7 @@ namespace Beagle.Util { public delegate void EmptyQueueDelegate (); public event EmptyQueueDelegate EmptyQueueEvent; - static public bool Debug = false; + public static bool Debug = false; public enum Priority { @@ -515,7 +515,7 @@ namespace Beagle.Util { ////////////////////////////////////////////////////////////////////////////// - static private double global_delay = -1.0; + private static double global_delay = -1.0; static Scheduler () { @@ -532,9 +532,9 @@ namespace Beagle.Util { ////////////////////////////////////////////////////////////////////////////// - static private Scheduler global = new Scheduler (); + private static Scheduler global = new Scheduler (); - static public Scheduler Global { + public static Scheduler Global { get { return global; } } @@ -621,22 +621,25 @@ namespace Beagle.Util { ////////////////////////////////////////////////////////////////////////////// - Thread thread = null; + private Thread thread = null; public bool running = false; + private static bool shutdown_requested = false; public void Start () { lock (this) { - if (thread != null) + if (shutdown_requested || thread != null) return; running = true; thread = ExceptionHandlingThread.Start (new ThreadStart (Worker)); } } - public void Stop () + public void Stop (bool to_shutdown) { lock (big_lock) { + shutdown_requested = to_shutdown; + if (running) { running = false; thread = null; @@ -646,6 +649,11 @@ namespace Beagle.Util { } } + public void Stop () + { + Stop (false); + } + // // Delay Computations // @@ -1164,17 +1172,17 @@ namespace Beagle.Util { Reschedule = true; } - static void BeginTaskGroup () + private static void BeginTaskGroup () { Console.WriteLine ("--- Begin Task Group!"); } - static void EndTaskGroup () + private static void EndTaskGroup () { Console.WriteLine ("--- End Task Group!"); } - static void Main () + public static void Main () { Scheduler sched = Scheduler.Global; diff --git a/Util/SystemInformation.cs b/Util/SystemInformation.cs index b5aa02f6..aeff23b6 100644 --- a/Util/SystemInformation.cs +++ b/Util/SystemInformation.cs @@ -42,12 +42,12 @@ namespace Beagle.Util { static extern int getloadavg (double[] loadavg, int nelem); const double loadavg_poll_delay = 3; - static DateTime proc_loadavg_time = DateTime.MinValue; - static double cached_loadavg_1min = -1; - static double cached_loadavg_5min = -1; - static double cached_loadavg_15min = -1; + private static DateTime proc_loadavg_time = DateTime.MinValue; + private static double cached_loadavg_1min = -1; + private static double cached_loadavg_5min = -1; + private static double cached_loadavg_15min = -1; - static private void CheckLoadAverage () + private static void CheckLoadAverage () { // Only call getloadavg() at most once every 10 seconds if ((DateTime.Now - proc_loadavg_time).TotalSeconds < loadavg_poll_delay) @@ -68,21 +68,21 @@ namespace Beagle.Util { proc_loadavg_time = DateTime.Now; } - static public double LoadAverageOneMinute { + public static double LoadAverageOneMinute { get { CheckLoadAverage (); return cached_loadavg_1min; } } - static public double LoadAverageFiveMinute { + public static double LoadAverageFiveMinute { get { CheckLoadAverage (); return cached_loadavg_5min; } } - static public double LoadAverageFifteenMinute { + public static double LoadAverageFifteenMinute { get { CheckLoadAverage (); return cached_loadavg_15min; @@ -91,10 +91,11 @@ namespace Beagle.Util { /////////////////////////////////////////////////////////////// + private static bool use_screensaver = false; const double screensaver_poll_delay = 1; - static DateTime screensaver_time = DateTime.MinValue; - static bool cached_screensaver_running = false; - static double cached_screensaver_idle_time = 0; + private static DateTime screensaver_time = DateTime.MinValue; + private static bool cached_screensaver_running = false; + private static double cached_screensaver_idle_time = 0; private enum ScreenSaverState { Off = 0, @@ -110,13 +111,31 @@ namespace Beagle.Util { } [DllImport ("libbeagleglue.so")] + extern static unsafe int screensaver_glue_init (); + + public static bool XssInit () + { + return XssInit (false); + } + + public static bool XssInit (bool actually_init_xss) + { + int has_xss = screensaver_glue_init (); + use_screensaver = (has_xss == 1); + return use_screensaver; + } + + [DllImport ("libbeagleglue.so")] extern static unsafe int screensaver_info (ScreenSaverState *state, ScreenSaverKind *kind, ulong *til_or_since, ulong *idle); - static private void CheckScreenSaver () + private static void CheckScreenSaver () { + if (! use_screensaver) + return; + if ((DateTime.Now - screensaver_time).TotalSeconds < screensaver_poll_delay) return; @@ -140,7 +159,7 @@ namespace Beagle.Util { screensaver_time = DateTime.Now; } - static public bool ScreenSaverRunning { + public static bool ScreenSaverRunning { get { CheckScreenSaver (); return cached_screensaver_running; @@ -149,7 +168,7 @@ namespace Beagle.Util { // returns number of seconds since input was received // from the user on any input device - static public double InputIdleTime { + public static double InputIdleTime { get { CheckScreenSaver (); return cached_screensaver_idle_time; @@ -161,11 +180,11 @@ namespace Beagle.Util { const double acpi_poll_delay = 30; const string proc_ac_state_filename = "/proc/acpi/ac_adapter/AC/state"; const string ac_present_string = "on-line"; - static bool proc_ac_state_exists = true; - static DateTime using_battery_time = DateTime.MinValue; - static bool using_battery; + private static bool proc_ac_state_exists = true; + private static DateTime using_battery_time = DateTime.MinValue; + private static bool using_battery; - static public void CheckAcpi () + public static void CheckAcpi () { if (! proc_ac_state_exists) return; @@ -194,7 +213,7 @@ namespace Beagle.Util { using_battery_time = DateTime.Now; } - static public bool UsingBattery { + public static bool UsingBattery { get { CheckAcpi (); return using_battery; @@ -209,28 +228,28 @@ namespace Beagle.Util { [DllImport ("libbeagleglue")] extern static int get_vmrss (); - static public int VmSize { + public static int VmSize { get { return get_vmsize (); } } - static public int VmRss { + public static int VmRss { get { return get_vmrss (); } } /////////////////////////////////////////////////////////////// - static private int disk_stats_read_reqs; - static private int disk_stats_write_reqs; - static private int disk_stats_read_bytes; - static private int disk_stats_write_bytes; + private static int disk_stats_read_reqs; + private static int disk_stats_write_reqs; + private static int disk_stats_read_bytes; + private static int disk_stats_write_bytes; - static private DateTime disk_stats_time = DateTime.MinValue; - static private double disk_stats_delay = 1.0; + private static DateTime disk_stats_time = DateTime.MinValue; + private static double disk_stats_delay = 1.0; - static private uint major, minor; + private static uint major, minor; // Update the disk statistics with data for block device on the (major,minor) pair. - static private void UpdateDiskStats () + private static void UpdateDiskStats () { string buffer; @@ -260,7 +279,7 @@ namespace Beagle.Util { } // Get the (major,minor) pair for the block device from which the index is mounted. - static private void GetIndexDev () + private static void GetIndexDev () { Mono.Unix.Native.Stat stat; if (Mono.Unix.Native.Syscall.stat (PathFinder.StorageDir, out stat) != 0) @@ -270,7 +289,7 @@ namespace Beagle.Util { minor = (uint) stat.st_dev & 0xff; } - static public int DiskStatsReadReqs { + public static int DiskStatsReadReqs { get { if (major == 0) GetIndexDev (); @@ -279,7 +298,7 @@ namespace Beagle.Util { } } - static public int DiskStatsReadBytes { + public static int DiskStatsReadBytes { get { if (major == 0) GetIndexDev (); @@ -288,7 +307,7 @@ namespace Beagle.Util { } } - static public int DiskStatsWriteReqs { + public static int DiskStatsWriteReqs { get { if (major == 0) GetIndexDev (); @@ -297,7 +316,7 @@ namespace Beagle.Util { } } - static public int DiskStatsWriteBytes { + public static int DiskStatsWriteBytes { get { if (major == 0) GetIndexDev (); @@ -306,7 +325,7 @@ namespace Beagle.Util { } } - static public bool IsPathOnBlockDevice (string path) + public static bool IsPathOnBlockDevice (string path) { Mono.Unix.Native.Stat stat; if (Mono.Unix.Native.Syscall.stat (path, out stat) != 0) @@ -354,9 +373,8 @@ namespace Beagle.Util { /////////////////////////////////////////////////////////////// #if false - static void Main () + public static void Main () { - Gtk.Application.Init (); while (true) { Console.WriteLine ("{0} {1} {2} {3} {4} {5} {6} {7}", LoadAverageOneMinute, diff --git a/beagled/BeagleDaemon.cs b/beagled/BeagleDaemon.cs index 3d47e48c..14bb6c74 100644 --- a/beagled/BeagleDaemon.cs +++ b/beagled/BeagleDaemon.cs @@ -30,10 +30,11 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; - -using Gtk; +using Thread = System.Threading.Thread; +using GLib; using Beagle.Util; +using Log = Beagle.Util.Log; #if ENABLE_WEBSERVICES using Beagle.WebService; @@ -43,6 +44,7 @@ namespace Beagle.Daemon { class BeagleDaemon { public static Thread MainLoopThread = null; + private static MainLoop main_loop = null; private static Server server = null; @@ -53,6 +55,7 @@ namespace Beagle.Daemon { public static bool StartServer () { Logger.Log.Debug ("Starting messaging server"); + try { server = new Server ("socket"); server.Start (); @@ -135,12 +138,12 @@ namespace Beagle.Daemon { public static bool StartupProcess () { + Log.Debug ("Beginning main loop"); + // Profile our initialization Stopwatch stopwatch = new Stopwatch (); stopwatch.Start (); - SetupSignalHandlers (); - // Fire up our server if (! StartServer ()) { if (arg_replace) @@ -201,8 +204,6 @@ namespace Beagle.Daemon { //Beagle Web, WebService access initialization code: WebServiceBackEnd.Start(); #endif - Shutdown.ShutdownEvent += OnShutdown; - Conf.WatchForUpdates (); stopwatch.Stop (); @@ -218,7 +219,7 @@ namespace Beagle.Daemon { return false; } - static void OnEmptySchedulerQueue () + private static void OnEmptySchedulerQueue () { Logger.Log.Debug ("Scheduler queue is empty: terminating immediately"); Shutdown.BeginShutdown (); @@ -458,13 +459,21 @@ namespace Beagle.Daemon { // Do BEAGLE_EXERCISE_THE_DOG_HARDER-related processing. ExerciseTheDogHarder (); - if (Application.InitCheck ("beagled", ref args)) + if (SystemInformation.XssInit ()) Logger.Log.Debug ("Established a connection to the X server"); else Logger.Log.Debug ("Unable to establish a connection to the X server"); - XSetIOErrorHandler (BeagleXIOErrorHandler); + QueryDriver.Init (); + Server.Init (); + + SetupSignalHandlers (); + Shutdown.ShutdownEvent += OnShutdown; + + main_loop = new MainLoop (); + Shutdown.RegisterMainLoop (main_loop); + // Defer all actual startup until the main loop is // running. That way shutdowns during the startup // process work correctly. @@ -472,8 +481,7 @@ namespace Beagle.Daemon { // Start our event loop. Logger.Log.Debug ("Starting main loop"); - - Application.Run (); + main_loop.Run (); // If we placed our sockets in a temp directory, try to clean it up // Note: this may fail because the helper is still running @@ -511,6 +519,7 @@ namespace Beagle.Daemon { return true; } + ///////////////////////////////////////////////////////////////////////////// private delegate int XIOErrorHandler (IntPtr display); @@ -535,7 +544,7 @@ namespace Beagle.Daemon { ///////////////////////////////////////////////////////////////////////////// - static void SetupSignalHandlers () + private static void SetupSignalHandlers () { // Force OurSignalHandler to be JITed OurSignalHandler (-1); @@ -549,60 +558,38 @@ namespace Beagle.Daemon { Mono.Unix.Native.Stdlib.signal (Mono.Unix.Native.Signum.SIGPIPE, Mono.Unix.Native.Stdlib.SIG_IGN); } - // Our handler triggers an orderly shutdown when it receives a signal. - // However, this can be annoying if the process gets wedged during - // shutdown. To deal with that case, we make a note of the time when - // the first signal comes in, and we allow signals to unconditionally - // kill the process after 5 seconds have passed. - static DateTime signal_time = DateTime.MinValue; - static void OurSignalHandler (int signal) + // Mono signal handler allows setting of global variables; + // anything else e.g. function calls, even reentrant native methods are risky + private static void OurSignalHandler (int signal) { // This allows us to call OurSignalHandler w/o doing anything. // We want to call it once to ensure that it is pre-JITed. if (signal < 0) return; + // Set shutdown flag to true so that other threads can stop initializing + if ((Mono.Unix.Native.Signum) signal != Mono.Unix.Native.Signum.SIGUSR1) + Shutdown.ShutdownRequested = true; + + // Do all signal handling work in the main loop and not in the signal handler. + GLib.Idle.Add (new GLib.IdleHandler (delegate () { HandleSignal (signal); return false; })); + } + + private static void HandleSignal (int signal) + { Logger.Log.Debug ("Handling signal {0} ({1})", signal, (Mono.Unix.Native.Signum) signal); // If we get SIGUSR1, turn the debugging level up. if ((Mono.Unix.Native.Signum) signal == Mono.Unix.Native.Signum.SIGUSR1) { LogLevel old_level = Log.Level; - Log.Level = LogLevel.Debug; - Log.Debug ("Moving from log level {0} to Debug", old_level); - GLib.Idle.Add (new GLib.IdleHandler (delegate () { RemoteIndexer.SignalRemoteIndexer (); return false; })); - return; } - bool first_signal = false; - if (signal_time == DateTime.MinValue) { - signal_time = DateTime.Now; - first_signal = true; - } - - if (Shutdown.ShutdownRequested) { - - if (first_signal) { - Logger.Log.Debug ("Shutdown already in progress."); - } else { - double t = (DateTime.Now - signal_time).TotalSeconds; - const double min_t = 5; - - if (t < min_t) { - Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t); - } else { - Logger.Log.Debug ("Forcing immediate shutdown."); - Environment.Exit (0); - } - } - - } else { - Logger.Log.Debug ("Initiating shutdown in response to signal."); - Shutdown.BeginShutdown (); - } + Logger.Log.Debug ("Initiating shutdown in response to signal."); + Shutdown.BeginShutdown (); } ///////////////////////////////////////////////////////////////////////////// @@ -615,11 +602,12 @@ namespace Beagle.Daemon { // Stop our Inotify threads Inotify.Stop (); - // Shut down the global scheduler - Scheduler.Global.Stop (); + // Stop the global scheduler and ask it to shutdown + Scheduler.Global.Stop (true); // Stop the messaging server - server.Stop (); + if (server != null) + server.Stop (); } ///////////////////////////////////////////////////////////////////////////// @@ -679,4 +667,5 @@ namespace Beagle.Daemon { } } } + } diff --git a/beagled/EvolutionDataServerQueryable/EvolutionDataServerQueryable.cs b/beagled/EvolutionDataServerQueryable/EvolutionDataServerQueryable.cs index 9630b2b1..b42bdf2f 100644 --- a/beagled/EvolutionDataServerQueryable/EvolutionDataServerQueryable.cs +++ b/beagled/EvolutionDataServerQueryable/EvolutionDataServerQueryable.cs @@ -66,6 +66,15 @@ namespace Beagle.Daemon.EvolutionDataServerQueryable { { base.Start (); + // Defer the actual startup till main_loop starts. + // This will improve kill beagle while starting up. + // EDS requires StartWorker to run in mainloop, + // hence it is not started in a separate thread. + GLib.Idle.Add (new GLib.IdleHandler (StartWorker)); + } + + private void StartWorker () + { Logger.Log.Info ("Scanning addressbooks and calendars"); Stopwatch timer = new Stopwatch (); timer.Start (); diff --git a/beagled/ExtractContent.cs b/beagled/ExtractContent.cs index ad86eacd..d2efca32 100644 --- a/beagled/ExtractContent.cs +++ b/beagled/ExtractContent.cs @@ -248,10 +248,12 @@ class ExtractContentTool { if (writer != null) writer.Close (); + GLib.MainLoop main_loop = new GLib.MainLoop (); + if (Environment.GetEnvironmentVariable ("BEAGLE_TEST_MEMORY") != null) { GC.Collect (); - GLib.Timeout.Add (1000, delegate() { Gtk.Application.Quit (); return false; }); - Gtk.Application.Run (); + GLib.Timeout.Add (1000, delegate() { main_loop.Quit (); return false; }); + main_loop.Run (); } return 0; diff --git a/beagled/IndexHelper/IndexHelper.cs b/beagled/IndexHelper/IndexHelper.cs index c13ca44f..b419f6ff 100644 --- a/beagled/IndexHelper/IndexHelper.cs +++ b/beagled/IndexHelper/IndexHelper.cs @@ -32,22 +32,25 @@ using SNS = System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; -using Gtk; +using GLib; using Beagle.Daemon; using Beagle.Util; +using Log = Beagle.Util.Log; +using Thread = System.Threading.Thread; namespace Beagle.IndexHelper { class IndexHelperTool { + private static MainLoop main_loop; - static DateTime last_activity; - static Server server; + private static DateTime last_activity; + private static Server server; [DllImport ("libc")] extern static private int unsetenv (string name); - static void Main (string [] args) + public static void Main (string [] args) { try { DoMain (args); @@ -58,7 +61,7 @@ namespace Beagle.IndexHelper { } } - static void DoMain (string [] args) + private static void DoMain (string [] args) { SystemInformation.SetProcessName ("beagled-helper"); @@ -82,14 +85,17 @@ namespace Beagle.IndexHelper { // goes away. It's important to do this before // Application.InitCheck(), since that's what makes the // connection. - unsetenv ("DISPLAY"); + //unsetenv ("DISPLAY"); - Application.InitCheck ("IndexHelper", ref args); + SystemInformation.XssInit (false); SetupSignalHandlers (); Shutdown.ShutdownEvent += OnShutdown; + main_loop = new MainLoop (); + Shutdown.RegisterMainLoop (main_loop); + // Start the server Logger.Log.Debug ("Starting messaging server"); bool server_has_been_started = false; @@ -116,7 +122,8 @@ namespace Beagle.IndexHelper { // if it terminates. ExceptionHandlingThread.Start (new ThreadStart (DaemonMonitorWorker)); - Application.Run (); + //Application.Run (); + main_loop.Run (); // If we palced our sockets in a temp directory, try to clean it up // Note: this may fail because the daemon is still running @@ -128,12 +135,12 @@ namespace Beagle.IndexHelper { } } - static public void ReportActivity () + public static void ReportActivity () { last_activity = DateTime.Now; } - static void MemoryAndIdleMonitorWorker () + private static void MemoryAndIdleMonitorWorker () { int vmrss_original = SystemInformation.VmRss; @@ -177,7 +184,7 @@ namespace Beagle.IndexHelper { } } - static void DaemonMonitorWorker () + private static void DaemonMonitorWorker () { string storage_dir = PathFinder.GetRemoteStorageDir (false); @@ -217,7 +224,7 @@ namespace Beagle.IndexHelper { ///////////////////////////////////////////////////////////////////////////// - static void SetupSignalHandlers () + private static void SetupSignalHandlers () { // Force OurSignalHandler to be JITed OurSignalHandler (-1); @@ -236,57 +243,39 @@ namespace Beagle.IndexHelper { // shutdown. To deal with that case, we make a note of the time when // the first signal comes in, and we allow signals to unconditionally // kill the process after 5 seconds have passed. - static DateTime signal_time = DateTime.MinValue; - static void OurSignalHandler (int signal) + private static DateTime signal_time = DateTime.MinValue; + private static void OurSignalHandler (int signal) { // This allows us to call OurSignalHandler w/o doing anything. // We want to call it once to ensure that it is pre-JITed. if (signal < 0) return; + // Set shutdown flag to true so that other threads can stop initializing + if ((Mono.Unix.Native.Signum) signal != Mono.Unix.Native.Signum.SIGUSR1) + Shutdown.ShutdownRequested = true; + + // Do all signal handling work in the main loop and not in the signal handler. + GLib.Idle.Add (new GLib.IdleHandler (delegate () { HandleSignal (signal); return false; })); + } + + private static void HandleSignal (int signal) + { Logger.Log.Debug ("Handling signal {0} ({1})", signal, (Mono.Unix.Native.Signum) signal); // If we get SIGUSR1, turn the debugging level up. if ((Mono.Unix.Native.Signum) signal == Mono.Unix.Native.Signum.SIGUSR1) { LogLevel old_level = Log.Level; - Log.Level = LogLevel.Debug; - Log.Debug ("Moving from log level {0} to Debug", old_level); - return; } - - bool first_signal = false; - if (signal_time == DateTime.MinValue) { - signal_time = DateTime.Now; - first_signal = true; - } - - if (Shutdown.ShutdownRequested) { - - if (first_signal) { - Logger.Log.Debug ("Shutdown already in progress."); - } else { - double t = (DateTime.Now - signal_time).TotalSeconds; - const double min_t = 5; - - if (t < min_t) { - Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t); - } else { - Logger.Log.Debug ("Forcing immediate shutdown."); - Environment.Exit (0); - } - } - - } else { - Logger.Log.Debug ("Initiating shutdown in response to signal."); - Shutdown.BeginShutdown (); - } + Logger.Log.Debug ("Initiating shutdown in response to signal."); + Shutdown.BeginShutdown (); } - static void OnShutdown () + private static void OnShutdown () { if (server != null) server.Stop (); diff --git a/beagled/IndexingServiceQueryable/IndexingServiceQueryable.cs b/beagled/IndexingServiceQueryable/IndexingServiceQueryable.cs index b2d711f3..e5a516c7 100644 --- a/beagled/IndexingServiceQueryable/IndexingServiceQueryable.cs +++ b/beagled/IndexingServiceQueryable/IndexingServiceQueryable.cs @@ -45,6 +45,7 @@ using System; using System.Collections; using System.IO; +using System.Threading; using Beagle.Daemon; using Beagle.Util; @@ -61,6 +62,13 @@ namespace Beagle.Daemon.IndexingServiceQueryable { public override void Start () { + base.Start (); + + ExceptionHandlingThread.Start (new ThreadStart (StartWorker)); + } + + private void StartWorker () + { string index_path = Path.Combine (PathFinder.StorageDir, "ToIndex"); if (!Directory.Exists (index_path)) diff --git a/beagled/QueryDriver.cs b/beagled/QueryDriver.cs index 32eab5a3..0a8af38b 100644 --- a/beagled/QueryDriver.cs +++ b/beagled/QueryDriver.cs @@ -329,12 +329,18 @@ namespace Beagle.Daemon { //////////////////////////////////////////////////////// - static public void Start () + private static ArrayList assemblies = null; + + // Perform expensive initialization steps all at once. + // Should be done before SignalHandler comes into play. + static public void Init () { ReadBackendsFromConf (); + assemblies = ReflectionFu.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder.BackendDir); + } - ArrayList assemblies = ReflectionFu.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder.BackendDir); - + static public void Start () + { // Only add the executing assembly if we haven't already loaded it. if (assemblies.IndexOf (Assembly.GetExecutingAssembly ()) == -1) assemblies.Add (Assembly.GetExecutingAssembly ()); diff --git a/beagled/Queryable.cs b/beagled/Queryable.cs index 33f3438b..58852781 100644 --- a/beagled/Queryable.cs +++ b/beagled/Queryable.cs @@ -47,7 +47,8 @@ namespace Beagle.Daemon { public void Start () { - iqueryable.Start (); + if (! Shutdown.ShutdownRequested) + iqueryable.Start (); } public string Name { diff --git a/beagled/Server.cs b/beagled/Server.cs index af5c1ac3..4ef007d4 100644 --- a/beagled/Server.cs +++ b/beagled/Server.cs @@ -40,7 +40,9 @@ namespace Beagle.Daemon { class ConnectionHandler { private static int connection_count = 0; - public static XmlSerializer serializer = null; + private static XmlSerializer serializer = null; + private static XmlSerializer req_serializer = null; + private object client_lock = new object (); private object blocking_read_lock = new object (); @@ -55,6 +57,13 @@ namespace Beagle.Daemon { this.client = client; } + // Perform expensive serialization all at once. Do this before signal handler is setup. + public static void Init () + { + serializer = new XmlSerializer (typeof (ResponseWrapper), ResponseMessage.Types); + req_serializer = new XmlSerializer (typeof (RequestWrapper), RequestMessage.Types); + } + public bool SendResponse (ResponseMessage response) { lock (this.client_lock) { @@ -152,8 +161,6 @@ namespace Beagle.Daemon { Close (); } - static XmlSerializer req_serializer = new XmlSerializer (typeof (RequestWrapper), RequestMessage.Types); - public void HandleConnection () { this.thread = Thread.CurrentThread; @@ -318,11 +325,12 @@ namespace Beagle.Daemon { } - static Server () + // Perform expensive serialization all at once. Do this before signal handler is setup. + public static void Init () { ScanAssemblyForExecutors (Assembly.GetExecutingAssembly ()); - Shutdown.ShutdownEvent += OnShutdown; + ConnectionHandler.Init (); } static internal void MarkHandlerAsKilled (ConnectionHandler handler) @@ -347,9 +355,8 @@ namespace Beagle.Daemon { this.listener.Start (); this.running = true; - Shutdown.WorkerStart (this, String.Format ("server '{0}'", socket_path)); - if (ConnectionHandler.serializer == null) - ConnectionHandler.serializer = new XmlSerializer (typeof (ResponseWrapper), ResponseMessage.Types); + if (! Shutdown.WorkerStart (this, String.Format ("server '{0}'", socket_path))) + return; while (this.running) { UnixClient client; diff --git a/beagled/Shutdown.cs b/beagled/Shutdown.cs index 968676e7..b7d5bbb4 100644 --- a/beagled/Shutdown.cs +++ b/beagled/Shutdown.cs @@ -94,21 +94,57 @@ namespace Beagle.Daemon { static public bool ShutdownRequested { get { return shutdownRequested; } + set { + lock (shutdownLock) + shutdownRequested = value; + } } - static public void BeginShutdown () + private static GLib.MainLoop main_loop = null; + + public static void RegisterMainLoop (GLib.MainLoop loop) { - if (Debug) - Logger.Log.Debug ("Calling BeginShutdown"); + main_loop = loop; + } + + // Our handler triggers an orderly shutdown when it receives a signal. + // However, this can be annoying if the process gets wedged during + // shutdown. To deal with that case, we make a note of the time when + // the first signal comes in, and we allow signals to unconditionally + // kill the process after 5 seconds have passed. + + static DateTime signal_time = DateTime.MinValue; + public static void BeginShutdown () + { lock (shutdownLock) { - if (shutdownRequested) - return; shutdownRequested = true; } - - if (Debug) - Logger.Log.Debug ("Beginning shutdown event"); + + // FIXME: This whole "unconditional killing after 5 seconds because + // beagled can hang while shutting down" thing should not occur. Any such + // incident should be immediately investigated and fixed. Hint: Sending + // kill -quit `pidof beagled` will probably reveal that beagled got locked + // when signal handler was called and some thread was executing some native + // method. + bool first_signal = false; + if (signal_time == DateTime.MinValue) { + signal_time = DateTime.Now; + first_signal = true; + } + + if (! first_signal) { + double t = (DateTime.Now - signal_time).TotalSeconds; + const double min_t = 5; + + if (t < min_t) { + Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t); + return; + } else { + Logger.Log.Debug ("Forcing immediate shutdown."); + Environment.Exit (0); + } + } if (ShutdownEvent != null) { try { @@ -119,9 +155,6 @@ namespace Beagle.Daemon { } } - if (Debug) - Logger.Log.Debug ("Done with shutdown event"); - int count = 0; lock (shutdownLock) { @@ -138,7 +171,7 @@ namespace Beagle.Daemon { } Logger.Log.Info ("Exiting"); - Gtk.Application.Quit (); + main_loop.Quit (); } } } diff --git a/bludgeon/Bludgeon.cs b/bludgeon/Bludgeon.cs index e133f436..b9253fcb 100644 --- a/bludgeon/Bludgeon.cs +++ b/bludgeon/Bludgeon.cs @@ -103,7 +103,7 @@ namespace Bludgeon { { if (version == null) { Log.Info ("Could not contact daemon -- giving up!"); - Gtk.Application.Quit (); + main_loop.Quit (); } Daemon.WaitUntilIdle (OnDaemonIdle); @@ -125,15 +125,15 @@ namespace Bludgeon { { Daemon.Shutdown (); Log.Spew ("Test home directory was '{0}'", PathFinder.HomeDir); - Gtk.Application.Quit (); + main_loop.Quit (); } ///////////////////////////////////////////////////////////////// + private static GLib.MainLoop main_loop = null; + static void Main (string [] args) { - Gtk.Application.InitCheck ("bludgeon", ref args); - args = CommandLine.Process (typeof (BludgeonMain), args); // BU.CommandLine.Process returns null if --help was passed @@ -185,7 +185,8 @@ namespace Bludgeon { abuse.MaxPause = max_pause; GLib.Idle.Add (new GLib.IdleHandler (Startup)); - Gtk.Application.Run (); + main_loop = new GLib.MainLoop (); + main_loop.Run (); } } } diff --git a/configure.in b/configure.in index ee816df4..dbb0def3 100644 --- a/configure.in +++ b/configure.in @@ -149,6 +149,11 @@ fi AC_SUBST(SQLITE_MAJ_VER) +AC_ARG_ENABLE([xss], + AC_HELP_STRING([--disable-xss], [Disable monitoring xscreensaver to speed up indexing when user is idle]), + enable_xss=$enableval, + enable_xss=yes) + AC_PATH_XTRA # Needed by glue/screensaver-glue.c @@ -160,9 +165,9 @@ CFLAGS="$CFLAGS $X_CFLAGS" LDFLAGS="$LDFLAGS $X_LIBS" AC_CHECK_HEADER(X11/extensions/scrnsaver.h, enable_scrnsaver=yes, enable_scrnsaver=no) AC_CHECK_LIB(Xss,XScreenSaverQueryExtension, enable_libxss=yes, enable_libxss=no) -AM_CONDITIONAL(HAS_LIBXSS, test "x$enable_scrnsaver$enable_libxss" = "xyesyes") -if test "x$enable_scrnsaver$enable_libxss" = "xyesyes"; then +if test "x$enable_xss$enable_scrnsaver$enable_libxss" = "xyesyesyes"; then XSS_LIBS="-lXss" + AC_DEFINE(HAVE_LIBXSS,1,[Define to 1 if libXss is installed]) fi CFLAGS="$OLD_CFLAGS" LDFLAGS="$OLD_LDFLAGS" @@ -341,7 +346,7 @@ PKG_CHECK_MODULES(BEAGLED, [ shared-mime-info gmime-sharp >= $GMIME_SHARP_REQUIRED - gtk-sharp-2.0 >= $GTK_SHARP_REQUIRED + glib-sharp-2.0 >= $GTK_SHARP_REQUIRED ]) BEAGLED_LIBS="$BEAGLED_LIBS $GSF_SHARP_LIBS" AC_SUBST(BEAGLED_LIBS) @@ -491,7 +496,6 @@ AC_SUBST(GTK_BINARY_VERSION) dnl For the systeminfo glue -PKG_CHECK_MODULES(SYSTEMINFO_GLUE, gdk-2.0) SYSTEMINFO_GLUE_X_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $XSS_LIBS $X_EXTRA_LIBS" AC_SUBST(SYSTEMINFO_GLUE_X_LIBS) @@ -697,6 +701,7 @@ echo " Enable WebServices no (WebServices are deprecated) Enable libbeagle ${enable_libbeagle} Enable python bindings ${have_python} + Monitor xscreensaver `test "$XSS_LIBS" = "-lXss" && echo yes || echo no` Enable beagle-search GUI ${enable_gui} Enable \"Open With\" menu ${OPEN_WITH} diff --git a/glue/screensaver-glue.c b/glue/screensaver-glue.c index 12ba0d91..69b158bb 100644 --- a/glue/screensaver-glue.c +++ b/glue/screensaver-glue.c @@ -27,11 +27,29 @@ * DEALINGS IN THE SOFTWARE. */ -#include -#include +#include +#include + +#if HAVE_LIBXSS == 1 #include #include +// Once an X-connection is eshtablished, if it breaks, the program terminates. +// So, we can safely store the DISPLAY once it is set and re-use it. +static Display *dsp = NULL; +#endif + +int +screensaver_glue_init () +{ +#if HAVE_LIBXSS == 1 + // screensaver_info is called only from the Scheduler thread; thus we dont need to enable XInitThreads() + dsp = XOpenDisplay(getenv("DISPLAY")); + return (dsp == NULL ? 0 : 1); +#else + return 0; +#endif +} int screensaver_info (int *state, int *kind, unsigned long *til_or_since, unsigned long *idle) @@ -42,22 +60,15 @@ screensaver_info (int *state, int *kind, unsigned long *til_or_since, unsigned l static int inited = 0; int event_base, error_base; - if (GDK_DISPLAY () == NULL) - return 0; - - /* FIXME: This should be called somewhere else. */ - if (! inited) { - gdk_threads_init (); - inited = 1; + if(dsp == NULL) { + return 0; } - - gdk_threads_enter (); - if (XScreenSaverQueryExtension (GDK_DISPLAY (), &event_base, &error_base)) - retval = XScreenSaverQueryInfo (GDK_DISPLAY (), DefaultRootWindow (GDK_DISPLAY ()), &ss_info); + + if (XScreenSaverQueryExtension (dsp, &event_base, &error_base)) + retval = XScreenSaverQueryInfo (dsp, RootWindow(dsp, XDefaultScreen(dsp)), &ss_info); else retval = 0; - gdk_threads_leave (); - + if (retval != 0) { *state = ss_info.state; *kind = ss_info.kind; diff --git a/tools/Config.cs b/tools/Config.cs index 35edba40..08f7b97c 100644 --- a/tools/Config.cs +++ b/tools/Config.cs @@ -34,7 +34,8 @@ using System.Reflection; using Beagle; using Beagle.Util; -using Gtk; +//using Gtk; +using GLib; public static class ConfigTool { @@ -100,8 +101,6 @@ public static class ConfigTool { public static void Main (string [] args) { - Application.InitCheck ("beagle-config", ref args); - if (args.Length == 0) PrintUsageAndExit (); diff --git a/tools/Query.cs b/tools/Query.cs index e51a38ef..df37ff20 100644 --- a/tools/Query.cs +++ b/tools/Query.cs @@ -33,7 +33,7 @@ using System.Threading; using System.Text; using System.Text.RegularExpressions; -using Gtk; +using GLib; using Beagle; using Beagle.Util; @@ -41,21 +41,22 @@ using Beagle.Daemon; class QueryTool { - static int count = 0; - static Query query = null; - static DateTime queryStartTime; - static DateTime lastQueryTime = DateTime.Now; + private static int count = 0; + private static Query query = null; + private static DateTime queryStartTime; + private static DateTime lastQueryTime = DateTime.Now; + private static MainLoop main_loop = null; // CLI args - static bool keep_running = false; - static bool verbose = false; - static bool display_hits = true; - static bool flood = false; - static bool listener = false; - static DateTime start_date = DateTime.MinValue; - static DateTime end_date = DateTime.MinValue; - - static void OnHitsAdded (HitsAddedResponse response) + private static bool keep_running = false; + private static bool verbose = false; + private static bool display_hits = true; + private static bool flood = false; + private static bool listener = false; + private static DateTime start_date = DateTime.MinValue; + private static DateTime end_date = DateTime.MinValue; + + private static void OnHitsAdded (HitsAddedResponse response) { lastQueryTime = DateTime.Now; @@ -97,7 +98,7 @@ class QueryTool { } } - static void OnHitsSubtracted (HitsSubtractedResponse response) + private static void OnHitsSubtracted (HitsSubtractedResponse response) { lastQueryTime = DateTime.Now; @@ -112,7 +113,7 @@ class QueryTool { } } - static void OnFinished (FinishedResponse response) + private static void OnFinished (FinishedResponse response) { if (verbose) { Console.WriteLine ("Elapsed time: {0:0.000}s", @@ -123,7 +124,8 @@ class QueryTool { if (flood) SendQuery (); else - Gtk.Application.Quit (); + main_loop.Quit (); + //Gtk.Application.Quit (); } public static void PrintUsageAndExit () @@ -163,7 +165,7 @@ class QueryTool { System.Environment.Exit (0); } - static void ReadBackendMappings () + private static void ReadBackendMappings () { ArrayList assemblies = ReflectionFu.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder.BackendDir); @@ -203,16 +205,17 @@ class QueryTool { } } - static void OnClosed () + private static void OnClosed () { if (flood) SendQuery (); else - Gtk.Application.Quit (); + main_loop.Quit (); + //Gtk.Application.Quit (); } - static int query_counter = 0; - static void SendQuery () + private static int query_counter = 0; + private static void SendQuery () { ++query_counter; if (flood) { @@ -231,9 +234,9 @@ class QueryTool { } } - static void Main (string[] args) + public static void Main (string[] args) { - Gtk.Application.InitCheck ("beagle-query", ref args); + main_loop = new MainLoop (); if (args.Length == 0 || Array.IndexOf (args, "--help") > -1 || Array.IndexOf (args, "--usage") > -1) PrintUsageAndExit (); @@ -385,7 +388,7 @@ class QueryTool { SendQuery (); - Gtk.Application.Run (); + main_loop.Quit (); } -- 2.11.4.GIT