Fix a fd leak in knotes backend (stupid me) and some cleanup in kaddrbook backend.
[beagle.git] / beagled / Shutdown.cs
blobbd82a35574120ae44d079342060549c34b422eb4
1 //
2 // Shutdown.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.Threading;
29 using System.Collections;
30 using Beagle.Util;
32 namespace Beagle.Daemon {
34 public class Shutdown {
36 static public bool Debug = false;
38 static object shutdownLock = new object ();
39 static Hashtable workers = new Hashtable ();
40 static Hashtable workers_names = new Hashtable ();
41 static bool shutdownRequested = false;
43 public delegate void ShutdownHandler ();
44 public static event ShutdownHandler ShutdownEvent;
46 public static bool WorkerStart (object o, string name)
48 lock (shutdownLock) {
49 if (shutdownRequested) {
50 return false;
52 int refcount = 0;
53 if (workers.Contains (o))
54 refcount = (int)workers[o];
55 ++refcount;
56 workers[o] = refcount;
57 workers_names[o] = name;
59 if (Debug)
60 Logger.Log.Debug ("worker added: name={0} refcount={1}", name, refcount);
62 return true;
65 public static bool WorkerStart (object o)
67 return WorkerStart (o, o.ToString ());
70 public static void WorkerFinished (object o)
72 lock (shutdownLock) {
73 if (!workers.Contains (o)) {
74 Logger.Log.Warn ("extra WorkerFinished called for {0}", o);
75 return;
78 int refcount = (int)workers[o];
79 --refcount;
80 if (refcount == 0) {
81 if (Debug)
82 Logger.Log.Debug ("worker removed: name={0}", workers_names[o]);
83 workers.Remove (o);
84 workers_names.Remove (o);
85 } else {
86 if (Debug)
87 Logger.Log.Debug ("worker finished: name={0} refcount={1}", workers_names[o], refcount);
88 workers[o] = refcount;
91 Monitor.Pulse (shutdownLock);
95 static public bool ShutdownRequested {
96 get { return shutdownRequested; }
97 set {
98 lock (shutdownLock)
99 shutdownRequested = value;
103 private static GLib.MainLoop main_loop = null;
105 public static void RegisterMainLoop (GLib.MainLoop loop)
107 main_loop = loop;
110 // Our handler triggers an orderly shutdown when it receives a signal.
111 // However, this can be annoying if the process gets wedged during
112 // shutdown. To deal with that case, we make a note of the time when
113 // the first signal comes in, and we allow signals to unconditionally
114 // kill the process after 5 seconds have passed.
116 static DateTime signal_time = DateTime.MinValue;
118 public static void BeginShutdown ()
120 lock (shutdownLock) {
121 shutdownRequested = true;
124 // FIXME: This whole "unconditional killing after 5 seconds because
125 // beagled can hang while shutting down" thing should not occur. Any such
126 // incident should be immediately investigated and fixed. Hint: Sending
127 // kill -quit `pidof beagled` will probably reveal that beagled got locked
128 // when signal handler was called and some thread was executing some native
129 // method.
130 bool first_signal = false;
131 if (signal_time == DateTime.MinValue) {
132 signal_time = DateTime.Now;
133 first_signal = true;
136 if (! first_signal) {
137 double t = (DateTime.Now - signal_time).TotalSeconds;
138 const double min_t = 5;
140 if (t < min_t) {
141 Logger.Log.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t-t);
142 return;
143 } else {
144 Logger.Log.Debug ("Forcing immediate shutdown.");
145 Environment.Exit (0);
149 if (ShutdownEvent != null) {
150 try {
151 ShutdownEvent ();
152 } catch (Exception ex) {
153 Logger.Log.Warn (ex, "Caught unhandled exception during shutdown event");
157 int count = 0;
159 lock (shutdownLock) {
160 while (workers.Count > 0) {
161 ++count;
162 Logger.Log.Debug ("({0}) Waiting for {1} worker{2}...",
163 count,
164 workers.Count,
165 workers.Count > 1 ? "s" : "");
166 foreach (object o in workers.Keys)
167 Logger.Log.Debug ("waiting for {0}", workers_names[o]);
168 Monitor.Wait (shutdownLock);
172 Logger.Log.Info ("All workers have finished. Exiting main loop.");
173 main_loop.Quit ();