Merge pull request #3749 from BrzVlad/fix-mips-fix
[mono.git] / mcs / class / referencesource / System / services / monitoring / system / diagnosticts / Process.cs
index a7be321fd460c351e4d0307019f2bd4ab7000b48..13016654b5ce11c726809607480a982610e976c0 100644 (file)
@@ -4,6 +4,10 @@
 // </copyright>                                                                
 //------------------------------------------------------------------------------
 
+#if MONO
+#undef FEATURE_PAL
+#endif
+
 namespace System.Diagnostics {
     using System.Text;
     using System.Threading;
@@ -41,7 +45,7 @@ namespace System.Diagnostics {
     PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust"),
     HostProtection(SharedState=true, Synchronization=true, ExternalProcessMgmt=true, SelfAffectingProcessMgmt=true)
     ]
-    public class Process : Component {
+    public partial class Process : Component {
         //
         // FIELDS
         //
@@ -52,7 +56,9 @@ namespace System.Diagnostics {
         SafeProcessHandle m_processHandle;
         bool isRemoteMachine;
         string machineName;
+#if !MONO
         ProcessInfo processInfo;
+#endif
         Int32 m_processAccess;
 
 #if !FEATURE_PAL        
@@ -85,12 +91,14 @@ namespace System.Diagnostics {
                
         DateTime exitTime;
         bool haveExitTime;
-        
+
+#if !MONO
         bool responding;
         bool haveResponding;
         
         bool priorityBoostEnabled;
         bool havePriorityBoostEnabled;
+#endif
         
         bool raisedOnExited;
         RegisteredWaitHandle registeredWaitHandle;
@@ -102,7 +110,9 @@ namespace System.Diagnostics {
         OperatingSystem operatingSystem;
         bool disposed;
         
+#if !MONO
         static object s_CreateProcessLock = new object();
+#endif
         
         // This enum defines the operation mode for redirected process stream.
         // We don't support switching between synchronous mode and asynchronous mode.
@@ -116,6 +126,9 @@ namespace System.Diagnostics {
         StreamReadMode outputStreamReadMode;
         StreamReadMode errorStreamReadMode;
         
+#if MONO
+        StreamReadMode inputStreamReadMode;
+#endif
        
         // Support for asynchrously reading streams
         [Browsable(true), MonitoringDescription(SR.ProcessAssociated)]
@@ -130,8 +143,9 @@ namespace System.Diagnostics {
         internal bool pendingOutputRead;
         internal bool pendingErrorRead;
 
-
+#if !MONO
         private static SafeFileHandle InvalidPipeHandle = new SafeFileHandle(IntPtr.Zero, false);
+#endif
 #if DEBUG
         internal static TraceSwitch processTracing = new TraceSwitch("processTracing", "Controls debug output from Process component");
 #else
@@ -157,7 +171,9 @@ namespace System.Diagnostics {
         [ResourceExposure(ResourceScope.Machine)]
         Process(string machineName, bool isRemoteMachine, int processId, ProcessInfo processInfo) : base() {
             Debug.Assert(SyntaxCheck.CheckMachineName(machineName), "The machine name should be valid!");
+#if !MONO
             this.processInfo = processInfo;
+#endif
             this.machineName = machineName;
             this.isRemoteMachine = isRemoteMachine;
             this.processId = processId;
@@ -182,7 +198,7 @@ namespace System.Diagnostics {
             }
         }
 
- #if !FEATURE_PAL
+ #if !FEATURE_PAL && !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets the base priority of
@@ -196,7 +212,7 @@ namespace System.Diagnostics {
                 return processInfo.basePriority;
             }
         }
-#endif // FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
 
         /// <devdoc>
         ///    <para>
@@ -209,6 +225,10 @@ namespace System.Diagnostics {
         public int ExitCode {
             get {
                 EnsureState(State.Exited);
+#if MONO
+                if (exitCode == -1)
+                    throw new InvalidOperationException ("Cannot get the exit code from a non-child process on Unix");
+#endif
                 return exitCode;
             }
           }
@@ -267,6 +287,9 @@ namespace System.Diagnostics {
                                 }
                                 if (signaled) 
                                 {
+                                    /* If it's a non-child process, it's impossible to get its exit code on
+                                     * Unix. We don't throw here, but GetExitCodeProcess (in the io-layer)
+                                     * will set exitCode to -1, and we will throw if we try to call ExitCode */
                                     if (!NativeMethods.GetExitCodeProcess(handle, out exitCode))                               
                                         throw new Win32Exception();
                                 
@@ -356,7 +379,15 @@ namespace System.Diagnostics {
             }
         }
 
-#if !FEATURE_PAL
+        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]  
+        public SafeProcessHandle SafeHandle {
+            get {
+                EnsureState(State.Associated);
+                return OpenProcessHandle(this.m_processAccess);
+            }
+        }
+
+#if !FEATURE_PAL && !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets the number of handles that are associated
@@ -370,7 +401,7 @@ namespace System.Diagnostics {
                 return processInfo.handleCount;
             }
         }
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
 
         /// <devdoc>
         ///    <para>
@@ -402,6 +433,7 @@ namespace System.Diagnostics {
 
  #if !FEATURE_PAL
 
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Returns the window handle of the main window of the associated process.
@@ -494,6 +526,7 @@ namespace System.Diagnostics {
                 }
             }
         }
+#endif
 
         /// <devdoc>
         ///    <para>
@@ -533,6 +566,7 @@ namespace System.Diagnostics {
             }
         }
 
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets
@@ -695,6 +729,7 @@ namespace System.Diagnostics {
                 return processInfo.virtualBytesPeak;
             }
         }
+#endif
 
         private OperatingSystem OperatingSystem {
             get {
@@ -705,6 +740,7 @@ namespace System.Diagnostics {
             }
         }
 
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets or sets a value indicating whether the associated process priority
@@ -748,6 +784,7 @@ namespace System.Diagnostics {
                 }
             }
         }
+#endif
 
         /// <devdoc>
         ///    <para>
@@ -782,11 +819,13 @@ namespace System.Diagnostics {
                     throw new InvalidEnumArgumentException("value", (int)value, typeof(ProcessPriorityClass));
                 }
 
+#if !MONO
                 // BelowNormal and AboveNormal are only available on Win2k and greater.
                 if (((value & (ProcessPriorityClass.BelowNormal | ProcessPriorityClass.AboveNormal)) != 0)   && 
                     (OperatingSystem.Platform != PlatformID.Win32NT || OperatingSystem.Version.Major < 5)) {
                     throw new PlatformNotSupportedException(SR.GetString(SR.PriorityClassNotSupported), null);
                 }                
+#endif // !MONO
                                     
                 SafeProcessHandle handle = null;
 
@@ -804,6 +843,7 @@ namespace System.Diagnostics {
             }
         }
 
+#if !MONO
         /// <devdoc>
         ///     Returns the number of bytes that the associated process has allocated that cannot
         ///     be shared with other processes.
@@ -825,6 +865,7 @@ namespace System.Diagnostics {
                 return processInfo.privateBytes;
             }
         }
+#endif
 
         /// <devdoc>
         ///     Returns the amount of time the process has spent running code inside the operating
@@ -838,6 +879,7 @@ namespace System.Diagnostics {
             }
         }
 
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets
@@ -956,9 +998,11 @@ namespace System.Diagnostics {
                 return processInfo.sessionId;                
             }
         }
+#endif // !MONO
 
 #endif // !FEATURE_PAL
 
+#if MONO_FEATURE_PROCESS_START
         /// <devdoc>
         ///    <para>
         ///       Gets or sets the properties to pass into the <see cref='System.Diagnostics.Process.Start'/> method for the <see cref='System.Diagnostics.Process'/>
@@ -981,6 +1025,7 @@ namespace System.Diagnostics {
                 startInfo = value;
             }
         }
+#endif
 
 #if !FEATURE_PAL        
         /// <devdoc>
@@ -1028,6 +1073,7 @@ namespace System.Diagnostics {
 
 #if !FEATURE_PAL        
         
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Gets the set of threads that are running in the associated
@@ -1052,6 +1098,7 @@ namespace System.Diagnostics {
                 return threads;
             }
         }
+#endif
 
         /// <devdoc>
         ///     Returns the amount of time the associated process has spent utilizing the CPU.
@@ -1078,6 +1125,7 @@ namespace System.Diagnostics {
             }
         }
 
+#if !MONO
         /// <devdoc>
         ///     Returns the amount of virtual memory that the associated process has requested.
         /// </devdoc>
@@ -1089,8 +1137,11 @@ namespace System.Diagnostics {
                 return unchecked((int)processInfo.virtualBytes);
             }
         }
+#endif // !MONO
+
 #endif // !FEATURE_PAL
 
+#if !MONO
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessVirtualMemorySize)]
         [System.Runtime.InteropServices.ComVisible(false)]        
         public long VirtualMemorySize64 {
@@ -1099,6 +1150,7 @@ namespace System.Diagnostics {
                 return processInfo.virtualBytes;
             }
         }
+#endif
 
         /// <devdoc>
         ///    <para>
@@ -1128,7 +1180,7 @@ namespace System.Diagnostics {
             }
         }
 
-
+#if MONO_FEATURE_PROCESS_START
         /// <devdoc>
         ///    <para>[To be supplied.]</para>
         /// </devdoc>
@@ -1139,6 +1191,9 @@ namespace System.Diagnostics {
                     throw new InvalidOperationException(SR.GetString(SR.CantGetStandardIn));
                 }
 
+#if MONO
+                inputStreamReadMode = StreamReadMode.syncMode;
+#endif
                 return standardInput;
             }
         }
@@ -1184,8 +1239,9 @@ namespace System.Diagnostics {
                 return standardError;
             }
         }
+#endif
 
-#if !FEATURE_PAL  
+#if !FEATURE_PAL && !MONO
         /// <devdoc>
         ///     Returns the total amount of physical memory the associated process.
         /// </devdoc>
@@ -1197,8 +1253,9 @@ namespace System.Diagnostics {
                 return unchecked((int)processInfo.workingSet);
             }
         }
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
 
+#if !MONO
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MonitoringDescription(SR.ProcessWorkingSet)]
         [System.Runtime.InteropServices.ComVisible(false)]        
         public long WorkingSet64 {
@@ -1207,6 +1264,7 @@ namespace System.Diagnostics {
                 return processInfo.workingSet;
             }
         }
+#endif
 
         [Category("Behavior"), MonitoringDescription(SR.ProcessExited)]
         public event EventHandler Exited {
@@ -1218,8 +1276,7 @@ namespace System.Diagnostics {
             }
         }
 
-#if !FEATURE_PAL
-    
+#if !FEATURE_PAL && !MONO
         /// <devdoc>
         ///    <para>
         ///       Closes a process that has a user interface by sending a close message
@@ -1236,8 +1293,7 @@ namespace System.Diagnostics {
             NativeMethods.PostMessage(new HandleRef(this, mainWindowHandle), NativeMethods.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
             return true;
         }
-
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
 
         /// <devdoc>
         ///     Release the temporary handle we used to get process information.
@@ -1301,6 +1357,40 @@ namespace System.Diagnostics {
                 machineName = ".";
                 raisedOnExited = false;
 
+#if MONO
+                //Call close on streams if the user never saw them.
+                //A stream in the undefined mode was never fetched by the user.
+                //A stream in the async mode is wrapped on a AsyncStreamReader and we should dispose that instead.
+                //  no way for users to get a hand on a AsyncStreamReader.
+                var tmpIn = standardInput;
+                standardInput = null;
+                if (inputStreamReadMode == StreamReadMode.undefined && tmpIn != null)
+                    tmpIn.Close ();
+
+                var tmpOut = standardOutput;
+                standardOutput = null;
+                if (outputStreamReadMode == StreamReadMode.undefined && tmpOut != null)
+                    tmpOut.Close ();
+
+                tmpOut = standardError;
+                standardError = null;
+                if (errorStreamReadMode == StreamReadMode.undefined && tmpOut != null)
+                    tmpOut.Close ();
+
+                var tmpAsync = output;
+                output = null;
+                if (outputStreamReadMode == StreamReadMode.asyncMode && tmpAsync != null) {
+                    tmpAsync.CancelOperation ();
+                    tmpAsync.Close ();
+                }
+
+                tmpAsync = error;
+                error = null;
+                if (errorStreamReadMode == StreamReadMode.asyncMode && tmpAsync != null) {
+                    tmpAsync.CancelOperation ();
+                    tmpAsync.Close ();
+                }
+#else
                 //Don't call close on the Readers and writers
                 //since they might be referenced by somebody else while the 
                 //process is still alive but this method called.
@@ -1311,6 +1401,7 @@ namespace System.Diagnostics {
                 output = null;
                 error = null;
        
+#endif
 
                 Refresh();
             }
@@ -1324,6 +1415,7 @@ namespace System.Diagnostics {
         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
         void EnsureState(State state) {
 
+#if !MONO
             if ((state & State.IsWin2k) != (State)0) {
 #if !FEATURE_PAL
                 if (OperatingSystem.Platform != PlatformID.Win32NT || OperatingSystem.Version.Major < 5)
@@ -1337,6 +1429,7 @@ namespace System.Diagnostics {
 #endif // !FEATURE_PAL                    
                     throw new PlatformNotSupportedException(SR.GetString(SR.WinNTRequired));
             }
+#endif // !MONO
 
             if ((state & State.Associated) != (State)0)
                 if (!Associated)
@@ -1344,7 +1437,7 @@ namespace System.Diagnostics {
 
             if ((state & State.HaveId) != (State)0) {
                 if (!haveProcessId) {
-#if !FEATURE_PAL                    
+#if !FEATURE_PAL && !MONO
                     if (haveProcessHandle) {
                         SetProcessId(ProcessManager.GetProcessIdFromHandle(m_processHandle));
                      }
@@ -1355,7 +1448,7 @@ namespace System.Diagnostics {
 #else
                     EnsureState(State.Associated);
                     throw new InvalidOperationException(SR.GetString(SR.ProcessIdRequired));
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
                 }
             }
 
@@ -1364,7 +1457,7 @@ namespace System.Diagnostics {
             }
             
             if ((state & State.HaveProcessInfo) != (State)0) {
-#if !FEATURE_PAL                
+#if !FEATURE_PAL && !MONO
                 if (processInfo == null) {
                     if ((state & State.HaveId) == (State)0) EnsureState(State.HaveId);
                     ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(machineName);
@@ -1380,7 +1473,7 @@ namespace System.Diagnostics {
                 }
 #else
                 throw new InvalidOperationException(SR.GetString(SR.NoProcessInfo));
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
             }
 
             if ((state & State.Exited) != (State)0) {
@@ -1447,11 +1540,14 @@ namespace System.Diagnostics {
         }
 
         public static void EnterDebugMode() {
+#if !MONO
             if (ProcessManager.IsNt) {
                 SetPrivilege("SeDebugPrivilege", NativeMethods.SE_PRIVILEGE_ENABLED);
             }
+#endif
         }
 
+#if !MONO
         [ResourceExposure(ResourceScope.None)]
         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
         private static void SetPrivilege(string privilegeName, int attrib) {
@@ -1489,16 +1585,20 @@ namespace System.Diagnostics {
                 SafeNativeMethods.CloseHandle(hToken);
             }
         }
+#endif
 
         /// <devdoc>
         ///    <para>[To be supplied.]</para>
         /// </devdoc>
         public static void LeaveDebugMode() {
+#if !MONO
             if (ProcessManager.IsNt) {
                 SetPrivilege("SeDebugPrivilege", 0);
             }
+#endif
         }     
 
+#if !MONO
         /// <devdoc>
         ///    <para>
         ///       Returns a new <see cref='System.Diagnostics.Process'/> component given a process identifier and
@@ -1605,9 +1705,10 @@ namespace System.Diagnostics {
                 }
                 Debug.Unindent();
             }
-#endif
+#endif // DEBUG
             return processes;
         }
+#endif // !MONO
 
 #endif // !FEATURE_PAL        
 
@@ -1680,7 +1781,7 @@ namespace System.Diagnostics {
             else {
                 EnsureState(State.HaveId | State.IsLocal);
                 SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
-#if !FEATURE_PAL                
+#if !FEATURE_PAL && !MONO
                 handle = ProcessManager.OpenProcess(processId, access, throwIfExited);
 #else
                 IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
@@ -1695,7 +1796,7 @@ namespace System.Diagnostics {
                                                     NativeMethods.DUPLICATE_CLOSE_SOURCE)) {
                     throw new Win32Exception();
                 }
-#endif // !FEATURE_PAL
+#endif // !FEATURE_PAL && !MONO
                 if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) {         
                     if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) {
                         throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
@@ -1736,6 +1837,7 @@ namespace System.Diagnostics {
             return m_processHandle;
         }
 
+#if !MONO
         /// <devdoc>
         ///     Raise the Exited event, but make sure we don't do it more than once.
         /// </devdoc>
@@ -1750,6 +1852,7 @@ namespace System.Diagnostics {
                 }
             }
         }
+#endif
 
         /// <devdoc>
         ///    <para>
@@ -1760,7 +1863,9 @@ namespace System.Diagnostics {
         ///    </para>
         /// </devdoc>
         public void Refresh() {
+#if !MONO
             processInfo = null;
+#endif
 #if !FEATURE_PAL            
             threads = null;
             modules = null;
@@ -1773,8 +1878,10 @@ namespace System.Diagnostics {
             haveProcessorAffinity = false;
             havePriorityClass = false;
             haveExitTime = false;
+#if !MONO
             haveResponding = false;
             havePriorityBoostEnabled = false;
+#endif
         }
 
         /// <devdoc>
@@ -1855,6 +1962,8 @@ namespace System.Diagnostics {
 
 #endif // !FEATURE_PAL
 
+#if MONO_FEATURE_PROCESS_START
+
         /// <devdoc>
         ///    <para>
         ///       Starts a process specified by the <see cref='System.Diagnostics.Process.StartInfo'/> property of this <see cref='System.Diagnostics.Process'/>
@@ -1883,7 +1992,7 @@ namespace System.Diagnostics {
             }
         }
 
-
+#if !MONO
         [ResourceExposure(ResourceScope.Process)]
         [ResourceConsumption(ResourceScope.Process)]
         private static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, NativeMethods.SECURITY_ATTRIBUTES lpPipeAttributes, int nSize) {
@@ -2054,6 +2163,9 @@ namespace System.Diagnostics {
 
 #if !FEATURE_PAL                    
                 if (startInfo.UserName.Length != 0) {                              
+                    if (startInfo.Password != null && startInfo.PasswordInClearText != null)
+                            throw new ArgumentException(SR.GetString(SR.CantSetDuplicatePassword));
+
                     NativeMethods.LogonFlags logonFlags = (NativeMethods.LogonFlags)0;                    
                     if( startInfo.LoadUserProfile) {
                         logonFlags = NativeMethods.LogonFlags.LOGON_WITH_PROFILE;
@@ -2061,10 +2173,12 @@ namespace System.Diagnostics {
 
                     IntPtr password = IntPtr.Zero;
                     try {
-                        if( startInfo.Password == null) {
+                        if( startInfo.Password != null) {
+                            password = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password);
+                        } else if( startInfo.PasswordInClearText != null) {
+                            password = Marshal.StringToCoTaskMemUni(startInfo.PasswordInClearText);
+                        } else {
                             password = Marshal.StringToCoTaskMemUni(String.Empty);
-                            } else {
-                            password = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password);                        
                         }
 
                         RuntimeHelpers.PrepareConstrainedRegions();
@@ -2167,9 +2281,11 @@ namespace System.Diagnostics {
             return ret;
 
         }
+#endif // !MONO
 
 #if !FEATURE_PAL
 
+#if !MONO
         [ResourceExposure(ResourceScope.Machine)]
         [ResourceConsumption(ResourceScope.Machine)]
         private bool StartWithShellExecuteEx(ProcessStartInfo startInfo) {                        
@@ -2275,6 +2391,7 @@ namespace System.Diagnostics {
             
             return false;            
         }
+#endif
 
         [ResourceExposure(ResourceScope.Machine)]
         [ResourceConsumption(ResourceScope.Machine)]
@@ -2348,6 +2465,8 @@ namespace System.Diagnostics {
             return null;
         }
 
+#endif // MONO_FEATURE_PROCESS_START
+
         /// <devdoc>
         ///    <para>
         ///       Stops the
@@ -2520,6 +2639,7 @@ namespace System.Diagnostics {
 
 #endif // !FEATURE_PAL        
 
+#if MONO_FEATURE_PROCESS_START
         // Support for working asynchronously with streams
         /// <devdoc>
         /// <para>
@@ -2654,6 +2774,7 @@ namespace System.Diagnostics {
                 }
             }
         }
+#endif // MONO_FEATURE_PROCESS_START
 
         /// <summary>
         ///     A desired internal state.
@@ -2679,6 +2800,7 @@ namespace System.Diagnostics {
     /// </devdoc>
     /// <internalonly/>
     internal class ProcessInfo {
+#if !MONO
         public ArrayList threadInfoList = new ArrayList();
         public int basePriority;
         public string processName;
@@ -2695,8 +2817,10 @@ namespace System.Diagnostics {
         public long privateBytes;
         public int mainModuleId; // used only for win9x - id is only for use with CreateToolHelp32
         public int sessionId; 
+#endif
     }
 
+#if !MONO
     /// <devdoc>
     ///     This data structure contains information about a thread in a process that
     ///     is collected in bulk by querying the operating system.  The reason to
@@ -2731,6 +2855,7 @@ namespace System.Diagnostics {
         public int sizeOfImage;
         public int Id; // used only on win9x - for matching up with ProcessInfo.mainModuleId
     }
+#endif
 
     internal static class EnvironmentBlock {
         public static byte[] ToByteArray(StringDictionary sd, bool unicode) {
@@ -2823,6 +2948,7 @@ namespace System.Diagnostics {
         }
     }
 
+#if !MONO
     internal class ShellExecuteHelper {
         private NativeMethods.ShellExecuteInfo _executeInfo;
         private int _errorCode;
@@ -2864,4 +2990,5 @@ namespace System.Diagnostics {
             }
         }
     }
+#endif
 }