예제 #1
0
        internal static string FormatArguments(int parentPid, PostMortemSettings postMortemSettings)
        {
            var builder = new StringBuilder();

            builder.Append(parentPid);
            if (postMortemSettings != null)
            {
                builder.Append(" ");
                builder.Append(postMortemSettings.CollectMinidumps);
                builder.Append(" ");
                builder.Append(postMortemSettings.SuppressErrorWindows);
                builder.Append(" ");
                builder.Append(postMortemSettings.HandleAccessViolations);
                builder.Append(" ");
                builder.Append(postMortemSettings.HandleCrtAsserts);
                builder.Append(" ");
                builder.Append(postMortemSettings.HandleCrtPureVirtualFunctionCalls);
                builder.Append(" ");
                builder.Append(((int)postMortemSettings.RuntimeVersions).ToString(CultureInfo.InvariantCulture));
                builder.Append(" ");
                builder.Append(postMortemSettings.NumMinidumpsRetained);
                builder.Append(" ");
                builder.Append(postMortemSettings.MinidumpFolder ?? Path.GetTempPath());
                builder.Append(" ");
                builder.Append(postMortemSettings.MinidumpName ?? "<Unused>");
            }
            return(builder.ToString());
        }
예제 #2
0
        /// <summary>
        ///     Initializes a new instance of this ProcessWatchdog with the specified options.
        ///     The given host process will only be started once <see cref="Start()" /> is called.
        /// </summary>
        /// <param name="process"></param>
        /// <param name="options"></param>
        /// <param name="postMortemSettings">The settings for the post mortem debugger of the host process, if none are specified then no post mortem debugging is performed</param>
        /// <param name="processReadyTimeout">The amount of time the host process has to report being ready before it is assumed to be dead</param>
        /// <exception cref="ArgumentNullException">
        ///     When <paramref name="process" /> is null
        /// </exception>
        /// <exception cref="ArgumentException">
        ///     When <paramref name="process" /> is contains only whitespace
        /// </exception>
        public ProcessWatchdog(
            string process         = SharpRemoteHost,
            ProcessOptions options = ProcessOptions.HideConsole,
            PostMortemSettings postMortemSettings = null,
            TimeSpan?processReadyTimeout          = null
            )
        {
            if (process == null)
            {
                throw new ArgumentNullException(nameof(process));
            }
            if (string.IsNullOrWhiteSpace(process))
            {
                throw new ArgumentException("process");
            }
            if (postMortemSettings != null && !postMortemSettings.IsValid)
            {
                throw new ArgumentException("postMortemSettings");
            }

            if (postMortemSettings != null)
            {
                _postMortemSettings = postMortemSettings.Clone();
                if (_postMortemSettings.MinidumpFolder != null)
                {
                    _postMortemSettings.MinidumpFolder = _postMortemSettings.MinidumpFolder.Replace('/', '\\');
                    if (!_postMortemSettings.MinidumpFolder.EndsWith("\\"))
                    {
                        _postMortemSettings.MinidumpFolder += '\\';
                    }
                }
            }

            _processReadyTimeout = processReadyTimeout ?? new FailureSettings().ProcessReadyTimeout;
            _waitHandle          = new ManualResetEvent(false);
            _hostedProcessState  = HostState.BootPending;
            _syncRoot            = new object();

            _parentPid = Process.GetCurrentProcess().Id;
            _startInfo = new ProcessStartInfo(process)
            {
                Arguments = FormatArguments(_parentPid, _postMortemSettings),
                RedirectStandardOutput = true,
                UseShellExecute        = false
            };
            switch (options)
            {
            case ProcessOptions.HideConsole:
                _startInfo.CreateNoWindow = true;
                break;

            case ProcessOptions.ShowConsole:
                _startInfo.CreateNoWindow = false;
                break;
            }


            _hasProcessExited = true;
        }
예제 #3
0
        /// <summary>
        ///     Initializes a new silo server.
        /// </summary>
        /// <param name="args">The command line arguments given to the Main() method</param>
        /// <param name="customTypeResolver">The type resolver, if any, responsible for resolving Type objects by their assembly qualified name</param>
        /// <param name="codeGenerator">The code generator to create proxy and servant types</param>
        /// <param name="postMortemSettings">
        ///     Settings to control how and if minidumps are collected - when set to null, default values are used (
        ///     <see
        ///         cref="PostMortemSettings" />
        ///     )
        /// </param>
        /// <param name="heartbeatSettings">The settings for heartbeat mechanism, if none are specified, then default settings are used</param>
        /// <param name="latencySettings">The settings for latency measurements, if none are specified, then default settings are used</param>
        /// <param name="endPointSettings">The settings for the endpoint itself (max. number of concurrent calls, etc...)</param>
        /// <param name="endPointName">The name of this silo, used for debugging (and logging)</param>
        public OutOfProcessSiloServer(string[] args,
                                      ITypeResolver customTypeResolver      = null,
                                      ICodeGenerator codeGenerator          = null,
                                      PostMortemSettings postMortemSettings = null,
                                      HeartbeatSettings heartbeatSettings   = null,
                                      LatencySettings latencySettings       = null,
                                      EndPointSettings endPointSettings     = null,
                                      string endPointName = null)
        {
            if (postMortemSettings != null && !postMortemSettings.IsValid)
            {
                throw new ArgumentException("postMortemSettings");
            }

            Log.InfoFormat("Silo Server starting, args ({0}): \"{1}\", {2} custom type resolver",
                           args.Length,
                           string.Join(" ", args),
                           customTypeResolver != null ? "with" : "without"
                           );

            int pid;

            if (args.Length >= 1 && int.TryParse(args[0], out pid))
            {
                _parentProcessId = pid;
                _parentProcess   = Process.GetProcessById(pid);
                _parentProcess.EnableRaisingEvents = true;
                _parentProcess.Exited += ParentProcessOnExited;
            }

            if (Log.IsDebugEnabled)
            {
                Log.DebugFormat("Args.Length: {0}", args.Length);
            }

            if (args.Length >= 10)
            {
                if (postMortemSettings != null)
                {
                    Log.Info("Ignoring post-mortem settings specified from the command-line");
                }
                else
                {
                    var settings = new PostMortemSettings();
                    bool.TryParse(args[1], out settings.CollectMinidumps);
                    bool.TryParse(args[2], out settings.SuppressErrorWindows);
                    bool.TryParse(args[3], out settings.HandleAccessViolations);
                    bool.TryParse(args[4], out settings.HandleCrtAsserts);
                    bool.TryParse(args[5], out settings.HandleCrtPureVirtualFunctionCalls);
                    int tmp;
                    int.TryParse(args[6], out tmp);
                    settings.RuntimeVersions = (CRuntimeVersions)tmp;
                    int.TryParse(args[7], out settings.NumMinidumpsRetained);
                    settings.MinidumpFolder = args[8];
                    settings.MinidumpName   = args[9];

                    if (!settings.IsValid)
                    {
                        Log.ErrorFormat("Received invalid post-mortem debugger settings: {0}", settings);
                    }
                    else
                    {
                        postMortemSettings = settings;
                    }
                }
            }

            _registry           = new DefaultImplementationRegistry();
            _waitHandle         = new ManualResetEvent(false);
            _customTypeResolver = customTypeResolver;

            _postMortemSettings = postMortemSettings;
            if (_postMortemSettings != null)
            {
                Log.InfoFormat("Using post-mortem debugger: {0}", _postMortemSettings);

                if (!NativeMethods.LoadPostmortemDebugger())
                {
                    int err = Marshal.GetLastWin32Error();
                    Log.ErrorFormat("Unable to load the post-mortem debugger dll: {0}",
                                    err);
                }

                if (_postMortemSettings.CollectMinidumps)
                {
                    if (NativeMethods.InitDumpCollection(_postMortemSettings.NumMinidumpsRetained,
                                                         _postMortemSettings.MinidumpFolder,
                                                         _postMortemSettings.MinidumpName))
                    {
                        Log.InfoFormat("Installed post-mortem debugger; up to {0} mini dumps will automatically be saved to: {1}",
                                       _postMortemSettings.NumMinidumpsRetained,
                                       _postMortemSettings.MinidumpFolder
                                       );
                    }
                }

                NativeMethods.InstallPostmortemDebugger(_postMortemSettings.HandleAccessViolations,
                                                        _postMortemSettings.SuppressErrorWindows,
                                                        _postMortemSettings.HandleCrtAsserts,
                                                        _postMortemSettings.HandleCrtPureVirtualFunctionCalls,
                                                        _postMortemSettings.RuntimeVersions);
            }

            _endPoint = new SocketEndPoint(EndPointType.Server,
                                           endPointName,
                                           codeGenerator: codeGenerator,
                                           heartbeatSettings: heartbeatSettings,
                                           latencySettings: latencySettings,
                                           endPointSettings: endPointSettings
                                           );

            _endPoint.OnConnected    += EndPointOnOnConnected;
            _endPoint.OnDisconnected += EndPointOnOnDisconnected;
            _endPoint.OnFailure      += EndPointOnOnFailure;
        }
예제 #4
0
        /// <summary>
        ///     Initializes a new instance of this silo with the specified options.
        ///     The given host process will only be started once <see cref="Start" /> is called.
        /// </summary>
        /// <param name="process"></param>
        /// <param name="options"></param>
        /// <param name="codeGenerator">The code generator to create proxy and servant types</param>
        /// <param name="latencySettings">
        ///     The settings for latency measurements, if none are specified, then default settings are
        ///     used
        /// </param>
        /// <param name="postMortemSettings">
        ///     The settings for the post mortem debugger of the host process, if none are specified
        ///     then no post mortem debugging is performed
        /// </param>
        /// <param name="endPointSettings">The settings for the endpoint itself (max. number of concurrent calls, etc...)</param>
        /// <param name="failureSettings">
        ///     The settings specifying when a failure is assumed to have occured in the host process -
        ///     if none are specified, then defaults are used
        /// </param>
        /// <param name="failureHandler">
        ///     The object responsible for deciding how failures are dealt with - if none is specified
        ///     then a new <see cref="ZeroFailureToleranceStrategy" /> is used
        /// </param>
        /// <param name="endPointName">The name of the endpoint - used in log messages to differentiate between different endpoints</param>
        /// <exception cref="ArgumentNullException">When <paramref name="process" /> is null</exception>
        /// <exception cref="ArgumentException">When <paramref name="process" /> is contains only whitespace</exception>
        public OutOfProcessSilo(
            string process                        = ProcessWatchdog.SharpRemoteHost,
            ProcessOptions options                = ProcessOptions.HideConsole,
            ICodeGenerator codeGenerator          = null,
            LatencySettings latencySettings       = null,
            PostMortemSettings postMortemSettings = null,
            EndPointSettings endPointSettings     = null,
            FailureSettings failureSettings       = null,
            IFailureHandler failureHandler        = null,
            string endPointName                   = null
            )
        {
            if (process == null)
            {
                throw new ArgumentNullException(nameof(process));
            }
            if (string.IsNullOrWhiteSpace(process))
            {
                throw new ArgumentException("process");
            }
            if (postMortemSettings != null && !postMortemSettings.IsValid)
            {
                throw new ArgumentException("postMortemSettings");
            }
            if (failureSettings != null)
            {
                if (failureSettings.ProcessReadyTimeout <= TimeSpan.Zero)
                {
                    throw new ArgumentOutOfRangeException(nameof(failureSettings), "ProcessReadyTimeout should be greater than zero");
                }

                if (failureSettings.EndPointConnectTimeout <= TimeSpan.Zero)
                {
                    throw new ArgumentOutOfRangeException(nameof(failureSettings),
                                                          "EndPointConnectTimeout should be greater than zero");
                }
            }

            failureSettings = failureSettings ?? new FailureSettings();
            failureHandler  = failureHandler ?? new ZeroFailureToleranceStrategy();

            _endPoint = new SocketEndPoint(EndPointType.Client,
                                           endPointName,
                                           codeGenerator: codeGenerator,
                                           heartbeatSettings: failureSettings.HeartbeatSettings,
                                           latencySettings: latencySettings,
                                           endPointSettings: endPointSettings);

            _subjectHost = _endPoint.CreateProxy <ISubjectHost>(Constants.SubjectHostId);

            _syncRoot = new object();

            _process = new ProcessWatchdog(
                process,
                options,
                postMortemSettings
                );

            _process.OnHostOutputWritten += EmitHostOutputWritten;

            _queue = new OutOfProcessQueue(
                _process,
                _endPoint,
                failureHandler,
                failureSettings
                );
            _queue.OnHostStarted += QueueOnOnHostStarted;
        }