In Test/System.Diagnostics:
authorRobert Jordan <robertj@gmx.net>
Tue, 30 Oct 2007 18:35:42 +0000 (18:35 -0000)
committerRobert Jordan <robertj@gmx.net>
Tue, 30 Oct 2007 18:35:42 +0000 (18:35 -0000)
2007-10-30  Robert Jordan  <robertj@gmx.net>

* ProcessTest.cs: Add tests for bug #319829.

In System.Diagnostics:
2007-10-30  Robert Jordan  <robertj@gmx.net>

* Process.cs: Wrap the redirected streams with a stream
that provides real async Begin/Read|Write operations.
Fixes bug #319829.

In System.IO:
2007-10-30  Robert Jordan  <robertj@gmx.net>

* MonoSyncFileStream.cs: Add.

svn path=/trunk/mcs/; revision=88491

mcs/class/System/System.Diagnostics/ChangeLog
mcs/class/System/System.Diagnostics/Process.cs
mcs/class/System/System.IO/ChangeLog
mcs/class/System/System.IO/MonoSyncFileStream.cs [new file with mode: 0644]
mcs/class/System/System.dll.sources
mcs/class/System/Test/System.Diagnostics/ChangeLog
mcs/class/System/Test/System.Diagnostics/ProcessTest.cs

index 458f20cd2e4d2e7c4b009a59560b936e075527b4..8a1feacaba38273796bf93d26757be6a147f2525 100644 (file)
@@ -1,3 +1,9 @@
+2007-10-30  Robert Jordan  <robertj@gmx.net>
+
+       * Process.cs: Wrap the redirected streams with a stream
+       that provides real async Begin/Read|Write operations.
+       Fixes bug #319829.
+
 2007-09-25  Miguel de Icaza  <miguel@novell.com>
 
        * Process.cs: Return an empty collection to prevent crashes;
index c570e93342e224b00dc74d7898ed6c1e7c93a24d..766cd726679912835e60a567f9af091f3fd86dbb 100644 (file)
@@ -1072,7 +1072,7 @@ namespace System.Diagnostics {
                        
                        if (startInfo.RedirectStandardInput == true) {
                                MonoIO.Close (stdin_rd, out error);
-                               process.input_stream = new StreamWriter (new FileStream (stdin_wr, FileAccess.Write, true), Console.Out.Encoding);
+                               process.input_stream = new StreamWriter (new MonoSyncFileStream (stdin_wr, FileAccess.Write, true, 8192), Console.Out.Encoding);
                                process.input_stream.AutoFlush = true;
                        }
 
@@ -1086,12 +1086,12 @@ namespace System.Diagnostics {
 
                        if (startInfo.RedirectStandardOutput == true) {
                                MonoIO.Close (stdout_wr, out error);
-                               process.output_stream = new StreamReader (new FileStream (process.stdout_rd, FileAccess.Read, true), stdoutEncoding);
+                               process.output_stream = new StreamReader (new MonoSyncFileStream (process.stdout_rd, FileAccess.Read, true, 8192), stdoutEncoding);
                        }
 
                        if (startInfo.RedirectStandardError == true) {
                                MonoIO.Close (stderr_wr, out error);
-                               process.error_stream = new StreamReader (new FileStream (process.stderr_rd, FileAccess.Read, true), stderrEncoding);
+                               process.error_stream = new StreamReader (new MonoSyncFileStream (process.stderr_rd, FileAccess.Read, true, 8192), stderrEncoding);
                        }
 
                        process.StartExitCallbackIfNeeded ();
index 1f6a4c91d5dae7e22f6e858c362d852959a66693..27ab41ba06e76c4c4c231254a1fa57ff228dc5da 100644 (file)
@@ -1,3 +1,7 @@
+2007-10-30  Robert Jordan  <robertj@gmx.net>
+
+       * MonoSyncFileStream.cs: Add.
+
 2007-07-19  Juraj Skripsky  <js@hotfeet.ch>
 
        * FileSystemWatcher.ch (RaiseEvent): Invoke delegate directly, we don't
diff --git a/mcs/class/System/System.IO/MonoSyncFileStream.cs b/mcs/class/System/System.IO/MonoSyncFileStream.cs
new file mode 100644 (file)
index 0000000..f6dd076
--- /dev/null
@@ -0,0 +1,119 @@
+// 
+// System.IO.MonoSyncFileStream.cs: Synchronous FileStream with
+//     asynchronous BeginRead/Write methods.
+//
+// Authors:
+//     Robert Jordan (robertj@gmx.net)
+//
+// Copyright (C) 2007 Novell, Inc. (http://www.novell.com)
+//
+
+//
+// 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.Runtime.Remoting.Messaging;
+
+namespace System.IO
+{
+       internal class MonoSyncFileStream : FileStream
+       {
+               public MonoSyncFileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
+                       : base (handle, access, ownsHandle, bufferSize, false)
+               {
+               }
+
+               delegate void WriteDelegate (byte [] buffer, int offset, int count);
+
+               public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
+                                                       AsyncCallback cback, object state)
+               {
+                       if (!CanWrite)
+                               throw new NotSupportedException ("This stream does not support writing");
+
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
+
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
+
+                       WriteDelegate d = new WriteDelegate (this.Write);
+                       return d.BeginInvoke (buffer, offset, count, cback, state);
+               }
+
+               public override void EndWrite (IAsyncResult asyncResult)
+               {
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+
+                       AsyncResult ar = asyncResult as AsyncResult;
+                       if (ar == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       WriteDelegate d = ar.AsyncDelegate as WriteDelegate;
+                       if (d == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       d.EndInvoke (asyncResult);
+               }
+
+               delegate int ReadDelegate (byte [] buffer, int offset, int count);
+
+               public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
+                                                       AsyncCallback cback, object state)
+               {
+                       if (!CanRead)
+                               throw new NotSupportedException ("This stream does not support reading");
+
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
+
+                       if (offset < 0)
+                               throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
+
+                       ReadDelegate d = new ReadDelegate (this.Read);
+                       return d.BeginInvoke (buffer, offset, count, cback, state);
+               }
+
+               public override int EndRead (IAsyncResult asyncResult)
+               {
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+
+                       AsyncResult ar = asyncResult as AsyncResult;
+                       if (ar == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       ReadDelegate d = ar.AsyncDelegate as ReadDelegate;
+                       if (d == null)
+                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+
+                       return d.EndInvoke (asyncResult);
+               }
+
+       }
+}
index 77580c560010f877e72cb97c7d825114c781f9a8..f8f042536a37f54f0799d5d53c13834165b43dba 100644 (file)
@@ -572,6 +572,7 @@ System.IO/IODescriptionAttribute.cs
 System.IO/KeventWatcher.cs
 System.IO/MonoIO.cs
 System.IO/MonoIOError.cs
+System.IO/MonoSyncFileStream.cs
 System.IO/NotifyFilters.cs
 System.IO.Ports/Handshake.cs
 System.IO.Ports/ISerialStream.cs
index 52795e2d401a9b33265d4849d1cbac9b70c098fe..3b9e611b0f8d3dfe479f302df98b829853048947 100644 (file)
@@ -1,3 +1,7 @@
+2007-10-30  Robert Jordan  <robertj@gmx.net>
+
+       * ProcessTest.cs: Add tests for bug #319829.
+
 2007-10-21  Gert Driesen  <drieseng@users.sourceforge.net>
 
        * SwitchesTest.cs: Fixed compiler warning.
index 73a3988b2fd33b53d25c687b9c1163f47e915fe2..37bdc8552e2208c713a9a04ba4db292fa1a61dc8 100644 (file)
@@ -3,12 +3,15 @@
 //
 // Authors:
 //   Gert Driesen (drieseng@users.sourceforge.net)
+//   Robert Jordan <robertj@gmx.net>
 //
 // (C) 2007 Gert Driesen
 // 
 
 using System;
 using System.Diagnostics;
+using System.IO;
+using System.Text;
 
 using NUnit.Framework;
 
@@ -46,5 +49,48 @@ namespace MonoTests.System.Diagnostics
                                Assert.IsNull (ex.InnerException, "#6");
                        }
                }
+
+               [Test]
+               [Category ("NotDotNet")]
+               public void TestRedirectedOutputIsAsync ()
+               {
+                       // Test requires cygwin, so we just bail out for now.
+                       if (Path.DirectorySeparatorChar == '\\')
+                               return;
+                       
+                       // Create a SH script that emits "hello" after it slept for 2 secs.
+                       string script = Path.GetTempFileName ();
+                       TextWriter w = File.CreateText (script);
+                       w.WriteLine ("sleep 2");
+                       w.WriteLine ("echo hello");
+                       w.Close ();
+
+                       Process p = new Process ();
+                       p.StartInfo = new ProcessStartInfo ("/bin/sh", script);
+                       p.StartInfo.RedirectStandardOutput = true;
+                       p.StartInfo.UseShellExecute = false;
+                       p.Start ();
+
+                       Stream stdout = p.StandardOutput.BaseStream;
+
+                       byte [] buffer = new byte [200];
+
+                       // start async Read operation
+                       DateTime start = DateTime.Now;
+                       stdout.BeginRead (buffer, 0, buffer.Length,
+                                         new AsyncCallback (Read), stdout);
+
+                       Assert.IsTrue ((DateTime.Now - start).TotalMilliseconds < 1000, "#01 BeginRead was not async");
+                       p.WaitForExit ();
+                       File.Delete (script);
+
+                       Assert.AreEqual ("hello", Encoding.Default.GetString (buffer, 0, 5), "#02");
+               }
+
+               void Read (IAsyncResult ar)
+               {
+                       Stream stm = (Stream) ar.AsyncState;
+                       stm.EndRead (ar);
+               }
        }
 }