bool thread_buffer_t::stop_thread()
{
    if( m_thread_started ) {
        if( int code=m_thread_control.set( exec_stream_t::s_child, 0 ) ) {
            throw os_error_t( "thread_buffer_t::stop_thread: unable to set thread termination event", code );
        }
        wait_result_t wait_result=m_thread_responce.wait( exec_stream_t::s_child, m_thread_termination_timeout, 0 );
        if( !wait_result.ok() && !wait_result.timed_out() ) {
            throw os_error_t( "thread_buffer_t::stop_thread: wait for m_thread_stopped failed", wait_result.error_code() );
        }
        if( wait_result.ok() ) {
            void * thread_result;
            if( int code=pthread_join( m_thread, &thread_result ) ) {
                throw os_error_t( "thread_buffer_t::stop_thread: pthread_join failed", code );
            }
            m_thread_started=false;
            // check for any errors encountered in the thread
            if( m_error_code!=0 ) {
                throw os_error_t( m_error_prefix, m_error_code );
            }
            return true;
        }else {
            return false;
        }
    }
    return true;
}
void thread_buffer_t::start()
{
    if( m_thread_started ) {
        throw exec_stream_t::error_t( "thread_buffer_t::start: thread already started" );
    }
    m_in_buffer.clear();
    m_out_buffer.clear();
    m_err_buffer.clear();

    int code;
    if( (code=m_thread_control.reset( ~0u, 0 )) || (code=m_thread_control.set( exec_stream_t::s_out|exec_stream_t::s_err, 0 ) ) ) {
        throw os_error_t( "thread_buffer_t::start: unable to initialize m_thread_control event", code );
    }
    if( (code=m_thread_responce.reset( ~0u, 0 )) || (code=m_thread_responce.set( exec_stream_t::s_in, 0 )) ) {
        throw os_error_t( "thread_buffer_t::start: unable to initialize m_thread_responce event", code );
    }
    
    m_error_prefix="";
    m_error_code=0;

    if( int code=pthread_create( &m_thread, 0, &thread_func, this ) ) {
        throw os_error_t( "exec_stream_therad_t::start: pthread_create failed", code );
    }
    m_thread_started=true;
    m_in_closed=false;
    m_in_bad=false;
}
void exec_stream_t::kill()
{
     if( m_impl->m_child_pid!=-1 )
     {
        if( ::kill( m_impl->m_child_pid, SIGKILL )==-1 )
        {
            throw os_error_t( "exec_stream_t::kill: kill failed" );
        }
// Updated via Sourceforge sansay0 comment as of 2010-08-20
// The correct way to handle killing a child process is to wait for the OS.
// to release the child process resources before assigning -1 to m_child_pid..
// Assigning -1 to m_child_pid without waiting will result in a "defunct" process.
// (aka zombie process) remaining in the process table..
        pid_t code=waitpid( m_impl->m_child_pid, &m_impl->m_exit_code, 0 );
        if( code == m_impl->m_child_pid )
        {
            m_impl->m_child_pid=-1;
            m_impl->m_exit_code=0;
        }
        else if( code == -1 )
        {
            throw os_error_t( "exec_stream_t::kill: waitpid failed" );
        }
    }
}
void thread_buffer_t::get( exec_stream_t::stream_kind_t kind, char * dst, std::size_t & size, bool & no_more )
{
    if( !m_thread_started ) {
        throw exec_stream_t::error_t( "thread_buffer_t::get: thread was not started" );
    }
    unsigned long timeout= kind==exec_stream_t::s_out ? m_out_wait_timeout : m_err_wait_timeout;
    int eof_kind= kind==exec_stream_t::s_out ? s_out_eof : s_err_eof;
    buffer_list_t & buffer= kind==exec_stream_t::s_out ? m_out_buffer : m_err_buffer;

    wait_result_t wait_result=m_thread_responce.wait( kind|exec_stream_t::s_child|eof_kind, timeout, 0 );
    if( !wait_result.ok() ) {
        throw os_error_t( "thread_buffer_t::get: wait for got_data failed", wait_result.error_code() );
    }
    
    if( wait_result.is_signaled( exec_stream_t::s_child ) ) {
        // thread stopped - no need to synchronize
        if( !buffer.empty() ) {
            // we have data - deliver it first
            // when thread terminated, there is no need to synchronize
            buffer.get( dst, size );
            no_more=false;
        }else {
            // thread terminated and we have no more data to return - report errors, if any
            if( m_error_code!=0 ) {
                throw os_error_t( m_error_prefix, m_error_code );
            }
            // if terminated without error  - signal eof 
            size=0;
            no_more=true;
        }        
    }else if( wait_result.is_signaled( kind|eof_kind ) ) {
        // thread got some data for us - grab them
        grab_mutex_t grab_mutex( m_mutex, 0 );
        if( !grab_mutex.ok() ) {
            throw os_error_t( "thread_buffer_t::get: wait for mutex failed", grab_mutex.error_code() );
        }

        if( !buffer.empty() ) {
            buffer.get( dst, size );
            no_more=false;
        }else {
            size=0;
            no_more=wait_result.is_signaled( eof_kind );
        }
        // if no data left - make the next get() wait until it arrives
        if( buffer.empty() ) {
            if( int code=m_thread_responce.reset( kind, 0 )  ) {
                throw os_error_t( "thread_buffer_t::get: unable to reset got_data event", code );
            }
        }        
        // if buffer is not too long tell the thread we want more data
        std::size_t buffer_limit= kind==exec_stream_t::s_out ? m_out_buffer_limit : m_err_buffer_limit;
        if( !buffer.full( buffer_limit ) ) {
            if( int code=m_thread_control.set( kind, 0 ) ) {
                throw os_error_t( "thread_buffer_t::get: unable to set want_data event", code );
            }
        }
    }
}
Exemplo n.º 5
0
// set_stdhandle_t
set_stdhandle_t::set_stdhandle_t( DWORD kind, HANDLE handle )
: m_kind( kind ), m_save_handle( GetStdHandle( kind ) ) 
{
    if( m_save_handle==INVALID_HANDLE_VALUE )
        throw os_error_t( "set_stdhandle_t::set_stdhandle_t: GetStdHandle() failed" );
    if( !SetStdHandle( kind, handle ) )
        throw os_error_t( "set_stdhandle_t::set_stdhandle_t: SetStdHandle() failed" );
}
void thread_buffer_t::put( char * src, std::size_t & size, bool & no_more )
{
    if( !m_thread_started ) {
        throw exec_stream_t::error_t( "thread_buffer_t::put: thread was not started" );
    }
    if( m_in_closed || m_in_bad ) { 
        size=0;
        no_more=true;
        return;
    }
    // wait for both m_want_data and m_mutex
    wait_result_t wait_result=m_thread_responce.wait( exec_stream_t::s_in|exec_stream_t::s_child, m_in_wait_timeout, 0 );
    if( !wait_result.ok() ) {
        // workaround for versions of libstdc++ (at least in gcc 3.1 pre) that do not intercept exceptions in operator<<( std::ostream, std::string )
        m_in_bad=true;
        if( m_in.exceptions()&std::ios_base::badbit ) {
            throw os_error_t( "thread_buffer_t::put: wait for want_data failed", wait_result.error_code() );
        }else {
            m_in.setstate( std::ios_base::badbit );
            size=0;
            no_more=true;
            return;
        }
    }
    if( wait_result.is_signaled( exec_stream_t::s_child ) ) {
        // thread stopped - check for errors
        if( m_error_code!=0 ) {
            throw os_error_t( m_error_prefix, m_error_code );
        }        
        // if terminated without error  - signal eof, since no one will ever write our data
        size=0;
        no_more=true;
    }else if( wait_result.is_signaled( exec_stream_t::s_in ) ) {
        // thread wants some data from us - stuff them
        grab_mutex_t grab_mutex( m_mutex, 0 );
        if( !grab_mutex.ok() ) {
            throw os_error_t( "thread_buffer_t::put: wait for mutex failed", grab_mutex.error_code() );
        }

        no_more=false;
        m_in_buffer.put( src, size );
        
        // if the buffer is too long - make the next put() wait until it shrinks
        if( m_in_buffer.full( m_in_buffer_limit ) ) {
            if( int code=m_thread_responce.reset( exec_stream_t::s_in, 0 ) ) {
                throw os_error_t( "thread_buffer_t::put: unable to reset want_data event", code );
            }
        }
        // tell the thread we got data
        if( !m_in_buffer.empty() ) {
            if( int code=m_thread_control.set( exec_stream_t::s_in, 0 ) ) {
                throw os_error_t( "thread_buffer_t::put: unable to set got_data event", code );
            }
        }
    }
}
Exemplo n.º 7
0
bool exec_stream_t::close()
{
    if( !close_in() ) {
        // need to close child's stdin no matter what, because otherwise "usual" child  will run forever
        // And before closing child's stdin the writer thread should be stopped no matter what,
        // because it may be blocked on Write to m_in_pipe, and in that case closing m_in_pipe may block. 
        if( !m_impl->m_in_thread.abort_thread() ) {
            throw exec_stream_t::error_t( "exec_stream_t::close: waiting till in_thread stops exceeded timeout" );
        }
        // when thread is terminated abnormally, it may left child's stdin open
        // try to close it here 
        CloseHandle( m_impl->m_in_pipe );
        m_impl->m_in_pipe=0;
    }
    if( !m_impl->m_out_thread.stop_thread() ) {
        if( !m_impl->m_out_thread.abort_thread() ) {
            throw exec_stream_t::error_t( "exec_stream_t::close: waiting till out_thread stops exceeded timeout" );
        }
    }
    if( !m_impl->m_err_thread.stop_thread() ) {
        if( !m_impl->m_err_thread.abort_thread() ) {
            throw exec_stream_t::error_t( "exec_stream_t::close: waiting till err_thread stops exceeded timeout" );
        }
    }
    if( m_impl->m_out_pipe!=0 ) {
        if( !CloseHandle( m_impl->m_out_pipe ) ) {
            throw os_error_t( "exec_stream_t::close: unable to close out_pipe handle" );
        }
        m_impl->m_out_pipe=0;
    }
    if( m_impl->m_err_pipe!=0 ) {
        if( !CloseHandle( m_impl->m_err_pipe ) ) {
            throw os_error_t( "exec_stream_t::close: unable to close err_pipe handle" );
        }
        m_impl->m_err_pipe=0;
    }
    if( m_impl->m_child_process!=0 ) {
        wait_result_t wait_result=wait( m_impl->m_child_process, m_impl->m_child_timeout );
        if( !wait_result.ok() & !wait_result.timed_out() ) {
            throw os_error_t( std::string( "exec_stream_t::close: wait for child process failed. " )+wait_result.error_message() );
        }
        if( wait_result.ok() ) {
            DWORD exit_code;
            if( !GetExitCodeProcess( m_impl->m_child_process, &exit_code ) ) {
                throw os_error_t( "exec_stream_t::close: unable to get process exit code" );
            }
            m_impl->m_exit_code=exit_code;
            if( !CloseHandle( m_impl->m_child_process ) ) {
                throw os_error_t( "exec_stream_t::close: unable to close child process handle" );
            }
            m_impl->m_child_process=0;
        }
    }
    return m_impl->m_child_process==0;
}
Exemplo n.º 8
0
void exec_stream_t::kill() 
{
    if( m_impl->m_child_process!=0 ) {
        if( !TerminateProcess( m_impl->m_child_process, 0 ) ) {
            throw os_error_t( "exec_stream_t::kill: unable to terminate child process" );
        }
        m_impl->m_exit_code=0;
        if( !CloseHandle( m_impl->m_child_process ) ) {
            throw os_error_t( "exec_stream_t::close: unable to close child process handle" );
        }
        m_impl->m_child_process=0;
    }
}
bool thread_buffer_t::abort_thread()
{
    if( m_thread_started ) {
        if( int code=pthread_cancel( m_thread ) ) {
            throw os_error_t( "thread_buffer_t::abort_thread: pthread_cancel failed", code );
        }
        void * thread_result;
        if( int code=pthread_join( m_thread, &thread_result ) ) {
            throw os_error_t( "thread_buffer_t::stop_thread: pthread_join failed", code );
        }
        m_thread_started=false;
    }
    return true;
}
Exemplo n.º 10
0
void thread_buffer_t::put( char * const src, std::size_t & size, bool & no_more )
{
    if( m_direction!=dir_write ) {
        throw exec_stream_t::error_t( "thread_buffer_t::put: thread not started or started for reading" );
    }
    // check thread status
    DWORD thread_exit_code;
    if( !GetExitCodeThread( m_thread, &thread_exit_code ) ) {
        throw os_error_t( "thread_buffer_t::get: GetExitCodeThread failed" );
    }

    if( thread_exit_code!=STILL_ACTIVE ) {
        // thread terminated - check for errors
        check_error( m_message_prefix, m_error_code, m_error_message );
        // if terminated without error  - signal eof, since no one will ever write our data
        size=0;
        no_more=true;
    }else {
        // wait for both m_want_data and m_mutex
        wait_result_t wait_result=wait( m_want_data, m_wait_timeout );
        if( !wait_result.ok() ) {
            check_error( "thread_buffer_t::put: wait for want_data failed", wait_result.error_code(), wait_result.error_message() );
        }
        grab_mutex_t grab_mutex( m_mutex, m_wait_timeout );
        if( !grab_mutex.ok() ) {
            check_error( "thread_buffer_t::put: wait for mutex failed", grab_mutex.error_code(), grab_mutex.error_message() );
        }
        
        // got them - put data
        no_more=false;
        if( m_translate_crlf ) {
            m_buffer_list.put_translate_crlf( src, size );
        }else {
            m_buffer_list.put( src, size );
        }
        
        // if the buffer is too long - make the next put() wait until it shrinks
        if( m_buffer_list.full( m_buffer_limit ) ) {
            if( !m_want_data.reset() ) {
                throw os_error_t( "thread_buffer_t::put: unable to reset m_want_data event" );
            }
        }
        // tell the thread we got data
        if( !m_buffer_list.empty() ) {
            if( !m_got_data.set() ) {
                throw os_error_t( "thread_buffer_t::put: unable to set m_got_data event" );
            }
        }
    }
}
Exemplo n.º 11
0
// mutex_t
mutex_t::mutex_t()
{
    m_handle=CreateMutex( 0, FALSE, 0 );
    if( m_handle==0 ) {
        throw os_error_t( "mutex_t::mutex_t: CreateMutex failed" );
    }
}
Exemplo n.º 12
0
// event_t
event_t::event_t()
{
    m_handle=CreateEvent( 0, TRUE, FALSE, 0 );
    if( m_handle==0 ) {
        throw os_error_t( "event_t::event_t: create event failed" );
    }
}
// event_t
event_t::event_t()
{
    if( int code=pthread_cond_init( &m_cond, 0 ) ) {
        throw os_error_t( "event_t::event_t: pthread_cond_init failed", code );
    }
    m_state=0;
}
Exemplo n.º 14
0
bool exec_stream_t::close()
{
    close_in();
    if( !m_impl->m_thread.stop_thread() ) {
        m_impl->m_thread.abort_thread();
    }
    m_impl->m_in_pipe.close();
    m_impl->m_out_pipe.close();
    m_impl->m_err_pipe.close();

    if( m_impl->m_child_pid!=-1 ) {
        pid_t code=waitpid( m_impl->m_child_pid, &m_impl->m_exit_code, WNOHANG );
        if( code==-1 ) {
            throw os_error_t( "exec_stream_t::close: first waitpid failed" );
        }else if( code==0 ) {

            struct timeval select_timeout;
            select_timeout.tv_sec=m_impl->m_child_timeout/1000;
            select_timeout.tv_usec=(m_impl->m_child_timeout%1000)*1000;
            if( (code=select( 0, 0, 0, 0, &select_timeout ))==-1 ) {
                //
                //  This code is using select as a semi-portable
                //  msec-res sleep.  For some reason it seems to
                //  fail semi-randomly on linux.  Since we're really
                //  just sleeping here, there's no reason to throw
                //  if it "fails". -- Alan
                //
                //throw os_error_t( "exec_stream_t::close: select failed" );
            }

            code=waitpid( m_impl->m_child_pid, &m_impl->m_exit_code, WNOHANG );
            if( code==-1 ) {
                throw os_error_t( "exec_stream_t::close: second waitpid failed" );
            }else if( code==0 ) {
                return false;
            }else {
                m_impl->m_child_pid=-1;
                return true;
            }
                    
        }else {
            m_impl->m_child_pid=-1;
            return true;
        }
    }
    return true;
}
Exemplo n.º 15
0
void thread_buffer_t::check_error( std::string const & message_prefix, DWORD error_code, std::string const & error_message )
{
    if( !error_message.empty() ) {
        throw exec_stream_t::error_t( message_prefix+"\n"+error_message, error_code );
    }else if( error_code!=ERROR_SUCCESS ) {
        throw os_error_t( message_prefix, error_code );
    }
}
void pipe_t::open()
{
    close();
    if( pipe( m_fds )==-1 ) {
        throw os_error_t( "pipe_t::open(): pipe() failed" );
    }
    m_direction=both;
}
void pipe_t::close_r()
{
    if( m_direction==both || m_direction==read ) {
        if( ::close( m_fds[0] )==-1 ) {
            throw os_error_t( "pipe_t::close_r: close failed" );
        }
        m_direction= m_direction==both ? write : closed;
    }
}
Exemplo n.º 18
0
void pipe_t::close_r() 
{
    if( m_direction==both || m_direction==read ) {
        if( !CloseHandle( m_r ) ) {
            throw os_error_t( "pipe_t::close_r: CloseHandle failed" );
        }
        m_direction= m_direction==both ? write : closed;
    }
}
Exemplo n.º 19
0
void pipe_t::close_w() 
{
    if( m_direction==both || m_direction==write ) {
        if( !CloseHandle( m_w ) ) {
            throw os_error_t( "pipe_t::close_w: CloseHandle failed" );
        }
        m_direction= m_direction==both ? read : closed;
    }
}
void pipe_t::close_w()
{
    if( m_direction==both || m_direction==write ) {
        if( ::close( m_fds[1] )==-1 ) {
            throw os_error_t( "pipe_t::close_w: close failed" );
        }
        m_direction= m_direction==both ? read : closed;
    }
}
Exemplo n.º 21
0
void exec_stream_t::kill()
{
    if( m_impl->m_child_pid!=-1 ) {
        if( ::kill( m_impl->m_child_pid, SIGKILL )==-1 ) {
            throw os_error_t( "exec_stream_t::kill: kill failed" );
        }
        m_impl->m_child_pid=-1;
        m_impl->m_exit_code=0;
    }
}
Exemplo n.º 22
0
bool thread_buffer_t::abort_thread()
{
    if( m_direction!=dir_none ) {
        if( !TerminateThread( m_thread, 0 ) ) {
            throw os_error_t( "exec_steam_t::abort_thread: TerminateThread failed" );
        }
        return check_thread_stopped();
    }
    return true;
}
bool exec_stream_t::close()
{
    close_in();
    if( !m_impl->m_thread.stop_thread() ) {
        m_impl->m_thread.abort_thread();
    }
    m_impl->m_in_pipe.close();
    m_impl->m_out_pipe.close();
    m_impl->m_err_pipe.close();

    if( m_impl->m_child_pid!=-1 ) {
        pid_t code=waitpid( m_impl->m_child_pid, &m_impl->m_exit_code, WNOHANG );
        if( code==-1 ) {
            throw os_error_t( "exec_stream_t::close: first waitpid failed" );
        }else if( code==0 ) {

            struct timeval select_timeout;
            select_timeout.tv_sec=m_impl->m_child_timeout/1000;
            select_timeout.tv_usec=(m_impl->m_child_timeout%1000)*1000;
            //if( (code=select( 0, 0, 0, 0, &select_timeout ))==-1 ) {
            while( (code=select( 0, 0, 0, 0, &select_timeout ))==-1 ) {
                if (errno == EINTR) continue;
                throw os_error_t( "exec_stream_t::close: select failed" );
            }

            code=waitpid( m_impl->m_child_pid, &m_impl->m_exit_code, WNOHANG );
            if( code==-1 ) {
                throw os_error_t( "exec_stream_t::close: second waitpid failed" );
            }else if( code==0 ) {
                return false;
            }else {
                m_impl->m_child_pid=-1;
                return true;
            }
                    
        }else {
            m_impl->m_child_pid=-1;
            return true;
        }
    }
    return true;
}
Exemplo n.º 24
0
void pipe_t::open() 
{
    close();
    SECURITY_ATTRIBUTES sa;
    sa.nLength=sizeof( sa );
    sa.bInheritHandle=true;
    sa.lpSecurityDescriptor=0;
    if( !CreatePipe( &m_r, &m_w, &sa, 0 ) )
        throw os_error_t( "pipe_t::pipe_t: CreatePipe failed" );
    m_direction=both;
}
void thread_buffer_t::close_in()
{
    if( !m_in_bad ) {
        m_in.flush();
    }
    if( m_thread_started ) {
        if( int code=m_thread_control.set( s_in_eof, 0 ) ) {
            throw os_error_t( "thread_buffer_t::close_in: unable to set in_got_data event", code );
        }
        m_in_closed=true;
    }
}
Exemplo n.º 26
0
void thread_buffer_t::start_thread( HANDLE pipe, direction_t direction )
{
    if( m_direction!=dir_none ) {
        throw exec_stream_t::error_t( "thread_buffer_t::start_thread: thread already started" );
    }
    m_buffer_list.clear();
    m_pipe=pipe;
    if( !m_stop_thread.reset() ) {
        throw os_error_t( "thread_buffer_t::start_thread: unable to initialize m_stop_thread event" );
    }
    if( !m_got_data.reset() ) {
        throw os_error_t( "thread_buffer_t::start_thread: unable to initialize m_got_data event" );
    }
    if( !m_want_data.set() ) {
        throw os_error_t( "thread_buffer_t::start_thread: unable to initialize m_want_data event" );
    }
    DWORD thread_id;
    m_thread=CreateThread( 0, 0, direction==dir_read ? reader_thread : writer_thread, this, 0, &thread_id );
    if( m_thread==0 ) {
        throw os_error_t( "thread_buffer_t::start_thread: unable to start thread" );
    }
    m_direction= direction==dir_read ? dir_read : dir_write;
}
Exemplo n.º 27
0
bool thread_buffer_t::stop_thread()
{
    if( m_direction!=dir_none ) {
        if( !m_stop_thread.set() ) {
            throw os_error_t( "thread_buffer_t::stop_thread: m_stop_thread.set() failed" );
        }
        bool res=check_thread_stopped();
        if( res ) {
            check_error( m_message_prefix, m_error_code, m_error_message );
        }
        return res;
    }
    return true;
}
Exemplo n.º 28
0
void exec_stream_t::start( std::string const & program, std::string const & arguments )
{
    if( !close() ) {
        throw exec_stream_t::error_t( "exec_stream_t::start: previous child process has not yet terminated" );
    }

    pipe_t in;
    pipe_t out;
    pipe_t err;
    set_stdhandle_t set_in( STD_INPUT_HANDLE, in.r() );
    set_stdhandle_t set_out( STD_OUTPUT_HANDLE, out.w() );
    set_stdhandle_t set_err( STD_ERROR_HANDLE, err.w() );
    HANDLE cp=GetCurrentProcess();
    if( !DuplicateHandle( cp, in.w(), cp, &m_impl->m_in_pipe, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
        throw os_error_t( "exec_stream_t::start: unable to duplicate in handle" );
    }
    in.close_w();
    if( !DuplicateHandle( cp, out.r(), cp, &m_impl->m_out_pipe, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
        throw os_error_t( "exec_stream_t::start: unable to duplicate out handle" );
    }
    out.close_r();
    if( !DuplicateHandle( cp, err.r(), cp, &m_impl->m_err_pipe, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
        throw os_error_t( "exec_stream_t::start: unable to duplicate err handle" );
    }
    err.close_r();

    std::string command;
    command.reserve( program.size()+arguments.size()+3 );
    if( program.find_first_of( " \t" )!=std::string::npos ) {
        command+='"';
        command+=program;
        command+='"';
    }else
        command=program;
    if( arguments.size()!=0 ) {
        command+=' ';
        command+=arguments;
    }
    STARTUPINFOA si;
    ZeroMemory( &si, sizeof( si ) );
    si.cb=sizeof( si );
    PROCESS_INFORMATION pi;
    ZeroMemory( &pi, sizeof( pi ) );
    if( !CreateProcessA( 0, const_cast< char * >( command.c_str() ), 0, 0, TRUE, 0, 0, 0, &si, &pi ) ) {
        throw os_error_t( "exec_stream_t::start: CreateProcess failed.\n command line was: "+command );
    }

    m_impl->m_child_process=pi.hProcess;
    
    m_impl->m_in_buffer.clear();
    m_impl->m_out_buffer.clear();
    m_impl->m_err_buffer.clear();

    m_impl->m_in.clear();
    m_impl->m_out.clear();
    m_impl->m_err.clear();

    m_impl->m_out_thread.set_read_buffer_size( STREAM_BUFFER_SIZE );
    m_impl->m_out_thread.start_reader_thread( m_impl->m_out_pipe );

    m_impl->m_err_thread.set_read_buffer_size( STREAM_BUFFER_SIZE );
    m_impl->m_err_thread.start_reader_thread( m_impl->m_err_pipe );

    m_impl->m_in_thread.start_writer_thread( m_impl->m_in_pipe );
}
// mutex_t
mutex_t::mutex_t()
{
    if( int code=pthread_mutex_init( &m_mutex, 0 ) ) {
        throw os_error_t( "mutex_t::mutex_t: pthread_mutex_init failed", code );
    }    
}
Exemplo n.º 30
0
void exec_stream_t::impl_t::start( std::string const & program )
{
    m_in_pipe.open();
    m_out_pipe.open();
    m_err_pipe.open();
    
    pipe_t status_pipe;
    status_pipe.open();
    
    pid_t pid=fork();
    if( pid==-1 ) {
        throw os_error_t( "exec_stream_t::start: fork failed" );
    }else if( pid==0 ) {
        try {
            status_pipe.close_r();
            if( fcntl( status_pipe.w(), F_SETFD, FD_CLOEXEC )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to fcnth( status_pipe, F_SETFD, FD_CLOEXEC ) in child process" );
            }
            m_in_pipe.close_w();
            m_out_pipe.close_r();
            m_err_pipe.close_r();
            if( ::close( 0 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to close( 0 ) in child process" );
            }
            if( fcntl( m_in_pipe.r(), F_DUPFD, 0 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to fcntl( .., F_DUPFD, 0 ) in child process" );
            }
            if( ::close( 1 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to close( 1 ) in child process" );
            }
            if( fcntl( m_out_pipe.w(), F_DUPFD, 1 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to fcntl( .., F_DUPFD, 1 ) in child process" );
            }
            if( ::close( 2 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to close( 2 ) in child process" );
            }
            if( fcntl( m_err_pipe.w(), F_DUPFD, 2 )==-1 ) {
                throw os_error_t( "exec_stream_t::start: unable to fcntl( .., F_DUPFD, 2 ) in child process" );
            }
            m_in_pipe.close_r();
            m_out_pipe.close_w();
            m_err_pipe.close_w();
            if( execvp( m_child_args.data(), m_child_argp.data() )==-1 ) {
                throw os_error_t( "exec_stream_t::start: exec in child process failed. "+program );
            }
            throw exec_stream_t::error_t( "exec_stream_t::start: exec in child process returned" );
        }catch( std::exception const & e ) {
            const char * msg=e.what();
            std::size_t len=strlen( msg );
            write( status_pipe.w(), &len, sizeof( len ) );
            write( status_pipe.w(), msg, len );
            _exit( -1 );
        }catch( ... ) {
            const char * msg="exec_stream_t::start: unknown exception in child process";
            std::size_t len=strlen( msg );
            write( status_pipe.w(), &len, sizeof( len ) );
            write( status_pipe.w(), msg, len );
            _exit( 1 );
        }
    }else {
        m_child_pid=pid;
        status_pipe.close_w();
        fd_set status_fds;
        FD_ZERO( &status_fds );
        FD_SET( status_pipe.r(), &status_fds );
        struct timeval timeout;
        timeout.tv_sec=3;
        timeout.tv_usec=0;
        if( select( status_pipe.r()+1, &status_fds, 0, 0, &timeout )==-1 ) {
            throw os_error_t( "exec_stream_t::start: select on status_pipe failed" );
        }
        if( !FD_ISSET( status_pipe.r(), &status_fds ) ) {
            throw os_error_t( "exec_stream_t::start: timeout while waiting for child to report via status_pipe" );
        }
        std::size_t status_len;
        int status_nread=read( status_pipe.r(), &status_len, sizeof( status_len ) );
        // when all ok, status_pipe is closed on child's exec, and nothing is written to it
        if( status_nread!=0 ) {
            // otherwize, check what went wrong.
            if( status_nread==-1 ) {
                throw os_error_t( "exec_stream_t::start: read from status pipe failed" );
            }else if( status_nread!=sizeof( status_len ) ) {
                throw os_error_t( "exec_stream_t::start: unable to read length of status message from status_pipe" );
            }
            std::string status_msg;
            if( status_len!=0 ) {
                buf_t< char > status_buf;
                status_buf.new_data( status_len );
                status_nread=read( status_pipe.r(), status_buf.data(), status_len );
                if( status_nread==-1 ) {
                    throw os_error_t( "exec_stream_t::start: readof status message from status pipe failed" );
                }
                status_msg.assign( status_buf.data(), status_len );
            }
            throw exec_stream_t::error_t( "exec_stream_t::start: error in child process."+status_msg );
        }
        status_pipe.close_r();

        m_in_pipe.close_r();
        m_out_pipe.close_w();
        m_err_pipe.close_w();

        if( fcntl( m_in_pipe.w(), F_SETFL, O_NONBLOCK )==-1 ) {
            throw os_error_t( "exec_stream_t::start: fcntl( in_pipe, F_SETFL, O_NONBLOCK ) failed" );
        }

        m_in_buffer.clear();
        m_out_buffer.clear();
        m_err_buffer.clear();

        m_in.clear();
        m_out.clear();
        m_err.clear();
        
        m_thread.set_read_buffer_size( exec_stream_t::s_out, STREAM_BUFFER_SIZE );
        m_thread.set_read_buffer_size( exec_stream_t::s_err, STREAM_BUFFER_SIZE );
        m_thread.start();
    }
}