Author: joergr
Date: 2005-04-12 07:49:10 -0400 (Tue, 12 Apr 2005)
New Revision: 42819

Modified:
   trunk/mcs/tools/mono-service/ChangeLog
   trunk/mcs/tools/mono-service/mono-service.cs
Log:
2005-04-12  Joerg Rosenkranz  <[EMAIL PROTECTED]>

        * mono-service.cs: Service runs in its own AppDomain now.
        Improved exception handling.



Modified: trunk/mcs/tools/mono-service/ChangeLog
===================================================================
--- trunk/mcs/tools/mono-service/ChangeLog      2005-04-12 05:18:54 UTC (rev 
42818)
+++ trunk/mcs/tools/mono-service/ChangeLog      2005-04-12 11:49:10 UTC (rev 
42819)
@@ -1,3 +1,8 @@
+2005-04-12  Joerg Rosenkranz  <[EMAIL PROTECTED]>
+
+       * mono-service.cs: Service runs in its own AppDomain now.
+       Improved exception handling.
+
 2005-04-09  Joerg Rosenkranz  <[EMAIL PROTECTED]>
 
        * mono-service.cs: Fixed dynamic loading of assemblies

Modified: trunk/mcs/tools/mono-service/mono-service.cs
===================================================================
--- trunk/mcs/tools/mono-service/mono-service.cs        2005-04-12 05:18:54 UTC 
(rev 42818)
+++ trunk/mcs/tools/mono-service/mono-service.cs        2005-04-12 11:49:10 UTC 
(rev 42819)
@@ -16,18 +16,18 @@
 using System.Threading;
 using System.Runtime.InteropServices;
 
-class MonoServiceRunner {
-       static string assembly, directory, lockfile, name, logname;
-       static ServiceBase service = null;
-
-       static void info (string format, params object [] args)
+class MonoServiceRunner : MarshalByRefObject
+{
+       string assembly, name, logname;
+       
+       static void info (string prefix, string format, params object [] args)
        {
-               Syscall.syslog (SyslogLevel.LOG_INFO, String.Format ("{0}: 
{1}", assembly, String.Format (format, args)));
+               Syscall.syslog (SyslogLevel.LOG_INFO, String.Format ("{0}: 
{1}", prefix, String.Format (format, args)));
        }
        
-       static void error (string format, params object [] args)
+       static void error (string prefix, string format, params object [] args)
        {
-               Syscall.syslog (SyslogLevel.LOG_ERR, String.Format ("{0}: {1}", 
assembly, String.Format (format, args)));
+               Syscall.syslog (SyslogLevel.LOG_ERR, String.Format ("{0}: {1}", 
prefix, String.Format (format, args)));
        }
        
        static void Usage ()
@@ -40,14 +40,14 @@
 
        delegate void sighandler_t (int arg);
        
-       static AutoResetEvent signal_event;
+       AutoResetEvent signal_event;
 
        [DllImport ("libc")]
        extern static int signal (int signum, sighandler_t handler);
 
-       static int signum;
+       int signum;
        
-       static void my_handler (int sig)
+       void my_handler (int sig)
        {
                signum = sig;
                signal_event.Set ();
@@ -64,6 +64,12 @@
        
        static int Main (string [] args)
        {
+               string assembly = null;
+               string directory = null;
+               string lockfile = null;
+               string name = null;
+               string logname = null;
+
                foreach (string s in args){
                        if (s.Length > 3 && s [0] == '-' && s [2] == ':'){
                                string arg = s.Substring (3);
@@ -83,24 +89,21 @@
                        }
                }
 
+               if (logname == null)
+                       logname = assembly;
+
                if (assembly == null){
-                       error ("Assembly name is missing");
+                       error (logname, "Assembly name is missing");
                        Usage ();
                }
-
-               if (logname == null)
-                       logname = assembly;
                
                if (directory != null){
                        if (Syscall.chdir (directory) != 0){
-                               error ("Could not change to directory {0}", 
directory);
+                               error (logname, "Could not change to directory 
{0}", directory);
                                return 1;
                        }
                }
                
-               // Allow loading of dynamic assemblies
-               AppDomain.CurrentDomain.AppendPrivatePath 
(Environment.CurrentDirectory);
-
                // Use lockfile to allow only one instance
                if (lockfile == null)
                        lockfile = String.Format ("/tmp/{0}.lock", 
Path.GetFileName (assembly));
@@ -109,12 +112,12 @@
                        
FilePermissions.S_IRUSR|FilePermissions.S_IWUSR|FilePermissions.S_IRGRP);
        
                if (lfp<0)  {
-                       error ("Cannot open lock file.");
+                       error (logname, "Cannot open lock file.");
                        return 1;
                }
        
                if (Syscall.lockf(lfp, LockFlags.F_TLOCK,0)<0)  {
-                       info ("Daemon is already running.");
+                       info (logname, "Daemon is already running.");
                        return 0;
                }
                
@@ -124,127 +127,171 @@
                Syscall.write (lfp, buf, (ulong)pid.Length);
                Marshal.FreeCoTaskMem (buf);
 
-               //
-               // Setup signals
-               //
-               signal_event = new AutoResetEvent (false);
-
-               // Invoke all the code used in the signal handler, so the JIT 
does
-               // not kick-in inside the signal handler
-               signal_event.Set ();
-               signal_event.Reset ();
-
-               // Hook up 
-               signal (UnixConvert.FromSignum (Signum.SIGTERM), new 
sighandler_t (my_handler));
-               signal (UnixConvert.FromSignum (Signum.SIGUSR1), new 
sighandler_t (my_handler));
-               signal (UnixConvert.FromSignum (Signum.SIGUSR2), new 
sighandler_t (my_handler));
-
-               // Load service assembly
-               Assembly a = null;
+               // Create new AppDomain to run service
+               AppDomainSetup setup = new AppDomainSetup ();
+               setup.ApplicationBase = Environment.CurrentDirectory;
+               setup.ConfigurationFile = Path.Combine 
(Environment.CurrentDirectory, assembly + ".config");
+               setup.ApplicationName = logname;
                
-               try {
-                       a = Assembly.LoadFrom (assembly);
-               } catch (FileNotFoundException) {
-                       error ("Could not find assembly {0}", assembly);
+               AppDomain newDomain = AppDomain.CreateDomain (logname, 
AppDomain.CurrentDomain.Evidence, setup);
+               MonoServiceRunner rnr = newDomain.CreateInstanceAndUnwrap(
+            typeof (MonoServiceRunner).Assembly.FullName,
+            typeof (MonoServiceRunner).FullName,
+            true,
+            BindingFlags.Default,
+            null,
+            new object [] {assembly, name, logname},
+            null, null, null) as MonoServiceRunner;
+                       
+               if (rnr == null) {
+                       error (logname, "Internal Mono Error: Could not create 
MonoServiceRunner.");
                        return 1;
-               } catch (BadImageFormatException){
-                       error ("File {0} is not a valid assembly", assembly);
-                       return 1;
-               } catch { }
-               
-               if (a == null){
-                       error ("Could not load assembly {0}", assembly);
-                       return 1;
-               }
+               }
 
-               // Hook up RunService callback
-               Type cbType = Type.GetType 
("System.ServiceProcess.ServiceBase+RunServiceCallback, System.ServiceProcess");
-               if (cbType == null){
-                       error ("Internal Mono Error: Could not find 
RunServiceCallback in ServiceBase");
-                       return 1;                       
-               }
-               
-               FieldInfo fi = typeof (ServiceBase).GetField ("RunService", 
BindingFlags.Static | BindingFlags.NonPublic);
-               if (fi == null){
-                       error ("Internal Mono Error: Could not find RunService 
in ServiceBase");
+               return rnr.StartService ();
+       }
+       
+       public MonoServiceRunner (string assembly, string name, string logname)
+       {
+               this.assembly = assembly;
+               this.name = name;
+               this.logname = logname;
+       }
+       
+       public int StartService ()
+       {
+               try     {
+                       //
+                       // Setup signals
+                       //
+                       signal_event = new AutoResetEvent (false);
+       
+                       // Invoke all the code used in the signal handler, so 
the JIT does
+                       // not kick-in inside the signal handler
+                       signal_event.Set ();
+                       signal_event.Reset ();
+       
+                       // Hook up 
+                       signal (UnixConvert.FromSignum (Signum.SIGTERM), new 
sighandler_t (my_handler));
+                       signal (UnixConvert.FromSignum (Signum.SIGUSR1), new 
sighandler_t (my_handler));
+                       signal (UnixConvert.FromSignum (Signum.SIGUSR2), new 
sighandler_t (my_handler));
+       
+                       // Load service assembly
+                       Assembly a = null;
+                       
+                       try {
+                               a = Assembly.LoadFrom (assembly);
+                       } catch (FileNotFoundException) {
+                               error (logname, "Could not find assembly {0}", 
assembly);
+                               return 1;
+                       } catch (BadImageFormatException){
+                               error (logname, "File {0} is not a valid 
assembly", assembly);
+                               return 1;
+                       } catch { }
+                       
+                       if (a == null){
+                               error (logname, "Could not load assembly {0}", 
assembly);
+                               return 1;
+                       }
+       
+                       // Hook up RunService callback
+                       Type cbType = Type.GetType 
("System.ServiceProcess.ServiceBase+RunServiceCallback, System.ServiceProcess");
+                       if (cbType == null){
+                               error (logname, "Internal Mono Error: Could not 
find RunServiceCallback in ServiceBase");
+                               return 1;                       
+                       }
+                       
+                       FieldInfo fi = typeof (ServiceBase).GetField 
("RunService", BindingFlags.Static | BindingFlags.NonPublic);
+                       if (fi == null){
+                               error (logname, "Internal Mono Error: Could not 
find RunService in ServiceBase");
+                               return 1;
+                       }
+                       fi.SetValue (null, Delegate.CreateDelegate(cbType, 
this, "MainLoop"));
+                       
+                       // And run its Main. Our RunService handler is invoked 
from 
+                       // ServiceBase.Run.
+                       MethodInfo entry = a.EntryPoint;
+                       if (entry == null){
+                               error (logname, "Entry point not defined in 
service");
+                               return 1;
+                       }
+       
+                       string [] service_args = new string [0];
+                       entry.Invoke (null, service_args);
+                       
+                       return 0;
+                       
+               } catch ( Exception ex ) {
+                       for (Exception e = ex; e != null; e = e.InnerException)
+                               error (logname, e.Message);
+                       
                        return 1;
                }
-               fi.SetValue (null, Delegate.CreateDelegate(cbType, 
-                       typeof (MonoServiceRunner).GetMethod ("RunService", 
BindingFlags.Static | BindingFlags.NonPublic)));
-               
-               // And run its Main. Our RunService handler is invoked from 
-               // ServiceBase.Run.
-               MethodInfo entry = a.EntryPoint;
-               if (entry == null){
-                       error ("Entry point not defined in service");
-                       return 1;
-               }
-
-               string [] service_args = new string [0];
-               entry.Invoke (null, service_args);
-
-               return 0;
        }
        
        // The main service loop
-       private static void RunService (ServiceBase [] services)
+       private void MainLoop (ServiceBase [] services)
        {
-               if (services == null || services.Length == 0){
-                       error ("No services were registered by this service");
-                       return;
-               }
-               
-               // Start up the service.
-               service = null;
-               
-               if (name != null){
-                       foreach (ServiceBase svc in services){
-                               if (svc.ServiceName == name){
-                                       service = svc;
-                                       break;
+               try {
+                       ServiceBase service;
+       
+                       if (services == null || services.Length == 0){
+                               error (logname, "No services were registered by 
this service");
+                               return;
+                       }
+                       
+                       // Start up the service.
+                       service = null;
+                       
+                       if (name != null){
+                               foreach (ServiceBase svc in services){
+                                       if (svc.ServiceName == name){
+                                               service = svc;
+                                               break;
+                                       }
                                }
+                       } else {
+                               service = services [0];
                        }
-               } else {
-                       service = services [0];
-               }
-
-               call (service, "OnStart", new string [0]);
-               info ("Service {0} started", service.ServiceName);
-
-               for (bool running = true; running; ){
-                       signal_event.WaitOne ();
-                       Signum v;
-                       
-                       if (UnixConvert.TryToSignum (signum, out v)){
-                               signum = 0;
+       
+                       call (service, "OnStart", new string [0]);
+                       info (logname, "Service {0} started", 
service.ServiceName);
+       
+                       for (bool running = true; running; ){
+                               signal_event.WaitOne ();
+                               Signum v;
                                
-                               switch (v){
-                               case Signum.SIGTERM:
-                                       if (service.CanStop) {
-                                               info ("Stopping service {0}", 
service.ServiceName);
-                                               call (service, "OnStop", null);
-                                               running = false;
+                               if (UnixConvert.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;
                                        }
-                                       break;
-                               case Signum.SIGUSR1:
-                                       if (service.CanPauseAndContinue) {
-                                               info ("Pausing service {0}", 
service.ServiceName);
-                                               call (service, "OnPause", null);
-                                       }
-                                       break;
-                               case Signum.SIGUSR2:
-                                       if (service.CanPauseAndContinue) {
-                                               info ("Continuing service {0}", 
service.ServiceName);
-                                               call (service, "OnContinue", 
null);
-                                       }
-                                       break;
                                }
                        }
+               } finally {
+                       // Clean up
+                       foreach (ServiceBase svc in services){
+                               svc.Dispose ();
+                       }
                }
-
-               // Clean up
-               foreach (ServiceBase svc in services){
-                       svc.Dispose ();
-               }
        }
 }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to