ncbi_pipe.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:44k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_pipe.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 18:45:13  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.37
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_pipe.cpp,v 1000.4 2004/06/01 18:45:13 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Anton Lavrentiev, Mike DiCuccio, Vladimir Ivanov
  35.  *
  36.  *
  37.  */
  38. #include <ncbi_pch.hpp>
  39. #include <connect/ncbi_pipe.hpp>
  40. #include <corelib/ncbi_system.hpp>
  41. #include <memory>
  42. #include <stdio.h>
  43. #ifdef NCBI_OS_MSWIN
  44. #  include <windows.h>
  45. #elif defined NCBI_OS_UNIX
  46. #  include <unistd.h>
  47. #  include <errno.h>
  48. #  include <sys/time.h>
  49. #  include <sys/types.h>
  50. #  include <sys/wait.h>
  51. #  include <signal.h>
  52. #  include <fcntl.h>
  53. #  ifdef NCBI_COMPILER_MW_MSL
  54. #    include <ncbi_mslextras.h>
  55. #  endif
  56. #else
  57. #  error "Class CPipe is supported only on Windows and Unix"
  58. #endif
  59. BEGIN_NCBI_SCOPE
  60. // Sleep time for timeouts
  61. const unsigned int kSleepTime = 100;
  62. //////////////////////////////////////////////////////////////////////////////
  63. //
  64. // Auxiliary functions
  65. //
  66. #define IS_SET(flags, mask) (((flags) & (mask)) == (mask))
  67. static STimeout* s_SetTimeout(const STimeout* from, STimeout* to)
  68. {
  69.     if ( !from ) {
  70.         return const_cast<STimeout*>(kInfiniteTimeout);
  71.     }
  72.     to->sec  = from->usec / 1000000 + from->sec;
  73.     to->usec = from->usec % 1000000;
  74.     return to;
  75. }
  76. static string s_FormatErrorMessage(const string& where, const string& what)
  77. {
  78.     return "[CPipe::" + where + "]  " + what + ".";
  79. }
  80. //////////////////////////////////////////////////////////////////////////////
  81. //
  82. // Class CNamedPipeHandle handles forwarded requests from CPipe.
  83. // This class is reimplemented in a platform-specific fashion where needed.
  84. //
  85. #if defined(NCBI_OS_MSWIN)
  86. //////////////////////////////////////////////////////////////////////////////
  87. //
  88. // CPipeHandle -- MS Windows version
  89. //
  90. class CPipeHandle
  91. {
  92. public:
  93.     CPipeHandle();
  94.     ~CPipeHandle();
  95.     EIO_Status Open(const string& cmd, const vector<string>& args,
  96.                     CPipe::TCreateFlags create_flags);
  97.     EIO_Status Close(int* exitcode, const STimeout* timeout);
  98.     EIO_Status CloseHandle (CPipe::EChildIOHandle handle);
  99.     EIO_Status Read(void* buf, size_t count, size_t* n_read,
  100.                     const CPipe::EChildIOHandle from_handle,
  101.                     const STimeout* timeout);
  102.     EIO_Status Write(const void* buf, size_t count, size_t* written,
  103.                      const STimeout* timeout);
  104.     TProcessHandle GetProcessHandle(void) const { return m_ProcHandle; };
  105. private:
  106.     // Clear object state.
  107.     void x_Clear(void);
  108.     // Get child's I/O handle.
  109.     HANDLE x_GetHandle(CPipe::EChildIOHandle from_handle) const;
  110.     // Convert STimeout value to number of milliseconds.
  111.     long   x_TimeoutToMSec(const STimeout* timeout) const;
  112.     // Trigger blocking mode on specified I/O handle.
  113.     bool   x_SetNonBlockingMode(HANDLE fd, bool nonblock = true) const;
  114. private:
  115.     // I/O handles for child process.
  116.     HANDLE  m_ChildStdIn;
  117.     HANDLE  m_ChildStdOut;
  118.     HANDLE  m_ChildStdErr;
  119.     // Child process descriptor.
  120.     HANDLE  m_ProcHandle;
  121.     // Child process pid.
  122.     TPid    m_Pid;
  123.     // Pipe flags
  124.     CPipe::TCreateFlags m_Flags;
  125. };
  126. CPipeHandle::CPipeHandle()
  127.     : m_ProcHandle(INVALID_HANDLE_VALUE),
  128.       m_ChildStdIn(INVALID_HANDLE_VALUE),
  129.       m_ChildStdOut(INVALID_HANDLE_VALUE),
  130.       m_ChildStdErr(INVALID_HANDLE_VALUE),
  131.       m_Flags(0)
  132. {
  133.     return;
  134. }
  135. CPipeHandle::~CPipeHandle()
  136. {
  137.     static const STimeout kZeroTimeout = {0, 0};
  138.     Close(0, &kZeroTimeout);
  139.     x_Clear();
  140. }
  141. EIO_Status CPipeHandle::Open(const string&         cmd,
  142.                              const vector<string>& args,
  143.                              CPipe::TCreateFlags   create_flags)
  144. {
  145.     x_Clear();
  146.     bool need_restore_handles = false; 
  147.     m_Flags = create_flags;
  148.     HANDLE stdin_handle       = INVALID_HANDLE_VALUE;
  149.     HANDLE stdout_handle      = INVALID_HANDLE_VALUE;
  150.     HANDLE stderr_handle      = INVALID_HANDLE_VALUE;
  151.     HANDLE child_stdin_read   = INVALID_HANDLE_VALUE;
  152.     HANDLE child_stdin_write  = INVALID_HANDLE_VALUE;
  153.     HANDLE child_stdout_read  = INVALID_HANDLE_VALUE;
  154.     HANDLE child_stdout_write = INVALID_HANDLE_VALUE;
  155.     HANDLE child_stderr_read  = INVALID_HANDLE_VALUE;
  156.     HANDLE child_stderr_write = INVALID_HANDLE_VALUE;
  157.     try {
  158.         if (m_ProcHandle != INVALID_HANDLE_VALUE) {
  159.             throw string("Pipe is already open");
  160.         }
  161.         // Save current I/O handles
  162.         stdin_handle  = GetStdHandle(STD_INPUT_HANDLE);
  163.         stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  164.         stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
  165.         
  166.         // Flush std.output buffers before remap
  167.         FlushFileBuffers(stdout_handle);
  168.         FlushFileBuffers(stderr_handle);
  169.         // Set base security attributes
  170.         SECURITY_ATTRIBUTES attr;
  171.         attr.nLength = sizeof(attr);
  172.         attr.bInheritHandle = TRUE;
  173.         attr.lpSecurityDescriptor = NULL;
  174.         HANDLE current_process = GetCurrentProcess();
  175.         need_restore_handles = true; 
  176.         // Create pipe for child's stdin
  177.         assert(CPipe::fStdIn_Close);
  178.         if ( !IS_SET(create_flags, CPipe::fStdIn_Close) ) {
  179.             if ( !CreatePipe(&child_stdin_read,
  180.                              &child_stdin_write, &attr, 0) ) {
  181.                 throw string("CreatePipe() failed");
  182.             }
  183.             if ( !SetStdHandle(STD_INPUT_HANDLE, child_stdin_read) ) {
  184.                 throw string("Failed to remap stdin for child process");
  185.             }
  186.             // Duplicate the handle
  187.             if ( !DuplicateHandle(current_process, child_stdin_write,
  188.                                   current_process, &m_ChildStdIn,
  189.                                   0, FALSE, DUPLICATE_SAME_ACCESS) ) {
  190.                 throw string("DuplicateHandle() failed on "
  191.                              "child's stdin handle");
  192.             }
  193.             ::CloseHandle(child_stdin_write);
  194.             x_SetNonBlockingMode(m_ChildStdIn);
  195.         }
  196.         // Create pipe for child's stdout
  197.         assert(CPipe::fStdOut_Close);
  198.         if ( !IS_SET(create_flags, CPipe::fStdOut_Close) ) {
  199.             if ( !CreatePipe(&child_stdout_read,
  200.                              &child_stdout_write, &attr, 0)) {
  201.                 throw string("CreatePipe() failed");
  202.             }
  203.             if ( !SetStdHandle(STD_OUTPUT_HANDLE, child_stdout_write) ) {
  204.                 throw string("Failed to remap stdout for child process");
  205.             }
  206.             // Duplicate the handle
  207.             if ( !DuplicateHandle(current_process, child_stdout_read,
  208.                                   current_process, &m_ChildStdOut,
  209.                                   0, FALSE, DUPLICATE_SAME_ACCESS) ) {
  210.                 throw string("DuplicateHandle() failed on "
  211.                              "child's stdout handle");
  212.             }
  213.             ::CloseHandle(child_stdout_read);
  214.             x_SetNonBlockingMode(m_ChildStdOut);
  215.         }
  216.         // Create pipe for child's stderr
  217.         assert(CPipe::fStdErr_Open);
  218.         if ( IS_SET(create_flags, CPipe::fStdErr_Open) ) {
  219.             if ( !CreatePipe(&child_stderr_read,
  220.                              &child_stderr_write, &attr, 0)) {
  221.                 throw string("CreatePipe() failed");
  222.             }
  223.             if ( !SetStdHandle(STD_ERROR_HANDLE, child_stderr_write) ) {
  224.                 throw string("Failed to remap stderr for child process");
  225.             }
  226.             // Duplicate the handle
  227.             if ( !DuplicateHandle(current_process, child_stderr_read,
  228.                                   current_process, &m_ChildStdErr,
  229.                                   0, FALSE, DUPLICATE_SAME_ACCESS) ) {
  230.                 throw string("DuplicateHandle() failed on "
  231.                              "child's stderr handle");
  232.             }
  233.             ::CloseHandle(child_stderr_read);
  234.             x_SetNonBlockingMode(m_ChildStdErr);
  235.         }
  236.         // Prepare command line to run
  237.         string cmd_line(cmd);
  238.         ITERATE (vector<string>, iter, args) {
  239.             if ( !cmd_line.empty() ) {
  240.                 cmd_line += " ";
  241.             }
  242.             cmd_line += *iter;
  243.         }
  244.         // Create child process
  245.         PROCESS_INFORMATION pinfo;
  246.         STARTUPINFO sinfo;
  247.         ZeroMemory(&pinfo, sizeof(PROCESS_INFORMATION));
  248.         ZeroMemory(&sinfo, sizeof(STARTUPINFO));
  249.         sinfo.cb = sizeof(sinfo);
  250.         if ( !CreateProcess(NULL,
  251.                             const_cast<char*> (cmd_line.c_str()),
  252.                             NULL, NULL, TRUE, 0,
  253.                             NULL, NULL, &sinfo, &pinfo) ) {
  254.             throw "CreateProcess() for "" + cmd_line + "" failed";
  255.         }
  256.         ::CloseHandle(pinfo.hThread);
  257.         m_ProcHandle = pinfo.hProcess;
  258.         m_Pid        = pinfo.dwProcessId; 
  259.         assert(m_ProcHandle != INVALID_HANDLE_VALUE);
  260.         // Restore remapped handles back to their original states
  261.         if ( !SetStdHandle(STD_INPUT_HANDLE,  stdin_handle) ) {
  262.             throw string("Failed to remap stdin for parent process");
  263.         }
  264.         if ( !SetStdHandle(STD_OUTPUT_HANDLE, stdout_handle) ) {
  265.             throw string("Failed to remap stdout for parent process");
  266.         }
  267.         if ( !SetStdHandle(STD_ERROR_HANDLE,  stderr_handle) ) {
  268.             throw string("Failed to remap stderr for parent process");
  269.         }
  270.         // Close unused pipe handles
  271.         ::CloseHandle(child_stdin_read);
  272.         ::CloseHandle(child_stdout_write);
  273.         ::CloseHandle(child_stderr_write);
  274.         return eIO_Success;
  275.      }
  276.     catch (string& what) {
  277.         // Restore all standard handles on error
  278.         if ( need_restore_handles ) {
  279.             SetStdHandle(STD_INPUT_HANDLE,  stdin_handle);
  280.             SetStdHandle(STD_OUTPUT_HANDLE, stdout_handle);
  281.             SetStdHandle(STD_ERROR_HANDLE,  stderr_handle);
  282.             ::CloseHandle(child_stdin_read);
  283.             ::CloseHandle(child_stdin_write);
  284.             ::CloseHandle(child_stdout_read);
  285.             ::CloseHandle(child_stdout_write);
  286.             ::CloseHandle(child_stderr_read);
  287.             ::CloseHandle(child_stderr_write);
  288.         }
  289.         const STimeout kZeroZimeout = {0,0};
  290.         Close(0, &kZeroZimeout);
  291.         ERR_POST(s_FormatErrorMessage("Open", what));
  292.         return eIO_Unknown;
  293.     }
  294. }
  295. EIO_Status CPipeHandle::Close(int* exitcode, const STimeout* timeout)
  296. {
  297.     if (m_ProcHandle == INVALID_HANDLE_VALUE) {
  298.         return eIO_Closed;
  299.     }
  300.     DWORD      x_exitcode = -1;
  301.     EIO_Status status     = eIO_Unknown;
  302.     // Get exit code of child process
  303.     if ( GetExitCodeProcess(m_ProcHandle, &x_exitcode) ) {
  304.         if (x_exitcode == STILL_ACTIVE) {
  305.             // Wait for the child process to exit
  306.             DWORD ws = WaitForSingleObject(m_ProcHandle,
  307.                                            x_TimeoutToMSec(timeout));
  308.             if (ws == WAIT_OBJECT_0) {
  309.                 // Get exit code of child process over again
  310.                 if ( GetExitCodeProcess(m_ProcHandle, &x_exitcode) ) {
  311.                     status = (x_exitcode == STILL_ACTIVE) ? 
  312.                         eIO_Timeout : eIO_Success;
  313.                 }
  314.             } else if (ws == WAIT_TIMEOUT) {
  315.                 status = eIO_Timeout;
  316.             }
  317.         } else {
  318.             status = eIO_Success;
  319.         }
  320.     }
  321.     // Is the process running?
  322.     if (status == eIO_Timeout) {
  323.         x_exitcode = -1;
  324.         assert(CPipe::fKillOnClose);
  325.         if ( IS_SET(m_Flags, CPipe::fKillOnClose) ) {
  326.             status = CProcess(m_Pid, CProcess::ePid).Kill() ?
  327.                               eIO_Success : eIO_Unknown;
  328.         }
  329.         // Active by default.
  330.         assert(!CPipe::fCloseOnClose);
  331.         if ( !IS_SET(m_Flags, CPipe::fCloseOnClose) ) {
  332.             status = eIO_Success;
  333.         }
  334.         // fKeepOnClose -- nothing to do.
  335.         assert(CPipe::fKeepOnClose);
  336.     }
  337.     // Is the process still running? Nothing to do.
  338.     if (status != eIO_Timeout) {
  339.         x_Clear();
  340.     }
  341.     if ( exitcode ) {
  342.         *exitcode = (int) x_exitcode;
  343.     }
  344.     return status;
  345. }
  346. EIO_Status CPipeHandle::CloseHandle(CPipe::EChildIOHandle handle)
  347. {
  348.     switch (handle) {
  349.     case CPipe::eStdIn:
  350.         if (m_ChildStdIn == INVALID_HANDLE_VALUE) {
  351.             return eIO_Closed;
  352.         }
  353.         ::CloseHandle(m_ChildStdIn);
  354.         m_ChildStdIn = INVALID_HANDLE_VALUE;
  355.         break;
  356.     case CPipe::eStdOut:
  357.         if (m_ChildStdOut == INVALID_HANDLE_VALUE) {
  358.             return eIO_Closed;
  359.         }
  360.         ::CloseHandle(m_ChildStdOut);
  361.         m_ChildStdOut = INVALID_HANDLE_VALUE;
  362.         break;
  363.     case CPipe::eStdErr:
  364.         if (m_ChildStdErr == INVALID_HANDLE_VALUE) {
  365.             return eIO_Closed;
  366.         }
  367.         ::CloseHandle(m_ChildStdErr);
  368.         m_ChildStdErr = INVALID_HANDLE_VALUE;
  369.         break;
  370.     default:
  371.         return eIO_InvalidArg;
  372.     }
  373.     return eIO_Success;
  374. }
  375. EIO_Status CPipeHandle::Read(void* buf, size_t count, size_t* read, 
  376.                              const CPipe::EChildIOHandle from_handle,
  377.                              const STimeout* timeout)
  378. {
  379.     EIO_Status status = eIO_Unknown;
  380.     try {
  381.         if (m_ProcHandle == INVALID_HANDLE_VALUE) {
  382.             status = eIO_Closed;
  383.             throw string("Pipe is closed");
  384.         }
  385.         HANDLE fd = x_GetHandle(from_handle);
  386.         if (fd == INVALID_HANDLE_VALUE) {
  387.             throw string("Pipe I/O handle is closed");
  388.         }
  389.         if ( !count ) {
  390.             return eIO_Success;
  391.         }
  392.         DWORD x_timeout   = x_TimeoutToMSec(timeout);
  393.         DWORD bytes_avail = 0;
  394.         DWORD bytes_read  = 0;
  395.         // Wait for data from the pipe with timeout.
  396.         // NOTE:  The function WaitForSingleObject() does not work with pipes.
  397.         do {
  398.             if ( !PeekNamedPipe(fd, NULL, 0, NULL, &bytes_avail, NULL) ) {
  399.                 // Has peer closed the connection?
  400.                 if (GetLastError() == ERROR_BROKEN_PIPE) {
  401.                     return eIO_Closed;
  402.                 }
  403.                 throw string("PeekNamedPipe() failed");
  404.             }
  405.             if ( bytes_avail ) {
  406.                 break;
  407.             }
  408.             DWORD x_sleep = kSleepTime;
  409.             if (x_timeout != INFINITE) {
  410.                 if (x_timeout < kSleepTime) {
  411.                     x_sleep = x_timeout;
  412.                 }
  413.                 x_timeout -= x_sleep;
  414.             }
  415.             SleepMilliSec(x_sleep);
  416.         } while (x_timeout == INFINITE  ||  x_timeout);
  417.         // Data is available to read or read request has timed out
  418.         if ( !bytes_avail ) {
  419.             return eIO_Timeout;
  420.         }
  421.         // We must read only "count" bytes of data regardless of
  422.         // the amount available to read
  423.         if (bytes_avail > count) {
  424.             bytes_avail = count;
  425.         }
  426.         if ( !ReadFile(fd, buf, count, &bytes_avail, NULL) ) {
  427.             throw string("Failed to read data from pipe");
  428.         }
  429.         if ( read ) {
  430.             *read = bytes_avail;
  431.         }
  432.         status = eIO_Success;
  433.     }
  434.     catch (string& what) {
  435.         ERR_POST(s_FormatErrorMessage("Read", what));
  436.     }
  437.     return status;
  438. }
  439. EIO_Status CPipeHandle::Write(const void* buf, size_t count,
  440.                               size_t* n_written, const STimeout* timeout)
  441. {
  442.     EIO_Status status = eIO_Unknown;
  443.     try {
  444.         if (m_ProcHandle == INVALID_HANDLE_VALUE) {
  445.             status = eIO_Closed;
  446.             throw string("Pipe is closed");
  447.         }
  448.         if (m_ChildStdIn == INVALID_HANDLE_VALUE) {
  449.             throw string("Pipe I/O handle is closed");
  450.         }
  451.         if ( !count ) {
  452.             return eIO_Success;
  453.         }
  454.         DWORD x_timeout     = x_TimeoutToMSec(timeout);
  455.         DWORD bytes_written = 0;
  456.         // Wait for data from the pipe with timeout.
  457.         // NOTE:  The function WaitForSingleObject() does not work with pipes.
  458.         do {
  459.             if ( !WriteFile(m_ChildStdIn, (char*)buf, count,
  460.                            &bytes_written, NULL) ) {
  461.                 if ( n_written ) {
  462.                     *n_written = bytes_written;
  463.                 }
  464.                 throw string("Failed to write data into pipe");
  465.             }
  466.             if ( bytes_written ) {
  467.                 break;
  468.             }
  469.             DWORD x_sleep = kSleepTime;
  470.             if (x_timeout != INFINITE) {
  471.                 if (x_timeout < kSleepTime) {
  472.                     x_sleep = x_timeout;
  473.                 }
  474.                 x_timeout -= x_sleep;
  475.             }
  476.             SleepMilliSec(x_sleep);
  477.         } while (x_timeout == INFINITE  ||  x_timeout);
  478.         if ( !bytes_written ) {
  479.             return eIO_Timeout;
  480.         }
  481.         if ( n_written ) {
  482.             *n_written = bytes_written;
  483.         }
  484.         status = eIO_Success;
  485.     }
  486.     catch (string& what) {
  487.         ERR_POST(s_FormatErrorMessage("Write", what));
  488.     }
  489.     return status;
  490. }
  491. void CPipeHandle::x_Clear(void)
  492. {
  493.     if (m_ChildStdIn != INVALID_HANDLE_VALUE) {
  494.         ::CloseHandle(m_ChildStdIn);
  495.         m_ChildStdIn = INVALID_HANDLE_VALUE;
  496.     }
  497.     if (m_ChildStdOut != INVALID_HANDLE_VALUE) {
  498.         ::CloseHandle(m_ChildStdOut);
  499.         m_ChildStdOut = INVALID_HANDLE_VALUE;
  500.     }
  501.     if (m_ChildStdErr != INVALID_HANDLE_VALUE) {
  502.         ::CloseHandle(m_ChildStdErr);
  503.         m_ChildStdErr = INVALID_HANDLE_VALUE;
  504.     }
  505.     m_ProcHandle = INVALID_HANDLE_VALUE;
  506.     m_Pid = 0;
  507. }
  508. HANDLE CPipeHandle::x_GetHandle(CPipe::EChildIOHandle from_handle) const
  509. {
  510.     switch (from_handle) {
  511.     case CPipe::eStdIn:
  512.         return m_ChildStdIn;
  513.     case CPipe::eStdOut:
  514.         return m_ChildStdOut;
  515.     case CPipe::eStdErr:
  516.         return m_ChildStdErr;
  517.     }
  518.     return INVALID_HANDLE_VALUE;
  519. }
  520. long CPipeHandle::x_TimeoutToMSec(const STimeout* timeout) const
  521. {
  522.     return timeout ? (timeout->sec * 1000) + (timeout->usec / 1000) 
  523.         : INFINITE;
  524. }
  525. bool CPipeHandle::x_SetNonBlockingMode(HANDLE fd, bool nonblock) const
  526. {
  527.     // Pipe is in the byte-mode.
  528.     // NOTE: We cannot get a state of a pipe handle opened for writing.
  529.     //       We cannot set a state of a pipe handle opened for reading.
  530.     DWORD state = nonblock ? PIPE_READMODE_BYTE | PIPE_NOWAIT :
  531.         PIPE_READMODE_BYTE;
  532.     return SetNamedPipeHandleState(fd, &state, NULL, NULL) != 0; 
  533. }
  534. #elif defined(NCBI_OS_UNIX)
  535. //////////////////////////////////////////////////////////////////////////////
  536. //
  537. // CPipeHandle -- Unix version
  538. //
  539. class CPipeHandle
  540. {
  541. public:
  542.     CPipeHandle();
  543.     ~CPipeHandle();
  544.     EIO_Status Open(const string& cmd, const vector<string>& args,
  545.                     CPipe::TCreateFlags create_flags);
  546.     EIO_Status Close(int* exitcode, const STimeout* timeout);
  547.     EIO_Status CloseHandle (CPipe::EChildIOHandle handle);
  548.     EIO_Status Read(void* buf, size_t count, size_t* read,
  549.                     const CPipe::EChildIOHandle from_handle,
  550.                     const STimeout* timeout);
  551.     EIO_Status Write(const void* buf, size_t count, size_t* written,
  552.                      const STimeout* timeout);
  553.     TProcessHandle GetProcessHandle(void) const { return m_Pid; };
  554. private:
  555.     // Clear object state.
  556.     void x_Clear(void);
  557.     // Get child's I/O handle.
  558.     int  x_GetHandle(CPipe::EChildIOHandle from_handle) const;
  559.     // Trigger blocking mode on specified I/O handle.
  560.     bool x_SetNonBlockingMode(int fd, bool nonblock = true) const;
  561.     // Wait on the file descriptor I/O.
  562.     // Return eIO_Success when "fd" is found ready for the I/O.
  563.     // Return eIO_Timeout, if timeout expired before I/O became available.
  564.     // Throw an exception on error.
  565.     EIO_Status x_Wait(int fd, EIO_Event direction,
  566.                       const STimeout* timeout) const;
  567. private:
  568.     // I/O handles for child process.
  569.     int  m_ChildStdIn;
  570.     int  m_ChildStdOut;
  571.     int  m_ChildStdErr;
  572.     // Child process pid.
  573.     TPid m_Pid;
  574.     // Pipe flags
  575.     CPipe::TCreateFlags m_Flags;
  576. };
  577. CPipeHandle::CPipeHandle()
  578.     : m_ChildStdIn(-1), m_ChildStdOut(-1), m_ChildStdErr(-1),
  579.       m_Pid((pid_t)(-1)), m_Flags(0)
  580. {
  581.     return;
  582. }
  583. CPipeHandle::~CPipeHandle()
  584. {
  585.     static const STimeout kZeroTimeout = {0, 0};
  586.     Close(0, &kZeroTimeout);
  587.     x_Clear();
  588. }
  589. EIO_Status CPipeHandle::Open(const string&         cmd,
  590.                              const vector<string>& args,
  591.                              CPipe::TCreateFlags   create_flags)
  592. {
  593.     x_Clear();
  594.     bool need_delete_handles = false; 
  595.     int  fd_pipe_in[2], fd_pipe_out[2], fd_pipe_err[2];
  596.     m_Flags = create_flags;
  597.     // Child process I/O handles
  598.     fd_pipe_in[0]  = -1;
  599.     fd_pipe_out[1] = -1;
  600.     fd_pipe_err[1] = -1;
  601.     try {
  602.         if (m_Pid != (pid_t)(-1)) {
  603.             throw string("Pipe is already open");
  604.         }
  605.         need_delete_handles = true; 
  606.         // Create pipe for child's stdin
  607.         assert(CPipe::fStdIn_Close);
  608.         if ( !IS_SET(create_flags, CPipe::fStdIn_Close) ) {
  609.             if (pipe(fd_pipe_in) == -1) {
  610.                 throw string("Failed to create pipe for stdin");
  611.             }
  612.             m_ChildStdIn = fd_pipe_in[1];
  613.             x_SetNonBlockingMode(m_ChildStdIn);
  614.         }
  615.         // Create pipe for child's stdout
  616.         assert(CPipe::fStdOut_Close);
  617.         if ( !IS_SET(create_flags, CPipe::fStdOut_Close) ) {
  618.             if (pipe(fd_pipe_out) == -1) {
  619.                 throw string("Failed to create pipe for stdout");
  620.             }
  621.             fflush(stdout);
  622.             m_ChildStdOut = fd_pipe_out[0];
  623.             x_SetNonBlockingMode(m_ChildStdOut);
  624.         }
  625.         // Create pipe for child's stderr
  626.         assert(CPipe::fStdErr_Open);
  627.         if ( IS_SET(create_flags, CPipe::fStdErr_Open) ) {
  628.             if (pipe(fd_pipe_err) == -1) {
  629.                 throw string("Failed to create pipe for stderr");
  630.             }
  631.             fflush(stderr);
  632.             m_ChildStdErr = fd_pipe_err[0];
  633.             x_SetNonBlockingMode(m_ChildStdErr);
  634.         }
  635.         // Fork child process
  636.         switch (m_Pid = fork()) {
  637.         case (pid_t)(-1):
  638.             // Fork failed
  639.             throw string("Failed to fork process");
  640.         case 0:
  641.             // Now we are in the child process
  642.             int status = -1;
  643.             // Bind child's standard I/O file handles to pipe
  644.             assert(CPipe::fStdIn_Close);
  645.             if ( !IS_SET(create_flags, CPipe::fStdIn_Close) ) {
  646.                 if (dup2(fd_pipe_in[0], STDIN_FILENO) < 0) {
  647.                     _exit(status);
  648.                 }
  649.                 close(fd_pipe_in[0]);
  650.                 close(fd_pipe_in[1]);
  651.             } else {
  652.                 fclose(stdin);
  653.             }
  654.             assert(CPipe::fStdOut_Close);
  655.             if ( !IS_SET(create_flags, CPipe::fStdOut_Close) ) {
  656.                 if (dup2(fd_pipe_out[1], STDOUT_FILENO) < 0) {
  657.                     _exit(status);
  658.                 }
  659.                 close(fd_pipe_out[0]);
  660.                 close(fd_pipe_out[1]);
  661.             } else {
  662.                 fclose(stdout);
  663.             }
  664.             assert(!CPipe::fStdErr_Close);
  665.             if ( IS_SET(create_flags, CPipe::fStdErr_Open) ) {
  666.                 if (dup2(fd_pipe_err[1], STDERR_FILENO) < 0) {
  667.                     _exit(status);
  668.                 }
  669.                 close(fd_pipe_err[0]);
  670.                 close(fd_pipe_err[1]);
  671.             } else {
  672.                 fclose(stderr);
  673.             }
  674.             // Prepare program arguments
  675.             size_t cnt = args.size();
  676.             size_t i   = 0;
  677.             const char** x_args = new const char*[cnt + 2];
  678.             typedef ArrayDeleter<const char*> TArgsDeleter;
  679.             AutoPtr<const char*, TArgsDeleter> p_args = x_args;
  680.             ITERATE (vector<string>, arg, args) {
  681.                 x_args[++i] = arg->c_str();
  682.             }
  683.             x_args[0] = cmd.c_str();
  684.             x_args[cnt + 1] = 0;
  685.             // Execute the program
  686.             status = execvp(cmd.c_str(), const_cast<char**> (x_args));
  687.             _exit(status);
  688.         }
  689.         // Close unused pipe handles
  690.         assert(CPipe::fStdIn_Close);
  691.         if ( !IS_SET(create_flags, CPipe::fStdIn_Close) ) {
  692.             close(fd_pipe_in[0]);
  693.         }
  694.         assert(CPipe::fStdOut_Close);
  695.         if ( !IS_SET(create_flags, CPipe::fStdOut_Close) ) {
  696.             close(fd_pipe_out[1]);
  697.         }
  698.         assert(!CPipe::fStdErr_Close);
  699.         if ( IS_SET(create_flags, CPipe::fStdErr_Open) ) {
  700.             close(fd_pipe_err[1]);
  701.         }
  702.         return eIO_Success;
  703.     } 
  704.     catch (string& what) {
  705.         if ( need_delete_handles ) {
  706.             close(fd_pipe_in[0]);
  707.             close(fd_pipe_out[1]);
  708.             close(fd_pipe_err[1]);
  709.         }
  710.         // Close all opened file descriptors (close timeout doesn't apply here)
  711.         Close(0, 0);
  712.         ERR_POST(s_FormatErrorMessage("Open", what));
  713.         return eIO_Unknown;
  714.     }
  715. }
  716. EIO_Status CPipeHandle::Close(int* exitcode, const STimeout* timeout)
  717. {    
  718.     EIO_Status    status     = eIO_Unknown;
  719.     unsigned long x_timeout  = 1;
  720.     int           x_options  = 0;
  721.     int           x_exitcode = -1;
  722.     if (m_Pid == (pid_t)(-1)) {
  723.         status = eIO_Closed;
  724.     } else {
  725.         // If timeout is not infinite
  726.         if ( timeout ) {
  727.             x_timeout = (timeout->sec * 1000) + (timeout->usec / 1000);
  728.             x_options = WNOHANG;
  729.         }
  730.         // Retry if interrupted by signal
  731.         for (;;) {
  732.             pid_t ws = waitpid(m_Pid, &x_exitcode, x_options);
  733.             if (ws > 0) {
  734.                 // Process has terminated
  735.                 status = eIO_Success;
  736.                 break;
  737.             } else if (ws == 0) {
  738.                 // Process is still running
  739.                 assert(timeout);
  740.                 if ( !x_timeout ) {
  741.                     status = eIO_Timeout;
  742.                     break;
  743.                 }
  744.                 unsigned long x_sleep = kSleepTime;
  745.                 if (x_timeout < kSleepTime) {
  746.                     x_sleep = x_timeout;
  747.                 }
  748.                 x_timeout -= x_sleep;
  749.                 SleepMilliSec(x_sleep);
  750.             } else {
  751.                 // Some error
  752.                 if (errno != EINTR) {
  753.                     break;
  754.                 }
  755.             }
  756.         }
  757.     }
  758.     // Is the process running?
  759.     if (status == eIO_Timeout) {
  760.         x_exitcode = -1;
  761.         assert(CPipe::fKillOnClose);
  762.         if ( IS_SET(m_Flags, CPipe::fKillOnClose) ) {
  763.             status = CProcess(m_Pid, CProcess::ePid).Kill() ?
  764.                               eIO_Success : eIO_Unknown;
  765.         }
  766.         // Active by default.
  767.         assert(!CPipe::fCloseOnClose);
  768.         if ( !IS_SET(m_Flags, CPipe::fCloseOnClose) ) {
  769.             status = eIO_Success;
  770.         }
  771.         // fKeepOnClose -- nothing to do.
  772.         assert(CPipe::fKeepOnClose);
  773.     }
  774.     // Is the process still running? Nothing to do.
  775.     if (status != eIO_Timeout) {
  776.         x_Clear();
  777.     }
  778.     if ( exitcode ) {
  779.         // Get real exit code or -1 on error
  780.         *exitcode = (status == eIO_Success  &&  x_exitcode != -1) ?
  781.             WEXITSTATUS(x_exitcode) : -1;
  782.     }
  783.     return status;
  784. }
  785. EIO_Status CPipeHandle::CloseHandle(CPipe::EChildIOHandle handle)
  786. {
  787.     switch ( handle ) {
  788.     case CPipe::eStdIn:
  789.         if (m_ChildStdIn == -1) {
  790.             return eIO_Closed;
  791.         }
  792.         close(m_ChildStdIn);
  793.         m_ChildStdIn = -1;
  794.         break;
  795.     case CPipe::eStdOut:
  796.         if (m_ChildStdOut == -1) {
  797.             return eIO_Closed;
  798.         }
  799.         close(m_ChildStdOut);
  800.         m_ChildStdOut = -1;
  801.         break;
  802.     case CPipe::eStdErr:
  803.         if (m_ChildStdErr == -1) {
  804.             return eIO_Closed;
  805.         }
  806.         close(m_ChildStdErr);
  807.         m_ChildStdErr = -1;
  808.         break;
  809.     default:
  810.         return eIO_InvalidArg;
  811.     }
  812.     return eIO_Success;
  813. }
  814. EIO_Status CPipeHandle::Read(void* buf, size_t count, size_t* n_read, 
  815.                              const CPipe::EChildIOHandle from_handle,
  816.                              const STimeout* timeout)
  817. {
  818.     EIO_Status status = eIO_Unknown;
  819.     try {
  820.         if (m_Pid == (pid_t)(-1)) {
  821.             status = eIO_Closed;
  822.             throw string("Pipe is closed");
  823.         }
  824.         int fd = x_GetHandle(from_handle);
  825.         if (fd == -1) {
  826.             throw string("Pipe I/O handle is closed");
  827.         }
  828.         if ( !count ) {
  829.             return eIO_Success;
  830.         }
  831.         // Retry if either blocked or interrupted
  832.         for (;;) {
  833.             // Try to read
  834.             ssize_t bytes_read = read(fd, buf, count);
  835.             if (bytes_read >= 0) {
  836.                 if ( n_read ) {
  837.                     *n_read = (size_t)bytes_read;
  838.                 }
  839.                 status = bytes_read ? eIO_Success : eIO_Closed;
  840.                 break;
  841.             }
  842.             // Blocked -- wait for data to come;  exit if timeout/error
  843.             if (errno == EAGAIN  ||  errno == EWOULDBLOCK) {
  844.                 status = x_Wait(fd, eIO_Read, timeout);
  845.                 if (status != eIO_Success) {
  846.                     break;
  847.                 }
  848.                 continue;
  849.             }
  850.             // Interrupted read -- restart
  851.             if (errno != EINTR) {
  852.                 throw string("Failed to read data from pipe");
  853.             }
  854.         }
  855.     }
  856.     catch (string& what) {
  857.         ERR_POST(s_FormatErrorMessage("Read", what));
  858.     }
  859.     return status;
  860. }
  861. EIO_Status CPipeHandle::Write(const void* buf, size_t count,
  862.                               size_t* n_written, const STimeout* timeout)
  863. {
  864.     EIO_Status status = eIO_Unknown;
  865.     try {
  866.         if (m_Pid == (pid_t)(-1)) {
  867.             status = eIO_Closed;
  868.             throw string("Pipe is closed");
  869.         }
  870.         if (m_ChildStdIn == -1) {
  871.             throw string("Pipe I/O handle is closed");
  872.         }
  873.         if ( !count ) {
  874.             return eIO_Success;
  875.         }
  876.         // Retry if either blocked or interrupted
  877.         for (;;) {
  878.             // Try to write
  879.             ssize_t bytes_written = write(m_ChildStdIn, buf, count);
  880.             if (bytes_written >= 0) {
  881.                 if ( n_written ) {
  882.                     *n_written = (size_t) bytes_written;
  883.                 }
  884.                 status = eIO_Success;
  885.                 break;
  886.             }
  887.             // Peer has closed its end
  888.             if (errno == EPIPE) {
  889.                 return eIO_Closed;
  890.             }
  891.             // Blocked -- wait for write readiness;  exit if timeout/error
  892.             if (errno == EAGAIN  ||  errno == EWOULDBLOCK) {
  893.                 status = x_Wait(m_ChildStdIn, eIO_Write, timeout);
  894.                 if (status != eIO_Success) {
  895.                     break;
  896.                 }
  897.                 continue;
  898.             }
  899.             // Interrupted write -- restart
  900.             if (errno != EINTR) {
  901.                 throw string("Failed to write data into pipe");
  902.             }
  903.         }
  904.     }
  905.     catch (string& what) {
  906.         ERR_POST(s_FormatErrorMessage("Write", what));
  907.     }
  908.     return status;
  909. }
  910. void CPipeHandle::x_Clear(void)
  911. {
  912.     if (m_ChildStdIn  != -1) {
  913.         close(m_ChildStdIn);
  914.         m_ChildStdIn   = -1;
  915.     }
  916.     if (m_ChildStdOut != -1) {
  917.         close(m_ChildStdOut);
  918.         m_ChildStdOut  = -1;
  919.     }
  920.     if (m_ChildStdErr != -1) {
  921.         close(m_ChildStdErr);
  922.         m_ChildStdErr  = -1;
  923.     }
  924.     m_Pid = -1;
  925. }
  926. int CPipeHandle::x_GetHandle(CPipe::EChildIOHandle from_handle) const
  927. {
  928.     switch (from_handle) {
  929.     case CPipe::eStdIn:
  930.         return m_ChildStdIn;
  931.     case CPipe::eStdOut:
  932.         return m_ChildStdOut;
  933.     case CPipe::eStdErr:
  934.         return m_ChildStdErr;
  935.     default:
  936.         break;
  937.     }
  938.     return -1;
  939. }
  940. bool CPipeHandle::x_SetNonBlockingMode(int fd, bool nonblock) const
  941. {
  942.     return fcntl(fd, F_SETFL,
  943.                  nonblock ?
  944.                  fcntl(fd, F_GETFL, 0) | O_NONBLOCK :
  945.                  fcntl(fd, F_GETFL, 0) & (int) ~O_NONBLOCK) != -1;
  946. }
  947. EIO_Status CPipeHandle::x_Wait(int fd, EIO_Event direction,
  948.                                const STimeout* timeout) const
  949. {
  950.     // Wait for the file descriptor to become ready only
  951.     // if timeout is set or infinite
  952.     if (timeout  &&  !timeout->sec  &&  !timeout->usec) {
  953.         return eIO_Timeout;
  954.     }
  955.     for (;;) { // Auto-resume if interrupted by a signal
  956.         struct timeval* tmp;
  957.         struct timeval  tm;
  958.         if ( timeout ) {
  959.             // NB: Timeout has been normalized already
  960.             tm.tv_sec  = timeout->sec;
  961.             tm.tv_usec = timeout->usec;
  962.             tmp = &tm;
  963.         } else
  964.             tmp = 0;
  965.         fd_set rfds;
  966.         fd_set wfds;
  967.         fd_set efds;
  968.         switch (direction) {
  969.         case eIO_Read:
  970.             FD_ZERO(&rfds);
  971.             FD_SET(fd, &rfds);
  972.             break;
  973.         case eIO_Write:
  974.             FD_ZERO(&wfds);
  975.             FD_SET(fd, &wfds);
  976.             break;
  977.         default:
  978.             assert(0);
  979.             return eIO_Unknown;
  980.         }
  981.         FD_ZERO(&efds);
  982.         FD_SET(fd, &efds);
  983.         int n = select(fd + 1,
  984.                        direction == eIO_Read  ? &rfds : 0,
  985.                        direction == eIO_Write ? &wfds : 0,
  986.                        &efds, tmp);
  987.         if (n == 0) {
  988.             return eIO_Timeout;
  989.         } else if (n > 0) {
  990.             switch (direction) {
  991.             case eIO_Read:
  992.                 if ( !FD_ISSET(fd, &rfds) ) {
  993.                     assert( FD_ISSET(fd, &efds) );
  994.                     return eIO_Closed;
  995.                 }
  996.                 break;
  997.             case eIO_Write:
  998.                 if ( !FD_ISSET(fd, &wfds) ) {
  999.                     assert( FD_ISSET(fd, &efds) );
  1000.                     return eIO_Closed;
  1001.                 }
  1002.                 break;
  1003.             default:
  1004.                 assert(0);
  1005.                 return eIO_Unknown;
  1006.             }
  1007.             break;
  1008.         } else if (errno != EINTR) {
  1009.             throw string("Failed select() on pipe");
  1010.         }
  1011.     }
  1012.     return eIO_Success;
  1013. }
  1014. #endif  /* NCBI_OS_UNIX | NCBI_OS_MSWIN */
  1015. //////////////////////////////////////////////////////////////////////////////
  1016. //
  1017. // CPipe
  1018. //
  1019. CPipe::CPipe(void)
  1020.     : m_PipeHandle(0), m_ReadHandle(eStdOut),
  1021.       m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed),
  1022.       m_ReadTimeout(0), m_WriteTimeout(0), m_CloseTimeout(0)
  1023.  
  1024. {
  1025.     // Create new OS-specific pipe handle
  1026.     m_PipeHandle = new CPipeHandle();
  1027.     if ( !m_PipeHandle ) {
  1028.         NCBI_THROW(CPipeException, eInit,
  1029.                    "Cannot create OS-specific pipe handle");
  1030.     }
  1031. }
  1032. CPipe::CPipe(const string& cmd, const vector<string>& args,
  1033.              TCreateFlags create_flags)
  1034.     : m_PipeHandle(0), m_ReadHandle(eStdOut),
  1035.       m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed),
  1036.       m_ReadTimeout(0), m_WriteTimeout(0), m_CloseTimeout(0)
  1037. {
  1038.     // Create new OS-specific pipe handle
  1039.     m_PipeHandle = new CPipeHandle();
  1040.     if ( !m_PipeHandle ) {
  1041.         NCBI_THROW(CPipeException, eInit,
  1042.                    "Cannot create OS-specific pipe handle");
  1043.     }
  1044.     EIO_Status status = Open(cmd, args, create_flags);
  1045.     if (status != eIO_Success) {
  1046.         NCBI_THROW(CPipeException, eOpen, "CPipe::Open() failed");
  1047.     }
  1048. }
  1049. CPipe::~CPipe(void)
  1050. {
  1051.     Close();
  1052.     if ( m_PipeHandle ) {
  1053.         delete m_PipeHandle;
  1054.     }
  1055. }
  1056. EIO_Status CPipe::Open(const string& cmd, const vector<string>& args,
  1057.                        TCreateFlags create_flags)
  1058. {
  1059.     if ( !m_PipeHandle ) {
  1060.         return eIO_Unknown;
  1061.     }
  1062.     assert(CPipe::fStdIn_Close);
  1063.     EIO_Status status = m_PipeHandle->Open(cmd, args, create_flags);
  1064.     if (status == eIO_Success) {
  1065.         m_ReadStatus  = eIO_Success;
  1066.         m_WriteStatus = eIO_Success;
  1067.     }
  1068.     return status;
  1069. }
  1070. EIO_Status CPipe::Close(int* exitcode)
  1071. {
  1072.     if ( !m_PipeHandle ) {
  1073.         return eIO_Unknown;
  1074.     }
  1075.     m_ReadStatus  = eIO_Closed;
  1076.     m_WriteStatus = eIO_Closed;
  1077.     return m_PipeHandle->Close(exitcode, m_CloseTimeout);
  1078. }
  1079. EIO_Status CPipe::CloseHandle(EChildIOHandle handle)
  1080. {
  1081.     if ( !m_PipeHandle ) {
  1082.         return eIO_Unknown;
  1083.     }
  1084.     return m_PipeHandle->CloseHandle(handle);
  1085. }
  1086. EIO_Status CPipe::Read(void* buf, size_t count, size_t* read,
  1087.                        EChildIOHandle from_handle)
  1088. {
  1089.     if ( read ) {
  1090.         *read = 0;
  1091.     }
  1092.     if (from_handle == eDefault)
  1093.         from_handle = m_ReadHandle;
  1094.     if (from_handle == eStdIn) {
  1095.         return eIO_InvalidArg;
  1096.     }
  1097.     if (count  &&  !buf) {
  1098.         return eIO_InvalidArg;
  1099.     }
  1100.     if ( !m_PipeHandle ) {
  1101.         return eIO_Unknown;
  1102.     }
  1103.     m_ReadStatus = m_PipeHandle->Read(buf, count, read, from_handle,
  1104.                                       m_ReadTimeout);
  1105.     return m_ReadStatus;
  1106. }
  1107. EIO_Status CPipe::SetReadHandle(EChildIOHandle from_handle)
  1108. {
  1109.     if (from_handle == eStdIn) {
  1110.         return eIO_Unknown;
  1111.     }
  1112.     if (from_handle != eDefault) {
  1113.         m_ReadHandle = from_handle;
  1114.     }
  1115.     return eIO_Success;
  1116. }
  1117. EIO_Status CPipe::Write(const void* buf, size_t count, size_t* written)
  1118. {
  1119.     if ( written ) {
  1120.         *written = 0;
  1121.     }
  1122.     if (count  &&  !buf) {
  1123.         return eIO_InvalidArg;
  1124.     }
  1125.     if ( !m_PipeHandle ) {
  1126.         return eIO_Unknown;
  1127.     }
  1128.     m_WriteStatus = m_PipeHandle->Write(buf, count, written,
  1129.                                         m_WriteTimeout);
  1130.     return m_WriteStatus;
  1131. }
  1132. EIO_Status CPipe::Status(EIO_Event direction) const
  1133. {
  1134.     switch ( direction ) {
  1135.     case eIO_Read:
  1136.         return m_ReadStatus;
  1137.     case eIO_Write:
  1138.         return m_WriteStatus;
  1139.     default:
  1140.         break;
  1141.     }
  1142.     return eIO_InvalidArg;
  1143. }
  1144. EIO_Status CPipe::SetTimeout(EIO_Event event, const STimeout* timeout)
  1145. {
  1146.     if (timeout == kDefaultTimeout) {
  1147.         return eIO_Success;
  1148.     }
  1149.     switch ( event ) {
  1150.     case eIO_Close:
  1151.         m_CloseTimeout = s_SetTimeout(timeout, &m_CloseTimeoutValue);
  1152.         break;
  1153.     case eIO_Read:
  1154.         m_ReadTimeout  = s_SetTimeout(timeout, &m_ReadTimeoutValue);
  1155.         break;
  1156.     case eIO_Write:
  1157.         m_WriteTimeout = s_SetTimeout(timeout, &m_WriteTimeoutValue);
  1158.         break;
  1159.     case eIO_ReadWrite:
  1160.         m_ReadTimeout  = s_SetTimeout(timeout, &m_ReadTimeoutValue);
  1161.         m_WriteTimeout = s_SetTimeout(timeout, &m_WriteTimeoutValue);
  1162.         break;
  1163.     default:
  1164.         return eIO_InvalidArg;
  1165.     }
  1166.     return eIO_Success;
  1167. }
  1168. const STimeout* CPipe::GetTimeout(EIO_Event event) const
  1169. {
  1170.     switch ( event ) {
  1171.     case eIO_Close:
  1172.         return m_CloseTimeout;
  1173.     case eIO_Read:
  1174.         return m_ReadTimeout;
  1175.     case eIO_Write:
  1176.         return m_WriteTimeout;
  1177.     default:
  1178.         ;
  1179.     }
  1180.     return kDefaultTimeout;
  1181. }
  1182. TProcessHandle CPipe::GetProcessHandle(void) const
  1183. {
  1184.     return m_PipeHandle ? m_PipeHandle->GetProcessHandle() : 0;
  1185. }
  1186. END_NCBI_SCOPE
  1187. /*
  1188.  * ===========================================================================
  1189.  * $Log: ncbi_pipe.cpp,v $
  1190.  * Revision 1000.4  2004/06/01 18:45:13  gouriano
  1191.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.37
  1192.  *
  1193.  * Revision 1.37  2004/05/17 20:58:13  gorelenk
  1194.  * Added include of PCH ncbi_pch.hpp
  1195.  *
  1196.  * Revision 1.36  2003/12/04 16:28:52  ivanov
  1197.  * CPipeHandle::Close(): added handling new create flags f*OnClose.
  1198.  * Added GetProcessHandle(). Throw/catch string exceptions instead char*.
  1199.  *
  1200.  * Revision 1.35  2003/11/14 13:06:01  ucko
  1201.  * +<stdio.h> (still needed by source...)
  1202.  *
  1203.  * Revision 1.34  2003/11/04 03:11:51  lavr
  1204.  * x_GetHandle(): default switch case added [for GCC2.95.2 to be happy]
  1205.  *
  1206.  * Revision 1.33  2003/10/24 16:52:38  lavr
  1207.  * Check RW bits before E bits in select()
  1208.  *
  1209.  * Revision 1.32  2003/09/25 04:40:42  lavr
  1210.  * Fixed uninitted member in ctor; few more minor changes
  1211.  *
  1212.  * Revision 1.31  2003/09/23 21:08:37  lavr
  1213.  * PipeStreambuf and special stream removed: now all in ncbi_conn_stream.cpp
  1214.  *
  1215.  * Revision 1.30  2003/09/16 13:42:36  ivanov
  1216.  * Added deleting OS-specific pipe handle in the destructor
  1217.  *
  1218.  * Revision 1.29  2003/09/09 19:30:33  ivanov
  1219.  * Fixed I/O timeout handling in the UNIX CPipeHandle. Cleanup code.
  1220.  * Comments and messages changes.
  1221.  *
  1222.  * Revision 1.28  2003/09/04 13:55:47  kans
  1223.  * added include sys/time.h to fix Mac compiler error
  1224.  *
  1225.  * Revision 1.27  2003/09/03 21:37:05  ivanov
  1226.  * Removed Linux ESPIPE workaround
  1227.  *
  1228.  * Revision 1.26  2003/09/03 20:53:02  ivanov
  1229.  * UNIX CPipeHandle::Read(): Added workaround for Linux -- read() returns
  1230.  * ESPIPE if a second pipe end is closed.
  1231.  * UNIX CPipeHandle::Close(): Implemented close timeout handling.
  1232.  *
  1233.  * Revision 1.25  2003/09/03 14:35:59  ivanov
  1234.  * Fixed previous accidentally commited log message
  1235.  *
  1236.  * Revision 1.24  2003/09/03 14:29:58  ivanov
  1237.  * Set r/w status to eIO_Success in the CPipe::Open()
  1238.  *
  1239.  * Revision 1.23  2003/09/02 20:32:34  ivanov
  1240.  * Moved ncbipipe to CONNECT library from CORELIB.
  1241.  * Rewritten CPipe class using I/O timeouts.
  1242.  *
  1243.  * Revision 1.22  2003/06/18 21:21:48  vakatov
  1244.  * Formal code formatting
  1245.  *
  1246.  * Revision 1.21  2003/06/18 18:59:33  rsmith
  1247.  * put in 0,1,2 for fileno(stdin/out/err) for library that does not have
  1248.  * fileno().
  1249.  *
  1250.  * Revision 1.20  2003/05/19 21:21:38  vakatov
  1251.  * Get rid of unnecessary unreached statement
  1252.  *
  1253.  * Revision 1.19  2003/05/08 20:13:35  ivanov
  1254.  * Cleanup #include <util/...>
  1255.  *
  1256.  * Revision 1.18  2003/04/23 20:49:21  ivanov
  1257.  * Entirely rewritten the Unix version of the CPipeHandle.
  1258.  * Added CPipe/CPipeHandle::CloseHandle().
  1259.  * Added flushing a standart output streams before it redirecting.
  1260.  *
  1261.  * Revision 1.17  2003/04/04 16:02:38  lavr
  1262.  * Lines wrapped at 79th column; some minor reformatting
  1263.  *
  1264.  * Revision 1.16  2003/04/03 14:15:48  rsmith
  1265.  * combine pp symbols NCBI_COMPILER_METROWERKS & _MSL_USING_MW_C_HEADERS
  1266.  * into NCBI_COMPILER_MW_MSL
  1267.  *
  1268.  * Revision 1.15  2003/04/02 16:22:34  rsmith
  1269.  * clean up metrowerks ifdefs.
  1270.  *
  1271.  * Revision 1.14  2003/04/02 13:29:53  rsmith
  1272.  * include ncbi_mslextras.h when compiling with MSL libs in Codewarrior.
  1273.  *
  1274.  * Revision 1.13  2003/03/10 18:57:08  kuznets
  1275.  * iterate->ITERATE
  1276.  *
  1277.  * Revision 1.12  2003/03/07 16:19:39  ivanov
  1278.  * MSWin CPipeHandle::Close() -- Handling GetExitCodeProcess() returns
  1279.  * value 259 (STILL_ACTIVE)
  1280.  *
  1281.  * Revision 1.11  2003/03/06 21:12:10  ivanov
  1282.  * Formal comments rearrangement
  1283.  *
  1284.  * Revision 1.10  2003/03/03 14:47:20  dicuccio
  1285.  * Remplemented CPipe using private platform specific classes.  Remplemented
  1286.  * Win32 pipes using CreatePipe() / CreateProcess() - enabled CPipe in windows
  1287.  * subsystem
  1288.  *
  1289.  * Revision 1.9  2002/09/05 18:38:07  vakatov
  1290.  * Formal code rearrangement to get rid of comp.warnings;  some nice-ification
  1291.  *
  1292.  * Revision 1.8  2002/07/15 18:17:24  gouriano
  1293.  * renamed CNcbiException and its descendents
  1294.  *
  1295.  * Revision 1.7  2002/07/11 14:18:27  gouriano
  1296.  * exceptions replaced by CNcbiException-type ones
  1297.  *
  1298.  * Revision 1.6  2002/07/02 16:22:25  ivanov
  1299.  * Added closing file descriptors of the local end of the pipe in Close()
  1300.  *
  1301.  * Revision 1.5  2002/06/12 14:20:44  ivanov
  1302.  * Fixed some bugs in CPipeStreambuf class.
  1303.  *
  1304.  * Revision 1.4  2002/06/12 13:48:56  ivanov
  1305.  * Fixed contradiction in types of constructor CPipeStreambuf and its
  1306.  * realization
  1307.  *
  1308.  * Revision 1.3  2002/06/11 19:25:35  ivanov
  1309.  * Added class CPipeIOStream, CPipeStreambuf
  1310.  *
  1311.  * Revision 1.2  2002/06/10 18:35:27  ivanov
  1312.  * Changed argument's type of a running child program from char*[]
  1313.  * to vector<string>
  1314.  *
  1315.  * Revision 1.1  2002/06/10 16:59:39  ivanov
  1316.  * Initial revision
  1317.  *
  1318.  * ===========================================================================
  1319.  */