//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: TaskList.cs // // Note: Simple Windows XP-like TaskList program. // using System; using System.Collections; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Diagnostics.Contracts; using Microsoft.Singularity.Configuration; using Microsoft.Singularity.Io; using Microsoft.Singularity.Directory; using Microsoft.Singularity.V1.Services; using Microsoft.SingSharp; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.Singularity.Applications { [ConsoleCategory(HelpMessage="Tasklist [options] Displays XP-like task information", DefaultAction=true)] internal sealed class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [Endpoint] public readonly TRef processRef; [Endpoint] public readonly TRef memoryRef; [Endpoint] public readonly TRef channelRef; [BoolParameter( "d", Default=false , HelpMessage="Dumps output and PageTable to Debugger.")] internal bool dumpTable; [BoolParameter( "c", Default=false , HelpMessage="Displays channels per process.")] internal bool displayChannels; [BoolParameter( "t", Default=false , HelpMessage="Displays ThreadIds per process.")] internal bool displayThreads; [LongParameter( "r", Default=-1, HelpMessage="Repeat every seconds")] internal long pauseSeconds; reflective internal Parameters(); internal int AppMain() { return TaskList.AppMain(this); } } public class TaskList { public class ProcessData { public int id; public string name; public long memBytes; public long peakMemBytes; public long commMemBlocks; public long commMemBytes; public long handlePages; public int[] tids; public ProcessData() { tids = null; } } public class ChannelData { public int ChannelId; public int ImpProcessId; public int ExpProcessId; public int MessagesDeliveredToImp; public int MessagesDeliveredToExp; } public static int []! GetProcessIDs(ProcessContract.Imp:ReadyState! imp) { int [] ids = null; int[]! in ExHeap xids; imp.SendGetProcessIDs(); imp.RecvProcessIDs(out xids); // REVIEW: The kernel process is being returned twice so we're // skipping one of the entries if the process ID matches. int startIndex = 0; if (xids[0] == xids[1]) startIndex++; ids = new int[xids.Length - startIndex]; for (int i = startIndex; i < xids.Length; i++) { ids[i - startIndex] = xids[i]; } delete xids; return ids; } public static int [] GetProcessThreadIDs(ProcessContract.Imp:ReadyState! imp, int procID) { imp.SendGetProcessThreadIDs(procID); int [] retVal = null; switch receive { case imp.NotFound() : break; case imp.ProcessThreadIDs(int[]! in ExHeap tids) : retVal = new int[tids.Length]; for (int i=0; i= 4) { try { value = UInt32.Parse(arg.Substring(3)); return true; } catch (FormatException) {} catch (OverflowException) {} } Console.WriteLine("Could not parse {0}", name); value = 0; return false; } /// /// Use this method to write output to both the screen and the debugger if toDebugger is true. /// public static void WriteLine(bool toDebugger, string format, params object[] args) { string s = String.Format(format, args); Console.WriteLine(s); if (toDebugger) { DebugStub.WriteLine(s); } } public static void WriteLine(bool toDebugger) { Console.WriteLine(); if (toDebugger) { DebugStub.WriteLine(); } } internal static int AppMain(Parameters! config) { ProcessData [] processData; ChannelData [] channelData; // Set the default options bool displayChannels = config.displayChannels; bool displayThreads = config.displayThreads; bool dumpTable = config.dumpTable; int pauseSeconds = (int) config.pauseSeconds; ProcessContract.Imp imp1 = config.processRef.Acquire(); imp1.RecvReady(); config.processRef.Release(imp1); MemoryContract.Imp imp2 = config.memoryRef.Acquire(); imp2.RecvReady(); config.memoryRef.Release(imp2); ChannelContract.Imp imp3 = config.channelRef.Acquire(); imp3.RecvReady(); config.channelRef.Release(imp3); do { // Retrieve the process and channel data try { processData = GetProcessData(config); } catch (Exception ex) { Console.WriteLine("Error retrieving process data."); Console.WriteLine(ex.ToString()); return 1; } try { channelData = GetChannelData(processData,config); } catch (Exception ex) { Console.WriteLine("Error retrieving channel data."); Console.WriteLine(ex.ToString()); return 1; } // Prep for display Hashtable processName = new Hashtable(processData.Length); for (int i = 0; i < processData.Length; i++) { ProcessData pd = processData[i]; if (pd == null) continue; processName.Add(pd.id, pd.name); } // Display the results Console.WriteLine(); WriteLine(dumpTable, "PID Task Name Mem Usage Peak Mem Shared Mem Chan Imp Exp HP "); WriteLine(dumpTable, "=== =================== ========= ======== ========== ======== === ==="); for (int i = 0; i < processData.Length; i++) { ProcessData pd = processData[i]; if (pd == null) continue; ArrayList importedChannels = GetImportedChannels(channelData, pd.id); ArrayList exportedChannels = GetExportedChannels(channelData, pd.id); WriteLine(dumpTable, "{0,3} {1,-19} {2,7} K {3,6} K {4,8} K {5,8} {6,3} {7,3}", pd.id, pd.name, pd.memBytes / 1024, pd.peakMemBytes / 1024, pd.commMemBytes / 1024, importedChannels.Count, exportedChannels.Count, pd.handlePages); if (displayThreads) { if (pd.tids != null && pd.tids.Length > 0) { for (int j = 0; j < pd.tids.Length; j++) { WriteLine(dumpTable, " tid -> {0}",pd.tids[j]); } } } if (displayChannels) { // First display the imports for (int j = 0; j < importedChannels.Count; j++) { ChannelData data = (ChannelData!) importedChannels[j]; WriteLine(dumpTable, " -> {0} (cid={1}, msgs={2})", processName[data.ExpProcessId], data.ChannelId, data.MessagesDeliveredToImp); } // Then display the exports for (int j = 0; j < exportedChannels.Count; j++) { ChannelData data = (ChannelData!) exportedChannels[j]; WriteLine(dumpTable, " <- {0} (cid={1}, msgs={2})", processName[data.ImpProcessId], data.ChannelId, data.MessagesDeliveredToExp); } } } if (dumpTable) { AppRuntime.DumpPageTable(); } if (pauseSeconds > 0) { Thread.Sleep(1000 * (int)pauseSeconds); } } while (pauseSeconds >= 0); return 0; } } }