/// <summary> /// Ensures the monitoring process is restarted if it crashed. /// </summary> /// <param name="parameter">The monitoring process.</param> private static void ExecuteSymmetricWatch(object?parameter) { // Wait a bit to ensure the new process is started. // A proper synchronization would be preferable, but at this point I'm too lazy. Thread.Sleep(1000); Monitoring Monitoring = (Monitoring)parameter !; Debug.Assert(Monitoring.MonitorProcess != null); Debug.Assert(Monitoring.CancelEvent != null); #pragma warning disable CS8604 // Possible null reference argument. ExecuteSymmetricWatch(Monitoring, Monitoring.MonitorProcess, Monitoring.CancelEvent); #pragma warning restore CS8604 // Possible null reference argument. }
/// <summary> /// Installs the monitor. /// </summary> /// <returns>True if successful; False otherwise and <see cref="LastError"/> contains the error.</returns> public bool ZombifyMe() { Monitoring NewMonitoring = new Monitoring() { ClientName = ClientName, Delay = Delay, WatchingMessage = WatchingMessage, RestartMessage = RestartMessage, Flags = Flags, IsSymmetric = IsSymmetric, AliveTimeout = AliveTimeout, MonitorFolder = MonitorFolder }; Debug.Assert(NewMonitoring.CancelEvent == null); bool Result = ZombifyMeInternal(NewMonitoring, out Errors Error); CancelEvent = NewMonitoring.CancelEvent; LastError = Error; return(Result); }
/// <summary> /// Ensures the monitoring process is restarted if it crashed. /// </summary> /// <param name="monitoring">The monitoring information.</param> /// <param name="monitorProcess">The monitoring process.</param> /// <param name="cancelEvent">The cancellation event.</param> private static void ExecuteSymmetricWatch(Monitoring monitoring, Process monitorProcess, EventWaitHandle cancelEvent) { TimeSpan AliveTimeout = monitoring.AliveTimeout; Debug.Assert(AliveTimeout > TimeSpan.Zero); bool IsAlive = true; AliveWatch.Start(); while (IsAlive) { if (AliveWatch.Elapsed >= AliveTimeout) { break; } if (cancelEvent.WaitOne(SharedDefinitions.CheckInterval)) { break; } IsAlive = !monitorProcess.HasExited; if (!IsAlive) { using (monitorProcess) { } // Wait the same delay as if restarting the original process. Thread.Sleep(monitoring.Delay); ZombifyMeInternal(monitoring, out _); } } }
/// <summary> /// Starts a thread to ensure the monitoring process is restarted if it crashed. /// </summary> /// <param name="monitoring">Monitoring parameters.</param> private static void StartSymmetricWatch(Monitoring monitoring) { Thread NewThread = new Thread(ExecuteSymmetricWatch); NewThread.Start(monitoring); }
private static bool ZombifyMeInternal(Monitoring monitoring, out Errors error) { error = Errors.Success; if (!LoadMonitor(monitoring.MonitorFolder, out string MonitorProcessFileName)) { error = Errors.UnableToLoadSource; return(false); } #if NET48 int ProcessId = Process.GetCurrentProcess().Id; #else int ProcessId = Environment.ProcessId; #endif Contracts.Contract.RequireNotNull(Assembly.GetEntryAssembly(), out Assembly EntryAssembly); string ClientExePath = EntryAssembly.Location; string ArgsText = string.Empty; if (monitoring.Flags.HasFlag(Flags.ForwardArguments)) { // Accumulate arguments in a single string. string[] Args = Environment.GetCommandLineArgs(); for (int Index = 1; Index < Args.Length; Index++) { string Arg = Args[Index]; if (ArgsText.Length > 0) { ArgsText += " "; } ArgsText += Arg; } } long DelayTicks = monitoring.Delay.Ticks; monitoring.CancelEvent = new EventWaitHandle(false, EventResetMode.ManualReset, SharedDefinitions.GetCancelEventName(monitoring.ClientName)); // Use this impossible value as a hack to fail the launch. if (monitoring.Delay == TimeSpan.MinValue) { MonitorProcessFileName = string.Empty; } // Start the monitoring process. // Don't dispose of it, it's passed to another thread. Process MonitorProcess = new Process { StartInfo = { FileName = MonitorProcessFileName, Arguments = $"{ProcessId} \"{ClientExePath}\" \"{ArgsText}\" \"{monitoring.ClientName}\" {DelayTicks} \"{monitoring.WatchingMessage}\" \"{monitoring.RestartMessage}\" {(int)monitoring.Flags}", UseShellExecute = false, CreateNoWindow = true, }, }; bool Result; try { Result = MonitorProcess.Start(); } catch { Result = false; } if (!Result) { error = Errors.MonitorNotStarted; monitoring.MonitorProcess = null; } else { monitoring.MonitorProcess = MonitorProcess; if (monitoring.IsSymmetric && monitoring.AliveTimeout > TimeSpan.Zero) { StartSymmetricWatch(monitoring); } } return(Result); }