]> git.saurik.com Git - wxWidgets.git/commitdiff
Fix spurious errors when writing to the child process stdin under Unix.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 14 Nov 2010 14:04:37 +0000 (14:04 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 14 Nov 2010 14:04:37 +0000 (14:04 +0000)
Since the child pipe was made non-blocking in r65993, it became possible to
write to child process without deadlocking when the pipe became full. However
this still resulted in an error from wxFileOutputStream as it didn't handle
EAGAIN returned from write() any differently than any other error, even though
it is an expected situation in this particular case.

Change Unix wxExecute() to use wxPipeOutputStream which ignores EAGAIN unlike
wxFileOutputStream to fix this.

See #12636.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66152 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/unix/pipe.h
src/unix/utilsunx.cpp

index 82f6506aeb382e48e1de628b8289843f7471753f..d125bb1f5d45cda9a913c02d9b701a20df80aa7e 100644 (file)
@@ -410,6 +410,10 @@ All:
 - Added wxThread::OnKill() and OnDelete() callbacks.
 - Added wxFile::GetLastError() and ClearLastError() (ryazanov).
 
+Unix:
+
+- Fix spurious errors when writing to child process pipe (ryazanov).
+
 All (GUI):
 
 - Added wxRichMessageDialog (Rickard Westerlund, GSoC 2010 project).
index 3581008a6eb41f6c4e6fabea040a097602f53b93..e4799024edb7f4d274c3dd0fa8893a4a6db0acdb 100644 (file)
@@ -118,6 +118,20 @@ public:
     virtual bool CanRead() const;
 };
 
+// ----------------------------------------------------------------------------
+// wxPipeOutputStream: stream for writing to a pipe
+// ----------------------------------------------------------------------------
+
+class wxPipeOutputStream : public wxFileOutputStream
+{
+public:
+    wxPipeOutputStream(int fd) : wxFileOutputStream(fd) { }
+
+    // Override the base class version to ignore "pipe full" errors: this is
+    // not an error for this class.
+    size_t OnSysWrite(const void *buffer, size_t size);
+};
+
 #endif // wxUSE_STREAMS && wxUSE_FILE
 
 #endif // _WX_UNIX_PIPE_H_
index 282f4392585735b35e034374bb16ffcba280b435..a96e20e6392b391d2199c3b555b0ba83104f215e 100644 (file)
@@ -337,6 +337,45 @@ bool wxPipeInputStream::CanRead() const
     }
 }
 
+size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t size)
+{
+    // We need to suppress error logging here, because on writing to a pipe
+    // which is full, wxFile::Write reports a system error. However, this is
+    // not an extraordinary situation, and it should not be reported to the
+    // user (but if really needed, the program can recognize it by checking
+    // whether LastRead() == 0.) Other errors will be reported below.
+    size_t ret;
+    {
+        wxLogNull logNo;
+        ret = m_file->Write(buffer, size);
+    }
+
+    switch ( m_file->GetLastError() )
+    {
+       // pipe is full
+#ifdef EAGAIN
+       case EAGAIN:
+#endif
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+       case EWOULDBLOCK:
+#endif
+           // do not treat it as an error
+           m_file->ClearLastError();
+           // fall through
+
+       // no error
+       case 0:
+           break;
+
+       // some real error
+       default:
+           wxLogSysError(_("Can't write to child process's stdin"));
+           m_lasterror = wxSTREAM_WRITE_ERROR;
+    }
+
+    return ret;
+}
+
 #endif // HAS_PIPE_STREAMS
 
 // ----------------------------------------------------------------------------
@@ -662,10 +701,11 @@ long wxExecute(char **argv, int flags, wxProcess *process,
                 // it might not be the best idea.
                 wxLogSysError(_("Failed to set up non-blocking pipe, "
                                 "the program might hang."));
+                wxLog::FlushActive();
             }
 
             wxOutputStream *inStream =
-                new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
+                new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));
 
             const int fdOut = pipeOut.Detach(wxPipe::Read);
             wxPipeInputStream *outStream = new wxPipeInputStream(fdOut);