[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, ¶ms );
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, ¶ms );
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, ¶ms );
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, ¶ms );
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