* (C) 2005 Novell Inc
*/
using System;
+using System.Collections.Generic;
using System.IO;
using System.Reflection;
+using Mono.Unix;
using Mono.Unix.Native;
using System.ServiceProcess;
using System.Threading;
class MonoServiceRunner : MarshalByRefObject
{
string assembly, name, logname;
+ string[] args;
static void info (string prefix, string format, params object [] args)
{
Environment.Exit (1);
}
- int signum;
-
- void my_handler (int sig)
- {
- signum = sig;
- }
-
static void call (object o, string method, object [] arg)
{
MethodInfo m = o.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
string lockfile = null;
string name = null;
string logname = null;
+ var assebmlyArgs = new List<string>();
foreach (string s in args){
if (s.Length > 3 && s [0] == '-' && s [2] == ':'){
}
} else {
if (assembly != null)
- Usage ();
-
- assembly = s;
+ {
+ assebmlyArgs.Add(s);
+ }
+ else
+ {
+ assembly = s;
+ }
}
}
true,
BindingFlags.Default,
null,
- new object [] {assembly, name, logname},
+ new object [] {assembly, name, logname, assebmlyArgs.ToArray()},
null, null, null) as MonoServiceRunner;
if (rnr == null) {
}
}
- public MonoServiceRunner (string assembly, string name, string logname)
+ public MonoServiceRunner (string assembly, string name, string logname, string[] args)
{
this.assembly = assembly;
this.name = name;
this.logname = logname;
+ this.args = args;
}
public int StartService ()
{
try {
- // Invoke all the code used in the signal handler, so the JIT does
- // not kick-in inside the signal handler
- my_handler (0);
-
- // Hook up
- Stdlib.signal (Signum.SIGTERM, new SignalHandler (my_handler));
- Stdlib.signal (Signum.SIGUSR1, new SignalHandler (my_handler));
- Stdlib.signal (Signum.SIGUSR2, new SignalHandler (my_handler));
-
// Load service assembly
Assembly a = null;
// And run its Main. Our RunService handler is invoked from
// ServiceBase.Run.
- return AppDomain.CurrentDomain.ExecuteAssembly (assembly, AppDomain.CurrentDomain.Evidence);
+ return AppDomain.CurrentDomain.ExecuteAssembly (assembly, AppDomain.CurrentDomain.Evidence, args);
} catch ( Exception ex ) {
for (Exception e = ex; e != null; e = e.InnerException) {
} else {
service = services [0];
}
-
- call (service, "OnStart", new string [0]);
+
+ if (service.ExitCode != 0) {
+ //likely due to a previous execution, so we need to reset it to default
+ service.ExitCode = 0;
+ }
+ call (service, "OnStart", args);
info (logname, "Service {0} started", service.ServiceName);
+ UnixSignal intr = new UnixSignal (Signum.SIGINT);
+ UnixSignal term = new UnixSignal (Signum.SIGTERM);
+ UnixSignal usr1 = new UnixSignal (Signum.SIGUSR1);
+ UnixSignal usr2 = new UnixSignal (Signum.SIGUSR2);
+
+ UnixSignal[] sigs = new UnixSignal[]{
+ intr,
+ term,
+ usr1,
+ usr2
+ };
+
for (bool running = true; running; ){
- // Poll only after 500ms
- Thread.Sleep (500);
-
- Signum v;
-
- if (NativeConvert.TryToSignum (signum, out v)){
- signum = 0;
-
- switch (v){
- case Signum.SIGTERM:
- if (service.CanStop) {
- info (logname, "Stopping service {0}", service.ServiceName);
- call (service, "OnStop", null);
- running = false;
- }
- break;
- case Signum.SIGUSR1:
- if (service.CanPauseAndContinue) {
- info (logname, "Pausing service {0}", service.ServiceName);
- call (service, "OnPause", null);
- }
- break;
- case Signum.SIGUSR2:
- if (service.CanPauseAndContinue) {
- info (logname, "Continuing service {0}", service.ServiceName);
- call (service, "OnContinue", null);
- }
- break;
- }
+ int idx = UnixSignal.WaitAny (sigs);
+ if (idx < 0 || idx >= sigs.Length)
+ continue;
+ if ((intr.IsSet || term.IsSet) && service.CanStop) {
+ intr.Reset ();
+ term.Reset ();
+ info (logname, "Stopping service {0}", service.ServiceName);
+ call (service, "OnStop", null);
+ if (service.ExitCode != 0)
+ error (logname, "Service {0} stopped returning a non-zero ExitCode: {1}",
+ service.ServiceName, service.ExitCode);
+ running = false;
+ }
+ else if (usr1.IsSet && service.CanPauseAndContinue) {
+ usr1.Reset ();
+ info (logname, "Pausing service {0}", service.ServiceName);
+ call (service, "OnPause", null);
+ }
+ else if (usr2.IsSet && service.CanPauseAndContinue) {
+ usr2.Reset ();
+ info (logname, "Continuing service {0}", service.ServiceName);
+ call (service, "OnContinue", null);
}
}
} finally {