[Cppunit-cvs] cppunit2/src/opentest sharedmemorytransport.cpp,NONE,1.1
Brought to you by:
blep
From: Baptiste L. <bl...@us...> - 2005-06-26 21:24:39
|
Update of /cvsroot/cppunit/cppunit2/src/opentest In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16023/src/opentest Added Files: sharedmemorytransport.cpp Log Message: Intermediate comit (does not compile). Shared memory transport WIN32 implementation for TestDriver/TestRunner communication. Shared memory region has been setup. Still need to handle exchange of data using the circular buffers and related events. --- NEW FILE: sharedmemorytransport.cpp --- #include <opentest/sharedmemorytransport.h> #include <opentest/remoteinterfaces.h> #include <cpptl/thread.h> #include <tchar.h> #define WIN32_LEAN_AND_MEAN #define NOGDI #define NOUSER #define NOKERNEL #define NOSOUND #include <windows.h> /* Importance notes: * Be sure to use windows "macro" to access system access call. This ensure we can compile * the code as either unicode or ansi. Some Windows family OS only have 'unicode' system call. */ namespace OpenTest { static const DWORD magicKey = 0x43555431; static volatile unsigned int serial = 1; static CppTL::Mutex serialLock; static LPSECURITY_ATTRIBUTES setChildProcessCanInheritSecurity( SECURITY_ATTRIBUTES &saAttr ) { saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; // inherit handle saAttr.lpSecurityDescriptor = NULL; return &saAttr; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class AutoHandle // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// class AutoHandle : public CppTL::NonCopyable { public: AutoHandle( HANDLE handle = 0 ) : handle_( handle ) { } ~AutoHandle() { if ( handle_ ) ::CloseHandle( handle_ ); } operator HANDLE () const { return handle_; } AutoHandle &operator =( HANDLE handle ) { if ( handle_ ) ::CloseHandle( handle_ ); handle_ = handle; } private: HANDLE handle_; }; // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class BaseEvent // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// class BaseEvent { public: void signal() { ::SetEvent( hEvent_ ); } void reset() { ::ResetEvent( hEvent_ ); } bool isSignaled() const { return ::WaitForSingleObject( hEvent_, 0 ) == WAIT_OBJECT_0; } HANDLE get() const { return hEvent_; } protected: AutoHandle hEvent_; }; // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class NamedEvent // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// class NamedEvent : public BaseEvent { public: HANDLE create( const TCHAR *name ) { SECURITY_ATTRIBUTES sa; hEvent_ = ::CreateEvent( setChildProcessCanInheritSecurity(sa), FALSE, FALSE, name ); return get(); } }; // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class AnonymousManualEvent // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// class AnonymousManualEvent : public BaseEvent { public: AnonymousManualEvent() { SECURITY_ATTRIBUTES sa; hEvent_ = ::CreateEvent( setChildProcessCanInheritSecurity(sa), TRUE, FALSE, 0 ); } }; // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class SharedMemoryTransportImpl // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// class SharedMemoryTransportImpl { public: typedef DWORD Pos; SharedMemoryTransportImpl( const SharedMemoryConfig &config ); SharedMemoryTransportImpl( const String &transportName, const SharedMemoryConfig &config ); virtual ~SharedMemoryTransportImpl(); void send( const RemoteMessagePtr &message ); #pragma pack(push, 1) // The structure CircularBuffer & SharedData are // directly mapped to shared memory. // They should contains no C++ object (memory organization can depend on compilation options). // Name are declared from the server side point of view. // Pragma directive must be used to ensure they have the same binary // representation regarless of compilation option. struct CircularBuffer { Pos size_; Pos readPos_; // between 0 and size_ Pos writePos_; // between 0 and 2*size_ }; struct SharedData { DWORD structSize_; /// size of the SharedData struct (to detect incompatible struct due to compilation settings) DWORD magic_; HANDLE mutex_; CircularBuffer writeBuffer_; CircularBuffer readBuffer_; }; #pragma pack(pop) private: void initializeCircularBuffer( CircularBuffer &buffer ); HANDLE autoManage( HANDLE handle ); void setUpReadWriteSystemEvent(); void checkManualEvents(); void log( const char *format, ... ) {} static DWORD WINAPI threadBootstrap( void *p ); void startThread(); void stopThread(); void threadMain(); void prepareWaitObjects(); void readAndSendPendingData(); private: enum { readOperation = 0, writeOperation = 1 } typedef std::deque<RemoteMessagePtr> MessagesToSend; MessagesToSend messagesToSend_; CppTL::Mutex messagesToSendLock_ std::vector<AutoHandle> handles_; std::vector<HANDLE> waitObjects_; SharedMemoryConfig config_; NamedEvent readWriteEvents_[2]; Stream readWriteStreams_[2]; AnonymousManualEvent stopEvent_; AnonymousManualEvent sendMessageEvent_; AutoHandle hSharedMemory_; SharedData *shared_; unsigned int id_; TCHAR nameBuffer_[32]; unsigned int nameLength_; bool isConnectionCreator_; }; SharedMemoryTransportImpl::SharedMemoryTransportImpl( const SharedMemoryConfig &config ) : config_( config ) , isConnectionCreator_( true ) { { CppTL::Mutex::ScopedLockGuard guard( serialLock ); id_ = serial++; } unsigned int pid = ::GetCurrentProcessId(); nameLength_ = _tprintf( nameBuffer_, _T("cpput_%08x_%08x"), pid, id ); CPPTL_ASSERT_MESSAGE( nameLength_ < sizeof(nameBuffer_)-1, "buffer overflow" ); createSharedMemoryRegion(); setUpReadWriteSystemEvent(); checkManualEvents(); } SharedMemoryTransportImpl::SharedMemoryTransportImpl( const String &transportName, const SharedMemoryConfig &config ) : config_( config ) , isConnectionCreator_( false ) { if ( transportName.length() > sizeof(nameBuffer_)/sizeof(TCHAR)-4 ) throw SharedMemoryError( "Shared memory transport name too long." ); #ifdef _UNICODE // Use VC++ CRT extension to handle ansi->unicode conversion. nameLength_ = wprintf( nameBuffer_, L"%S", transportName.c_str() ); #else nameLength_ = sprintf( nameBuffer_, "%s", transportName.c_str() ); #endif openSharedMemoryRegion(); checkManualEvents(); } SharedMemoryTransportImpl::~SharedMemoryTransportImpl() { } void SharedMemoryTransportImpl::createSharedMemoryRegion() { SECURITY_ATTRIBUTES saAttr; setChildProcessCanInheritSecurity( saAttr ); DWORD fileMappingSize = sizeof(SharedData) + 2*config.bufferSize_; hSharedMemory_ = ::CreateFileMapping( INVALID_HANDLE_VALUE, &saAttr, // inherits handle PAGE_READWRITE, 0, // max size (hi-order) fileMappingSize, // max size (low-order) nameBuffer_ ); // name if ( hSharedMemory_ == 0 ) throw SharedMemoryError( "Failed to create shared memory region." ); setSharedMemoryRegion(); // Initialize shared memory region shared_->structSize_ = sizeof(SharedData); shared_->mutex_ = autoManage( ::CreateMutex( &saAttr, FALSE, 0 ) ); shared_->magic_ = magicKey; initializeCircularBuffer( shared_->readBuffer_ ); initializeCircularBuffer( shared_->writeBuffer_ ); if ( !shared_->mutex_ ) throw SharedMemoryError( "Failed to initialize shared memory structure (mutex creation failed)." ); } void SharedMemoryTransportImpl::openSharedMemoryRegion() { hSharedMemory_ = ::OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, nameBuffer_ ); if ( hSharedMemory_ == 0 ) throw SharedMemoryError( "Failed to open specified shared memory region." ); setSharedMemoryRegion(); } void SharedMemoryTransportImpl::setSharedMemoryRegion( HANDLE hMapFile ) { LPVOID lpMapAddress = ::MapViewOfFile( hSharedMemory_, // handle to mapping object FILE_MAP_ALL_ACCESS, // read/write permission 0, // max. object size 0, // size of hFile 0 ); // map entire file shared_ = static_cast<SharedData *>( lpMapAddress ); } void SharedMemoryTransportImpl::initializeCircularBuffer( CircularBuffer &buffer ) { buffer_.size_ = size; buffer_.readPos_ = 0; buffer_.writePos_ = 0; } HANDLE SharedMemoryTransportImpl::autoManage( HANDLE handle ) { handlers_.push_back( handle ); return handle; } void SharedMemoryTransportImpl::setUpReadWriteSystemEvent() { for ( int index = 0; index < 2; ++index ) { static const TCHAR suffixes[] = _T( "rw" ); // read/write event name suffix. nameBuffer_[nameLength_] = suffixes[index]; nameBuffer_[nameLength_+1] = 0; if ( readWriteEvents_[index].create( nameBuffer_ ) == 0 ) throw SharedMemoryError( "Failed to create named event." ); } nameBuffer_[nameLength_] = 0; } void SharedMemoryTransportImpl::checkManualEvents() { if ( stopEvent_.get() == 0 || sendMessageEvent_.get() == 0 ) throw SharedMemoryError( "Failed to creae manual events." ); } // Call to this method may come from another thread. void SharedMemoryTransportImpl::send( const RemoteMessagePtr &message ) { CppTL::Mutex::ScopedLockGuard guard( messagesToSendLock_ ); messagesToSend_.push_back( message ); } DWORD WINAPI SharedMemoryTransportImpl::threadBootstrap( void *p ) { static_cast<SharedMemoryTransportImpl *>( p )->threadMain(); return 0; } void SharedMemoryTransportImpl::startThread() { if ( !thread_ ) { DWORD threadId; thread_ = ::CreateThread( 0, 0, &SharedMemoryCommunicationManager::threadBootstrap, this, 0, &threadId ); if ( thread_ == 0 ) throw SharedMemoryError( "Failed to create thread." ); } } void SharedMemoryTransportImpl::stopThread() { if ( thread_ ) { log( "Stopping thread..." ); stopEvent_.signal(); WaitForSingleObject( thread_, INFINITE ); // join thread stopEvent_.reset(); log( "Thread stopped." ); } } void SharedMemoryTransportImpl::threadMain() { try { log( "Thread started." ); prepareWaitObjects(); while ( true ) { log( "Waiting event"); DWORD event = WaitForMultipleObjects( waitObjects_.size(), &waitObjects_[0], FALSE, INFINITE ); event -= WAIT_OBJECT_0; log( "Event signaled: %d", event ); if ( event <0 || event > waitObjects_.size() ) { if ( event + WAIT_OBJECT_0 == WAIT_TIMEOUT ) log( "timeout event !" ); else if ( event + WAIT_OBJECT_0 == WAIT_FAILED ) { System::Win32SystemError error( "wait failed" ); log( "%s", error.what() ); } else log ("abandonned event: %d!", event ); break; // timeout or abandonned event => child process died. } if ( waitObjects_[event] == stopEvent_ ) { log( "Stop event signaled !" ); break; } prepareMessageToSend(); readAndSendPendingData(); } log( "Thread stopped." ); } catch ( const std::exception &e ) { log( "thread aborted: %s", e.what() ); } catch ( ... ) { log( "thread aborted with an unspecified exception." ); } } void SharedMemoryTransportImpl::prepareWaitObjects() { waitObjects_.clear(); waitObjects_.push_back( stopEvent_.get() ); waitObjects_.push_back( sendMessageEvent_.get() ); waitObjects_.push_back( readWriteEvents_[0].get() ); waitObjects_.push_back( readWriteEvents_[1].get() ); } void SharedMemoryTransportImpl::prepareMessageToSend() { if ( !sendMessageEvent_.isSignaled() ) return; MessagesToSend messages; { CppTL::Mutex::ScopedLockGuard guard( messagesToSendLock_ ); messagesToSend.swap( messages ); } while ( !messages.empty() ) { getWriteStream().packets().beginMessage(); getWriteStream() << messages.front(); getWriteStream().packets().endMessage(); messages.pop(); } } void SharedMemoryTransportImpl::readAndSendPendingData() { // if ( readEvent().isSignaled() || writeEvent().isSignaled() } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class SharedMemoryTransport // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// SharedMemoryTransport::SharedMemoryTransport( const SharedMemoryConfig &config ) : impl_( new SharedMemoryTransportImpl( config ) ) { } SharedMemoryTransport::SharedMemoryTransport( const String &transportName, const SharedMemoryConfig &config ) : impl_( new SharedMemoryTransportImpl( transportName, config ) ) { } SharedMemoryTransport::~SharedMemoryTransport() { delete impl_; } void SharedMemoryTransport::send( const RemoteMessagePtr &message ) { impl_->send( message ); } } // namespace OpenTest |