[Ace-users] [ace-users] TTY_IO: problem with asynchronous I/O

Robert Lubaszka malyro at orange.pl
Tue Feb 5 16:24:37 CST 2008


     ACE VERSION:
         5.5.1

     HOST MACHINE and OPERATING SYSTEM:
         Windows 2000 Pro SP4 / WINSOCK2

     TARGET MACHINE and OPERATING SYSTEM, if different from HOST:

     THE $ACE_ROOT/ace/config.h FILE:
         config-win32.h

     THE $ACE_ROOT/include/makeinclude/platform_macros.GNU FILE: N/A

     CONTENTS OF $ACE_ROOT/bin/MakeProjectCreator/config/default.features:  
N/A

     AREA/CLASS/EXAMPLE AFFECTED:

     DOES THE PROBLEM AFFECT:
         COMPILATION? No
         LINKING? No
         EXECUTION? Yes
         OTHER (please specify)?

     SYNOPSIS:
I'm trying to write serial port driver with asynchronous I/O. I wrote  
simple
test code using ACE_Event_Handler ACE_DEV_Connector and ACE_Reactor. After
some "tricks" with overlapped I/O, specific "register_handler" calling,
specific "recv" etc, the test is running, but the reactor loop does not  
stop
after specified timeout and handle_signal is called even when no data  
arrives.
So I try to rewrite test code using Proactor pattern,
but behaviour of the test is very similar.

     DESCRIPTION:
I tried some "tricks" with port initialization ( like OVERLAPPED flag ),  
event
handler registering, but it doesn't help. I'v got one of these:

"Reactor" version of test:
1. "Socket operation on non socket" after register_handler, or
2. "Invalid argument (22)" after register_handler, or
3. "Unknown error (997)" after send(...), or
4. no data reception ( probably improper port initialization ), or
5. infinite reactor loop..

"Proactor" version of test:
1. no input, no handle_read_stream(...) calls, or
2. "not connected (10057)" error after open(..) on ACE_Asynch_Read_Stream,  
or
3. infinite proactor loop..

What am I doing wrong?


     REPEAT BY:
Test code:


=================================================
"Reactor" version of test:
=================================================
#include <ace/OS.h>
#include <ace/TTY_IO.h>
#include <ace/Svc_Handler.h>
#include <ace/DEV_Connector.h>
#include <ace/Connector.h>
#include <ace/Msg_WFMO_Reactor.h>
#include <string>

#define RSBUFSZ 1024

class TestHandler: public ACE_Event_Handler
{
public:
     ACE_DEV_Connector konektor_;
     char rsbuf[RSBUFSZ];
     OVERLAPPED ovr_;

public:
     ACE_TTY_IO peer_;
     TestHandler()
     {
         ACE_OS::memset( &ovr_, 0, sizeof( ovr_ ) );
     };
     virtual ~TestHandler() {};

//
// If not overriden: "Invalid argument (22)" after register_handler(..)
//
     virtual ACE_HANDLE get_handle( void ) const { return ovr_.hEvent; }

     int open( const std::string& device, int baud )
     {
         int result = konektor_.connect( peer_,
                                     ACE_DEV_Addr( device.c_str() ),
                                     0, //timeout
                                     ACE_Addr::sap_any,
                                     0, //reuse
//
// if FILE_FLAG_OVERLAPPED enabled: "Unknown error (997)" after send(..)
//
//                                    O_RDWR | FILE_FLAG_OVERLAPPED );
                                     O_RDWR );
         if( result == 0 )
         {
             // set the appropriate parameters
             ACE_TTY_IO::Serial_Params params;
             result = peer_.control( ACE_TTY_IO::GETPARAMS, &params );
             params.baudrate = baud;
             params.databits = 8;
             params.stopbits = 1;
             params.parityenb = 0;
             params.ctsenb = 0;
             params.rcvenb = 1;
             params.rtsenb = 1;
             params.dsrenb = 0;
             result = peer_.control( ACE_TTY_IO::SETPARAMS, &params );
             if( result != 0 )
             {
                 ACE_DEBUG( ( LM_ERROR,
                     ACE_TEXT( "TestDriver could not open serial port  
%s\n"),
                     device.c_str() ) );
                 return 0;
             }
         }

         ovr_.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
         if ( peer_.recv( rsbuf, RSBUFSZ, &ovr_ ) == -1 )
         {
             ACE_ERROR( ( LM_ERROR,
                         "Cannot initialize overlapped IO: %m (%d).\n",
                         ACE_OS::last_error() ) );
         }
         result = ACE_Reactor::instance()->register_handler( this );
         if ( result != 0 )
         {
             ACE_ERROR( ( LM_ERROR,
                     "%IFrameEventHandler: Cannot register handler:%m  
(%d).\n",
                     ACE_OS::last_error() ) );
         }
         return result;
     }
     int handle_input( ACE_HANDLE fd = ACE_INVALID_HANDLE )
     {
         return handle_signal( 0, NULL, NULL );
     }

     int handle_signal( int s, siginfo_t* sig, ucontext_t* con )
     {
         DWORD ncnt = peer_.recv( rsbuf, RSBUFSZ, &ovr_ );
         if ( ncnt > 0 )
         {
             ACE_DEBUG( ( LM_INFO, ACE_TEXT( "dane: [%d]\n" ), ncnt ) );
         }
#ifdef WIN32
         else // this is a hack to avoid high resource consumption on  
windows !
         {
             ACE_OS::sleep( ACE_Time_Value( 0, 20000 ) );
         }
#endif
         return 0;
     }
};


int main( int argc, char* argv[] )
{
     TestHandler* driver = new TestHandler;

     if ( driver->open( "COM1", 9600 ) != 0 )
     {
         ACE_DEBUG( ( LM_ERROR,
                      ACE_TEXT( "could not start TestHandler !\n" ) ) );
         return 0;
     }
     ACE_DEBUG( ( LM_INFO, ACE_TEXT( "started TestHandler !\n" ) ) );

     if ( driver->peer_.send( "fire 1\n", 7, &driver->ovr_ ) == -1 )
     {
         ACE_ERROR( ( LM_ERROR,
                      "Cannot send ala ma kota: %m (%d).\n",
                      ACE_OS::last_error() ) );
         return -1;
     }
     ACE_DEBUG( ( LM_INFO, ACE_TEXT( "fire 1 !\n" ) ) );
     ACE_OS::sleep( ACE_Time_Value( 2, 0 ) );
     driver->peer_.send( "fire 2\n", 7 );
     ACE_DEBUG( ( LM_INFO, ACE_TEXT( "fire 2 !\n" ) ) );
     ACE_OS::sleep( ACE_Time_Value( 2, 0 ) );
     driver->peer_.send( "fire 3\n", 7 );
     ACE_DEBUG( ( LM_INFO, ACE_TEXT( "fire 3 !\n" ) ) );
     ACE_Reactor::instance()->run_reactor_event_loop(
                                 ACE_Time_Value( 20, 0 ) );
     driver->peer_.close();
     delete driver;
     return 0;
}


=================================================
"Proactor" version of test:
=================================================
#include <ace/Asynch_IO.h>
#include <ace/OS.h>
#include <ace/Message_Block.h>
#include <ace/DEV_Connector.h>
#include <ace/TTY_IO.h>
#include <ace/Proactor.h>

class TTYService: public ACE_Handler
{
private:
     ACE_Asynch_Read_Stream reader_;
     ACE_Asynch_Write_Stream writer_;

public:
     ~TTYService()
     {
     }

     void openTTY()
     {
         ACE_TTY_IO peer_;
         ACE_DEV_Connector connector_;

         int result = connector_.connect( peer_,
                                         ACE_DEV_Addr( "COM1" ),
                                         0, //timeout
                                         ACE_Addr::sap_any,
                                         0, //reuse
                                         O_RDWR | FILE_FLAG_OVERLAPPED );
//
// If FILE_FLAG_OVERLAPPED not set: no data input,
// no handle_read_stream(...) calling
//
         if( result == 0 )
         {
             // set the appropriate parameters
             ACE_TTY_IO::Serial_Params params;
             result = peer_.control( ACE_TTY_IO::GETPARAMS, &params );
             params.baudrate = 9600;
             params.databits = 8;
             params.stopbits = 1;
             params.parityenb = 0;
             params.ctsenb = 0;
             params.rcvenb = 1;
             params.rtsenb = 1;
             params.dsrenb = 0;
             result = peer_.control( ACE_TTY_IO::SETPARAMS, &params );
             if( result != 0 )
             {
                 //error;
                 return;
             }
         }

//
// If second argument ( "peer_.get_handle()" ) not set:
// "not connected (10057)" error
//        if ( this->reader_.open( *this ) != 0 )
         if ( this->reader_.open( *this, peer_.get_handle() ) != 0 )
         {
             ACE_ERROR( ( LM_ERROR,
                          "BLAD: %m (%d).\n", ACE_OS::last_error() ) );
             return;
         }
//
// If second argument ( "peer_.get_handle()" ) not set:
// "not connected (10057)" error
//        if ( this->writer_.open( *this ) != 0 )
         if ( this->writer_.open( *this, peer_.get_handle() ) != 0 )
         {
             ACE_ERROR( ( LM_ERROR,
                          "BLAD: %m (%d).\n", ACE_OS::last_error() ) );
             return;
         }
         ACE_Message_Block* mb;
         ACE_NEW_NORETURN( mb, ACE_Message_Block( 1024 ) );
         if ( this->reader_.read( *mb, mb->space() ) != 0 )
         {
             //ERROR!!!
             mb->release();
             return;
         }
         return;
     }

     virtual void handle_read_stream(
                         const ACE_Asynch_Read_Stream::Result& result )
     {
         ACE_Message_Block& mb = result.message_block();
         bool sukces = result.success();
         int trsf = result.bytes_transferred();
         if ( !sukces )
         {
             mb.release();
             delete this;
             return;
         }
         if ( trsf != 0 )
         {
             if ( this->writer_.write( mb, mb.length() ) != 0 )
             {
                 //ERROR
                 mb.release();
                 return;
             }
         }
         else
         {
             mb.release();
#ifdef WIN32
             // this is a hack to avoid high resource consumption on  
windows !
             ACE_OS::sleep( ACE_Time_Value( 0, 20000 ) );
#endif
         }
         ACE_Message_Block* new_mb;
         ACE_NEW_NORETURN( new_mb, ACE_Message_Block( 1024 ) );
         this->reader_.read( *new_mb, new_mb->space() );
         return;
     }

     virtual void handle_write_stream(
                         const ACE_Asynch_Write_Stream::Result& result )
     {
         result.message_block().release();
         return;
     }
};

int main( int argc, ACE_TCHAR *argv[] )
{
     TTYService service;
     service.openTTY();

     int success = ACE_Proactor::instance()->run_event_loop(
                                                 ACE_Time_Value( 20, 0 ) );
     return 0;
}

-- 
Używam klienta poczty Opera



More information about the Ace-users mailing list