private static void SigTermHandler() { Console.WriteLine("(initializing SIGTERM handler)"); UnixSignal.WaitAny(new[] { new UnixSignal(Signum.SIGTERM) }); TaskTimerFactory.ShutdownAll(); _host.Dispose(); }
//--- Class Methods --- private static int Main(string[] args) { bool useTty = true; TimeSpan time; // process command line arguments XDoc config = new XDoc("config"); for (int i = 0; i < args.Length; i += 2) { string key = args[i].ToLowerInvariant(); string value = ((i + 1) < args.Length) ? args[i + 1] : string.Empty; switch (key) { case "help": PrintUsage(); return(0); case "notty": --i; useTty = false; break; case "capture-stack-trace": --i; DebugUtil.CaptureStackTrace = true; break; case "nolog": --i; // NOTE (steveb): this option used to disable logging, but was removed in favor of using the automatic re-reading of app.config by log4net break; case "settings": case "config": if (!File.Exists(value)) { WriteError(key, "config file not found"); return(1); } config = XDocFactory.LoadFrom(value, MimeType.XML); break; case "script": config.Start("script").Attr("src", value).End(); break; case "ip": case "host": config.Elem("host", value); break; case "http-port": case "path-prefix": case "server-path": case "server-name": case "storage-dir": case "connect-limit": case "apikey": case "guid": config.Elem(key, value); break; case "public-uri": case "root-uri": config.Elem("uri.public", value); break; case "service-dir": config.Elem("storage-dir", value); break; case "collect-interval": int interval; if (!int.TryParse(value, out interval)) { WriteError(key, "invalid collection interval (must be an integer representing seconds)"); return(1); } if (interval > 0) { DebugUtil.SetCollectionInterval(TimeSpan.FromSeconds(interval)); } break; case "auth": config.Elem("authentication-shemes", value); break; default: WriteError(key, "unknown setting"); return(1); } } try { // initialize environment if (config["apikey"].IsEmpty) { string apikey = StringUtil.CreateAlphaNumericKey(32); config.Elem("apikey", apikey); Console.WriteLine("Dream Host APIKEY: {0}", apikey); } Console.WriteLine("-------------------- initializing"); time = DebugUtil.Stopwatch(() => { _host = new DreamHost(config); }); Console.WriteLine("-------------------- initialized {0} secs", time.TotalSeconds); // execute scripts time = DebugUtil.Stopwatch(() => { _host.RunScripts(config, null); }); Console.WriteLine("-------------------- ready {0} secs", time.TotalSeconds); // for UNIX systems, let's also listen to SIGTERM if (SysUtil.IsUnix) { new Thread(SigTermHandler) { IsBackground = true }.Start(); } // check if we can use the console if (useTty) { int debuglevel = 0; // wait for user input then exit while (_host.IsRunning) { Thread.Sleep(250); #region Interactive Key Handler if (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); switch (key.Key) { case ConsoleKey.Q: case ConsoleKey.Escape: case ConsoleKey.Spacebar: Console.WriteLine("Shutting down"); return(0); case ConsoleKey.G: Console.WriteLine("Full garbage collection pass"); System.GC.Collect(); break; case ConsoleKey.C: Console.Clear(); break; case ConsoleKey.D: switch (++debuglevel) { default: debuglevel = 0; Threading.RendezVousEvent.CaptureTaskState = false; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: none"); break; case 1: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: task-state only"); break; case 2: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = true; Console.WriteLine("Debug capture: task-state and stack-trace"); break; } break; case ConsoleKey.I: { Console.WriteLine("--- System Information ---"); // show memory Console.WriteLine("Allocated memory: {0}", GC.GetTotalMemory(false)); // show threads int workerThreads; int completionThreads; int dispatcherThreads; int backgroundThreads; AsyncUtil.GetAvailableThreads(out workerThreads, out completionThreads, out dispatcherThreads, out backgroundThreads); int maxWorkerThreads; int maxCompletionThreads; int maxDispatcherThreads; int maxBackgroundThreads; AsyncUtil.GetMaxThreads(out maxWorkerThreads, out maxCompletionThreads, out maxDispatcherThreads, out maxBackgroundThreads); Console.WriteLine("Thread-pool worker threads available: {0} (max: {1})", workerThreads, maxWorkerThreads); Console.WriteLine("Thread-pool completion threads available: {0} (max: {1})", completionThreads, maxCompletionThreads); Console.WriteLine("Dispatcher threads available: {0} (max: {1})", dispatcherThreads, maxDispatcherThreads); Console.WriteLine("Thread-pool background worker threads available: {0} (max: {1})", backgroundThreads, maxBackgroundThreads); // show pending/waiting timers var taskTimerStats = Tasking.TaskTimerFactory.GetStatistics(); Console.WriteLine("Pending timer objects: {0}", taskTimerStats.PendingTimers); Console.WriteLine("Queued timer objects: {0}", taskTimerStats.QueuedTimers); Console.WriteLine("Timer retries: {0}", taskTimerStats.Retries); // show activities var activities = _host.ActivityMessages; Console.WriteLine("Host activities: {0}", activities.Length); foreach (var activity in activities) { Console.WriteLine("* {0}: {1}", activity.Created.ToString(XDoc.RFC_DATETIME_FORMAT), activity.Description); } // show pending tasks Console.WriteLine("Pending rendez-vous events: {0}", Threading.RendezVousEvent.PendingCounter); Console.WriteLine("Pending results: {0}", AResult.PendingCounter); lock (Threading.RendezVousEvent.Pending) { int count = 0; foreach (var entry in Threading.RendezVousEvent.Pending.Values) { ++count; if (entry.Key != null) { var context = entry.Key.GetState <DreamContext>(); if (context != null) { Console.WriteLine("--- DreamContext for pending rendez-vous event #{0} ---", count); Console.WriteLine(context.Uri.ToString(false)); } } Console.WriteLine(); if (entry.Value != null) { Console.WriteLine("--- Stack trace for pending rendez-vous event #{0} ---", count); Console.WriteLine(entry.Value.ToString()); } } } Console.WriteLine("--------------------------"); } break; case ConsoleKey.H: Console.WriteLine("Help:"); Console.WriteLine(" Q - quit application"); Console.WriteLine(" ESC - quit application"); Console.WriteLine(" SPACE - quit application"); Console.WriteLine(" G - full garbage collection"); Console.WriteLine(" C - clear screen"); Console.WriteLine(" D - set debug capture level"); Console.WriteLine(" I - show system information (memory, threads, pending tasks)"); Console.WriteLine(" H - this help text"); break; } } #endregion } } else { _host.WaitUntilShutdown(); } } finally { Console.WriteLine("-------------------- shutting down"); TaskTimerFactory.ShutdownAll(); if (_host != null) { _host.Dispose(); } } return(0); }