📄 unixsharedmemory.cpp
字号:
//// This file is part of the "More for C++" library//// Copyright (c) 1999-2003 by Thorsten Goertz (thorsten@morefor.org)//// The "More for C++" library is free software; you can redistribute it and/or// modify it under the terms of the license that comes with this package.//// Read "license.txt" for more details.//// THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES// OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.////////////////////////////////////////////////////////////////////////////////#include <more/string.hpp>#include "unixsharedmemory.hpp"using namespace more;using namespace more::os;using namespace more::os::unix_;typedef unsigned char byte;////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::Object( size_t nRootKey, size_t nObjectSize){ m_pChunkHeader = createChunk( nRootKey, nObjectSize, m_nSegmentId, m_nChunkOffset );}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::Object( const String& sObjectId): m_pChunkHeader( 0 ){ Array<String> splittedId = sObjectId.split( ',' ); if( splittedId.getLength( ) == 2 ) { splittedId[0].to( m_nSegmentId ); splittedId[1].to( m_nChunkOffset ); m_pChunkHeader = retrieveChunk( m_nSegmentId, m_nChunkOffset ); }}////////////////////////////////////////////////////////////////////////////////void UnixSharedMemory::Object::finalize( ){}////////////////////////////////////////////////////////////////////////////////bool UnixSharedMemory::Object::isValid( ) const{ return m_pChunkHeader != 0;}////////////////////////////////////////////////////////////////////////////////String UnixSharedMemory::Object::getId( ) const{ String sResult; if( isValid( ) ) { sResult = String::from( m_nSegmentId ) + ',' + String::from( m_nChunkOffset ); } return sResult;}////////////////////////////////////////////////////////////////////////////////size_t UnixSharedMemory::Object::getSize( ) const{ size_t nResult = 0; if( isValid( ) ) { nResult = m_pChunkHeader -> m_nObjectSize; } return nResult;}////////////////////////////////////////////////////////////////////////////////void* UnixSharedMemory::Object::getData( ) const{ void* pResult = 0; if( isValid( ) ) { pResult = ( m_pChunkHeader + 1 ); } return pResult;}////////////////////////////////////////////////////////////////////////////////void UnixSharedMemory::Object::destroy( ){ if( isValid( ) ) { m_pChunkHeader -> m_bInUse = false; m_pChunkHeader -> m_nObjectSize = 0; m_pChunkHeader = 0; joinChunks( retrieveSegment( m_nSegmentId ) ); }}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::ChunkHeader* UnixSharedMemory::Object::createChunk( size_t nRootKey, size_t nObjectSize, int& rnSegmentId, size_t& rnChunkOffset){ ChunkHeader* pResult = 0; SegmentHeader* pSegmentHeader = 0; SegmentHeader* pPreviousSegmentHeader = 0; pSegmentHeader = retrieveSegment( nRootKey, rnSegmentId ); while( pResult == 0 && pSegmentHeader != 0 ) { pResult = allocateChunk( pSegmentHeader, nObjectSize, rnChunkOffset ); if( pResult == 0 ) { pPreviousSegmentHeader = pSegmentHeader; pSegmentHeader = retrieveSegment( pSegmentHeader -> m_nNextSegment ); } } if( pResult == 0 ) { if( pPreviousSegmentHeader == 0 ) { pSegmentHeader = createSegment( nRootKey, 0, sizeof( ChunkHeader ) + nObjectSize, rnSegmentId ); } else { pSegmentHeader = createSegment( 0, pPreviousSegmentHeader, sizeof( ChunkHeader ) + nObjectSize, rnSegmentId ); } if( pSegmentHeader != 0 ) { pResult = allocateChunk( pSegmentHeader, nObjectSize, rnChunkOffset ); } } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::ChunkHeader* UnixSharedMemory::Object::allocateChunk( SegmentHeader* pSegmentHeader, size_t nObjectSize, size_t& rnChunkOffset){ ChunkHeader* pResult = 0; size_t nOffset = 0; size_t nMaxOffset = pSegmentHeader -> m_nSize - sizeof( SegmentHeader ); byte* pBytes = ( byte* ) ( pSegmentHeader + 1 ); while( pResult == 0 && nOffset < nMaxOffset ) { ChunkHeader* pChunkHeader = ( ChunkHeader* ) ( pBytes + nOffset ); if( pChunkHeader -> m_bInUse || sizeof( ChunkHeader ) + nObjectSize > pChunkHeader -> m_nChunkSize ) { nOffset += pChunkHeader -> m_nChunkSize; } else { pResult = splitChunk( pChunkHeader, nObjectSize ); pResult -> m_bInUse = true; pResult -> m_nObjectSize = nObjectSize; if( pResult == pChunkHeader ) { rnChunkOffset = nOffset; } else { rnChunkOffset = nOffset + pChunkHeader -> m_nChunkSize; } } } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::ChunkHeader* UnixSharedMemory::Object::retrieveChunk( int nSegmentId, size_t nChunkOffset){ ChunkHeader* pResult = 0; SegmentHeader* pSegmentHeader = retrieveSegment( nSegmentId ); if( pSegmentHeader != 0 ) { size_t nOffset = 0; size_t nMaxOffset = pSegmentHeader -> m_nSize; byte* pBytes = ( byte* ) ( pSegmentHeader + 1 ); while( pResult == 0 && nOffset < nMaxOffset && nOffset <= nChunkOffset ) { ChunkHeader* pChunkHeader = ( ChunkHeader* ) ( pBytes + nOffset ); if( pChunkHeader -> m_bInUse && nOffset == nChunkOffset ) { pResult = pChunkHeader; } else { nOffset += pChunkHeader -> m_nChunkSize; } } } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::ChunkHeader* UnixSharedMemory::Object::splitChunk( ChunkHeader* pChunkHeader, size_t nObjectSize){ ChunkHeader* pResult = pChunkHeader; size_t nChunkSize = pChunkHeader -> m_nChunkSize; if( nChunkSize > 2 * sizeof( ChunkHeader ) + nObjectSize ) { byte* pBytes = ( byte* ) pChunkHeader; size_t nRemainingSize = nChunkSize - sizeof( ChunkHeader ) - nObjectSize; nRemainingSize &= 0xFFFFFFF0; pResult = ( ChunkHeader* ) ( pBytes + nRemainingSize ); pResult -> m_nChunkSize = nChunkSize - nRemainingSize; pChunkHeader -> m_nChunkSize = nRemainingSize; } return pResult;}////////////////////////////////////////////////////////////////////////////////void UnixSharedMemory::Object::joinChunks( UnixSharedMemory::Object::SegmentHeader* pSegmentHeader){ size_t nOffset = 0; size_t nMaxOffset = pSegmentHeader -> m_nSize - sizeof( SegmentHeader ); byte* pBytes = ( byte* ) ( pSegmentHeader + 1 ); while( nOffset < nMaxOffset ) { ChunkHeader* pChunkHeader = ( ChunkHeader* ) ( pBytes + nOffset ); nOffset += pChunkHeader -> m_nChunkSize; if( !pChunkHeader -> m_bInUse ) { ChunkHeader* pTempChunkHeader = ( ChunkHeader* ) ( pBytes + nOffset ); while( nOffset < nMaxOffset && !pTempChunkHeader -> m_bInUse ) { pChunkHeader -> m_nChunkSize += pTempChunkHeader -> m_nChunkSize; nOffset += pTempChunkHeader -> m_nChunkSize; pTempChunkHeader = ( ChunkHeader* ) ( pBytes + nOffset ); } } }}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::SegmentHeader* UnixSharedMemory::Object::createSegment( size_t nSegmentKey, SegmentHeader* pPreviousSegmentHeader, size_t nSegmentSize, int& rnSegmentId){ SegmentHeader* pResult; if( nSegmentSize < 64 * 1024 ) { nSegmentSize = 64 * 1024; } pResult = allocateSegment( nSegmentKey, nSegmentSize, rnSegmentId ); if( pResult != 0 && pPreviousSegmentHeader != 0 ) { pPreviousSegmentHeader -> m_nNextSegment = rnSegmentId; } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::SegmentHeader* UnixSharedMemory::Object::allocateSegment( size_t nSegmentKey, size_t nSegmentSize, int& rnSegmentId){ SegmentHeader* pResult = 0; rnSegmentId = shmget( nSegmentKey, sizeof( SegmentHeader ) + nSegmentSize, IPC_CREAT | IPC_EXCL | 0600 ); if( rnSegmentId != -1 ) { void* pSegmentHeaderVoid = shmat( rnSegmentId, 0, 0 ); if( ( size_t ) pSegmentHeaderVoid != 0xFFFFFFFF ) { ChunkHeader* pChunkHeader; pResult = ( SegmentHeader* ) pSegmentHeaderVoid; pResult -> m_nMagic = 0x22021969; pResult -> m_nSize = sizeof( SegmentHeader ) + nSegmentSize; pResult -> m_nNextSegment = 0; pChunkHeader = ( ChunkHeader* ) ( pResult + 1 ); pChunkHeader -> m_bInUse = false; pChunkHeader -> m_nChunkSize = nSegmentSize; pChunkHeader -> m_nObjectSize = 0; } } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::SegmentHeader* UnixSharedMemory::Object::retrieveSegment( size_t nSegmentKey, int& rnSegmentId){ SegmentHeader* pResult = 0; rnSegmentId = shmget( nSegmentKey, 0, 0600 ); if( rnSegmentId != -1 ) { pResult = retrieveSegment( rnSegmentId ); } return pResult;}////////////////////////////////////////////////////////////////////////////////UnixSharedMemory::Object::SegmentHeader* UnixSharedMemory::Object::retrieveSegment( int nSegmentId){ SegmentHeader* pResult = 0; void* pSegmentHeaderVoid = shmat( nSegmentId, 0, 0 ); if( ( size_t ) pSegmentHeaderVoid != 0xFFFFFFFF ) { pResult = ( SegmentHeader* ) pSegmentHeaderVoid; if( pResult -> m_nMagic != 0x22021969 ) { shmdt( pSegmentHeaderVoid ); pResult = 0; } } return pResult;}////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -