4 // Copyright (C) 2004 Novell, Inc.
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.
28 using System
.Threading
;
29 using System
.Collections
;
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
)
49 if (shutdownRequested
) {
53 if (workers
.Contains (o
))
54 refcount
= (int)workers
[o
];
56 workers
[o
] = refcount
;
57 workers_names
[o
] = name
;
60 Logger
.Log
.Debug ("worker added: name={0} refcount={1}", name
, refcount
);
65 public static bool WorkerStart (object o
)
67 return WorkerStart (o
, o
.ToString ());
70 public static void WorkerFinished (object o
)
73 if (!workers
.Contains (o
)) {
74 Logger
.Log
.Warn ("extra WorkerFinished called for {0}", o
);
78 int refcount
= (int)workers
[o
];
82 Logger
.Log
.Debug ("worker removed: name={0}", workers_names
[o
]);
84 workers_names
.Remove (o
);
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; }
99 shutdownRequested
= value;
103 private static GLib
.MainLoop main_loop
= null;
105 public static void RegisterMainLoop (GLib
.MainLoop 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
130 bool first_signal
= false;
131 if (signal_time
== DateTime
.MinValue
) {
132 signal_time
= DateTime
.Now
;
136 if (! first_signal
) {
137 double t
= (DateTime
.Now
- signal_time
).TotalSeconds
;
138 const double min_t
= 5;
141 Logger
.Log
.Debug ("Signals can force an immediate shutdown in {0:0.00}s", min_t
-t
);
144 Logger
.Log
.Debug ("Forcing immediate shutdown.");
145 Environment
.Exit (0);
149 if (ShutdownEvent
!= null) {
152 } catch (Exception ex
) {
153 Logger
.Log
.Warn (ex
, "Caught unhandled exception during shutdown event");
159 lock (shutdownLock
) {
160 while (workers
.Count
> 0) {
162 Logger
.Log
.Debug ("({0}) Waiting for {1} worker{2}...",
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.");