Merge pull request #3029 from lambdageek/dev/simplify-monoerror-threads
[mono.git] / mcs / tools / mono-service / mono-service.cs
index 41c4931a7558516c43be3f8119d9016e49febc95..87847f849c245cf01076a68486acba9ac99eff09 100644 (file)
@@ -9,8 +9,10 @@
  * (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;
@@ -19,6 +21,7 @@ using System.Runtime.InteropServices;
 class MonoServiceRunner : MarshalByRefObject
 {
        string assembly, name, logname;
+       string[] args;
        
        static void info (string prefix, string format, params object [] args)
        {
@@ -38,13 +41,6 @@ class MonoServiceRunner : MarshalByRefObject
                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);
@@ -61,6 +57,7 @@ class MonoServiceRunner : MarshalByRefObject
                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] == ':'){
@@ -75,9 +72,13 @@ class MonoServiceRunner : MarshalByRefObject
                                }
                        } else {
                                if (assembly != null)
-                                       Usage ();
-                               
-                               assembly = s;
+                               {
+                                       assebmlyArgs.Add(s);
+                               }
+                               else
+                               {
+                                       assembly = s;
+                               }
                        }
                }
 
@@ -137,7 +138,7 @@ class MonoServiceRunner : MarshalByRefObject
                                true,
                                BindingFlags.Default,
                                null,
-                               new object [] {assembly, name, logname},
+                               new object [] {assembly, name, logname, assebmlyArgs.ToArray()},
                                null, null, null) as MonoServiceRunner;
                                
                        if (rnr == null) {
@@ -153,25 +154,17 @@ class MonoServiceRunner : MarshalByRefObject
                }
        }
        
-       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;
                        
@@ -211,7 +204,7 @@ class MonoServiceRunner : MarshalByRefObject
                        
                        // 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) {
@@ -246,40 +239,49 @@ class MonoServiceRunner : MarshalByRefObject
                        } 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 {