Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System / System.Diagnostics / PerformanceCounter.cs
index 2e7f50478d34907184aaca4c86c596e4076a3b54..f76f0950f459bbf951ebbf0ebba82e30b0f097bf 100644 (file)
@@ -3,27 +3,63 @@
 //
 // Authors:
 //   Jonathan Pryor (jonpryor@vt.edu)
+//   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
 //
 // (C) 2002
+// (C) 2003 Andreas Nahr
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
 using System;
 using System.ComponentModel;
+using System.ComponentModel.Design;
 using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
 
 namespace System.Diagnostics {
 
        // must be safe for multithreaded operations
-       public class PerformanceCounter : Component, ISupportInitialize {
+       [InstallerType (typeof (PerformanceCounterInstaller))]
+       public sealed class PerformanceCounter : Component, ISupportInitialize 
+       {
 
                private string categoryName;
                private string counterName;
                private string instanceName;
                private string machineName;
+               IntPtr impl;
+               PerformanceCounterType type;
+               CounterSample old_sample;
                private bool readOnly;
+               bool valid_old;
+               bool changed;
+               bool is_custom;
+               private PerformanceCounterInstanceLifetime lifetime;
 
-               [MonoTODO("Find the actual value")]
-               public static int DefaultFileMappingSize = 0x80000;
+               [Obsolete]
+               public static int DefaultFileMappingSize = 524288;
 
                // set catname, countname, instname to "", machname to "."
                public PerformanceCounter ()
@@ -61,6 +97,12 @@ namespace System.Diagnostics {
                        bool readOnly)
                {
 
+                       if (categoryName == null)
+                               throw new ArgumentNullException ("categoryName");
+                       if (counterName == null)
+                               throw new ArgumentNullException ("counterName");
+                       if (instanceName == null)
+                               throw new ArgumentNullException ("instanceName");
                        CategoryName = categoryName;
                        CounterName = counterName;
 
@@ -71,6 +113,7 @@ namespace System.Diagnostics {
                        this.instanceName = instanceName;
                        this.machineName = ".";
                        this.readOnly = readOnly;
+                       changed = true;
                }
 
                public PerformanceCounter (string categoryName,
@@ -82,135 +125,242 @@ namespace System.Diagnostics {
                        this.machineName = machineName;
                }
 
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               static extern IntPtr GetImpl (string category, string counter,
+                               string instance, string machine, out PerformanceCounterType ctype, out bool custom);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               static extern bool GetSample (IntPtr impl, bool only_value, out CounterSample sample);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               static extern long UpdateValue (IntPtr impl, bool do_incr, long value);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               static extern void FreeData (IntPtr impl);
+
+               /* the perf counter has changed, ensure it's valid and setup it to
+                * be able to collect/update data
+                */
+               void UpdateInfo ()
+               {
+                       // need to free the previous info
+                       if (impl != IntPtr.Zero)
+                               Close ();
+                       impl = GetImpl (categoryName, counterName, instanceName, machineName, out type, out is_custom);
+                       // system counters are always readonly
+                       if (!is_custom)
+                               readOnly = true;
+                       // invalid counter, need to handle out of mem
+
+                       // TODO: reenable this
+                       //if (impl == IntPtr.Zero)
+                       //      throw new InvalidOperationException ();
+                       changed = false;
+               }
+
                // may throw ArgumentNullException
+               [DefaultValue (""), ReadOnly (true), RecommendedAsConfigurable (true)]
+               [TypeConverter ("System.Diagnostics.Design.CategoryValueConverter, " + Consts.AssemblySystem_Design)]
+               [SRDescription ("The category name for this performance counter.")]
                public string CategoryName {
                        get {return categoryName;}
                        set {
                                if (value == null)
                                        throw new ArgumentNullException ("categoryName");
                                categoryName = value;
+                               changed = true;
                        }
                }
 
-//             // may throw InvalidOperationException
-//             [MonoTODO]
-//             public string CounterHelp {
-//                     get {return "";}
-//             }
-//
+               // may throw InvalidOperationException
+               [MonoTODO]
+               [ReadOnly (true), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [MonitoringDescription ("A description describing the counter.")]
+               public string CounterHelp {
+                       get {return "";}
+               }
+
                // may throw ArgumentNullException
-               public string CounterName {
+               [DefaultValue (""), ReadOnly (true), RecommendedAsConfigurable (true)]
+               [TypeConverter ("System.Diagnostics.Design.CounterNameConverter, " + Consts.AssemblySystem_Design)]
+               [SRDescription ("The name of this performance counter.")]
+               public string CounterName 
+                       {
                        get {return counterName;}
                        set {
                                if (value == null)
                                        throw new ArgumentNullException ("counterName");
                                counterName = value;
+                               changed = true;
                        }
                }
 
-//             // may throw InvalidOperationException
-//             [MonoTODO]
-//             public PerformanceCounterType CounterType {
-//                     get {return 0;}
-//             }
-//
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [MonitoringDescription ("The type of the counter.")]
+               public PerformanceCounterType CounterType {
+                       get {
+                               if (changed)
+                                       UpdateInfo ();
+                               return type;
+                       }
+               }
+
+               [MonoTODO]
+               [DefaultValue (PerformanceCounterInstanceLifetime.Global)]
+               public PerformanceCounterInstanceLifetime InstanceLifetime {
+                       get { return lifetime; }
+                       set { lifetime = value; }
+               }
+
+               [DefaultValue (""), ReadOnly (true), RecommendedAsConfigurable (true)]
+               [TypeConverter ("System.Diagnostics.Design.InstanceNameConverter, " + Consts.AssemblySystem_Design)]
+               [SRDescription ("The instance name for this performance counter.")]
                public string InstanceName {
                        get {return instanceName;}
-                       set {instanceName = value;}
+                       set {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               instanceName = value;
+                               changed = true;
+                       }
+               }
+
+               // may throw ArgumentException if machine name format is wrong
+               [MonoTODO("What's the machine name format?")]
+               [DefaultValue ("."), Browsable (false), RecommendedAsConfigurable (true)]
+               [SRDescription ("The machine where this performance counter resides.")]
+               public string MachineName {
+                       get {return machineName;}
+                       set {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               if (value == "" || value == ".") {
+                                       machineName = ".";
+                                       changed = true;
+                                       return;
+                               }
+                               throw new PlatformNotSupportedException ();
+                       }
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [MonitoringDescription ("The raw value of the counter.")]
+               public long RawValue {
+                       get {
+                               CounterSample sample;
+                               if (changed)
+                                       UpdateInfo ();
+                               GetSample (impl, true, out sample);
+                               // should this update old_sample as well?
+                               return sample.RawValue;
+                       }
+                       set {
+                               if (changed)
+                                       UpdateInfo ();
+                               if (readOnly)
+                                       throw new InvalidOperationException ();
+                               UpdateValue (impl, false, value);
+                       }
+               }
+
+               [Browsable (false), DefaultValue (true)]
+               [MonitoringDescription ("The accessability level of the counter.")]
+               public bool ReadOnly {
+                       get {return readOnly;}
+                       set {readOnly = value;}
                }
 
-//             // may throw ArgumentException if machine name format is wrong
-//             [MonoTODO("What's the machine name format?")]
-//             public string MachineName {
-//                     get {return machineName;}
-//                     set {machineName = value;}
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public long RawValue {
-//                     get {return 0;}
-//                     set {
-//                             throw new NotImplementedException ();
-//                     }
-//             }
-//
-//             public bool ReadOnly {
-//                     get {return readOnly;}
-//                     set {readOnly = value;}
-//             }
-//
-               [MonoTODO]
                public void BeginInit ()
                {
-                       throw new NotImplementedException ();
+                       // we likely don't need to do anything significant here
                }
 
-//             [MonoTODO]
-//             public void Close ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             [MonoTODO]
-//             public static void CloseSharedResources ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public long Decrement ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             [MonoTODO]
-//             protected override void Dispose (bool disposing)
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-               [MonoTODO]
                public void EndInit ()
                {
-                       throw new NotImplementedException ();
+                       // we likely don't need to do anything significant here
                }
 
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public long Increment ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public long IncrementBy (long value)
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public CounterSample NextSample ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public float NextValue ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             // may throw InvalidOperationException, Win32Exception
-//             [MonoTODO]
-//             public void RemoveInstance ()
-//             {
-//                     throw new NotImplementedException ();
-//             }
+               public void Close ()
+               {
+                       IntPtr p = impl;
+                       impl = IntPtr.Zero;
+                       if (p != IntPtr.Zero)
+                               FreeData (p);
+               }
+
+               public static void CloseSharedResources ()
+               {
+                       // we likely don't need to do anything significant here
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               public long Decrement ()
+               {
+                       return IncrementBy (-1);
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+                       Close ();
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               public long Increment ()
+               {
+                       return IncrementBy (1);
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public long IncrementBy (long value)
+               {
+                       if (changed)
+                               UpdateInfo ();
+                       if (readOnly) {
+                               // FIXME: This should really throw, but by now set this workaround in place.
+                               //throw new InvalidOperationException ();
+                               return 0;
+                       }
+                       return UpdateValue (impl, true, value);
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               public CounterSample NextSample ()
+               {
+                       CounterSample sample;
+                       if (changed)
+                               UpdateInfo ();
+                       GetSample (impl, false, out sample);
+                       valid_old = true;
+                       old_sample = sample;
+                       return sample;
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               public float NextValue ()
+               {
+                       CounterSample sample;
+                       if (changed)
+                               UpdateInfo ();
+                       GetSample (impl, false, out sample);
+                       float val;
+                       if (valid_old)
+                               val = CounterSampleCalculator.ComputeCounterValue (old_sample, sample);
+                       else
+                               val = CounterSampleCalculator.ComputeCounterValue (sample);
+                       valid_old = true;
+                       old_sample = sample;
+                       return val;
+               }
+
+               // may throw InvalidOperationException, Win32Exception
+               [MonoTODO]
+               [ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public void RemoveInstance ()
+               {
+                       throw new NotImplementedException ();
+               }
        }
 }