123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #include "BlMsf.h"
- #include "BeefySysLib/MemStream.h"
- #include "../Compiler/BfAstAllocator.h"
- USING_NS_BF;
- #define MSF_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
- #define CV_BLOCK_SIZE 0x1000
- #define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) )
- //////////////////////////////////////////////////////////////////////////
- BlMsfWorkThread::BlMsfWorkThread()
- {
- mMsf = NULL;
- mDone = false;
- mSortDirty = false;
- }
- BlMsfWorkThread::~BlMsfWorkThread()
- {
- Stop();
- }
- void BlMsfWorkThread::Stop()
- {
- mDone = true;
- mWorkEvent.Set();
- WorkThread::Stop();
- }
- void BlMsfWorkThread::Run()
- {
- while (!mDone)
- {
- if (mSortedWriteBlockWorkQueue.empty())
- {
- // Only fill in new entries when our queue is empty. This is not a strong ordering guarantee.
- bool sortDirty = false;
- mCritSect.Lock();
- if (!mWriteBlockWorkQueue.empty())
- {
- sortDirty = true;
- mSortedWriteBlockWorkQueue.insert(mSortedWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.end());
- mWriteBlockWorkQueue.clear();
- }
- mCritSect.Unlock();
- BlMsfBlock* block = NULL;
- if (sortDirty)
- {
- std::sort(mSortedWriteBlockWorkQueue.begin(), mSortedWriteBlockWorkQueue.end(), [](BlMsfBlock* lhs, BlMsfBlock* rhs)
- {
- return lhs->mIdx < rhs->mIdx;
- });
- }
- }
- BlMsfBlock* block = NULL;
- if (!mSortedWriteBlockWorkQueue.empty())
- {
- block = mSortedWriteBlockWorkQueue.front();
- mSortedWriteBlockWorkQueue.pop_front();
- }
-
- if (block == NULL)
- {
- mWorkEvent.WaitFor();
- continue;
- }
-
- mMsf->WriteBlock(block);
- }
- }
- void BlMsfWorkThread::Add(BlMsfBlock* block)
- {
- AutoCrit autoCrit(mCritSect);
- mWriteBlockWorkQueue.push_back(block);
- mWorkEvent.Set();
- mSortDirty = true;
- }
- //////////////////////////////////////////////////////////////////////////
- BlMsf::BlMsf()
- {
- mCodeView = NULL;
- mBlockSize = 0x1000;
- mFreePageBitmapIdx = 1;
- mFileSize = 0;
- mAllocatedFileSize = 0;
- mWorkThread.mMsf = this;
- }
- BlMsf::~BlMsf()
- {
- for (auto block : mBlocks)
- delete block->mData;
- }
- void BlMsf::WriteBlock(BlMsfBlock* block)
- {
- if (mAllocatedFileSize > mFileSize)
- {
- mFS.SetSizeFast(mAllocatedFileSize);
- mFileSize = mAllocatedFileSize;
- }
- int wantPos = block->mIdx * CV_BLOCK_SIZE;
- if (wantPos > mFileSize)
- {
- mFS.SetSizeFast(wantPos);
- mFileSize = wantPos;
- }
- if (mFileSize == wantPos)
- mFileSize = wantPos + CV_BLOCK_SIZE;
- mFS.SetPos(block->mIdx * CV_BLOCK_SIZE);
- mFS.Write(block->mData, CV_BLOCK_SIZE);
- delete block->mData;
- block->mData = NULL;
- }
- bool BlMsf::Create(const StringImpl& fileName)
- {
- mFileName = fileName;
- //if (!mFS.Open(fileName, GENERIC_WRITE | GENERIC_READ))
- //return false;
- if (!mFS.Open(fileName, BfpFileCreateKind_CreateAlways, (BfpFileCreateFlags)(BfpFileCreateFlag_Write | BfpFileCreateFlag_Read)))
- return false;
-
- // Header
- Alloc(true, false);
-
- // First FPM block
- Alloc(true, false);
- // 'Old' FPM block
- Alloc(true, false);
-
- return true;
- }
- int BlMsf::Alloc(bool clear, bool skipFPMBlock)
- {
- int blockIdx = (int)mBlocks.size();
- BlMsfBlock* msfBlock = mBlocks.Alloc();
- msfBlock->mData = new uint8[CV_BLOCK_SIZE];
- if (clear)
- memset(msfBlock->mData, 0, CV_BLOCK_SIZE);
- msfBlock->mIdx = blockIdx;
- if ((skipFPMBlock) && ((blockIdx % CV_BLOCK_SIZE) == mFreePageBitmapIdx))
- {
- // We need this page as a Free Page Bitmap. This will be triggered once for
- // every 16MB of PDB. It should be once every 128MB but isn't because of a
- // Microsoft bug in their initial implementation.
- return Alloc();
- }
- mAllocatedFileSize = (int)(mBlocks.size() * CV_BLOCK_SIZE);
- return blockIdx;
- }
- void BlMsf::FlushBlock(int blockIdx)
- {
- if (mWorkThread.mThread == NULL)
- mWorkThread.Start();
- mWorkThread.Add(mBlocks[blockIdx]);
- }
- void BlMsf::Finish(int rootBlockNum, int streamDirLen)
- {
- mWorkThread.Stop();
- int numBlocks = (int)mBlocks.size();
- MemStream headerStream(mBlocks[0]->mData, CV_BLOCK_SIZE, false);
- headerStream.Write(MSF_SIGNATURE_700, 32);
- headerStream.Write((int32)CV_BLOCK_SIZE); // Page size
- headerStream.Write((int32)mFreePageBitmapIdx); // FreeBlockMapBlock - always use page 1. It's allowed to flip between 1 and 2.
- headerStream.Write((int32)numBlocks); // Total page count
- headerStream.Write((int32)streamDirLen);
- headerStream.Write((int32)0); // Unknown
- headerStream.Write((int32)rootBlockNum);
- // Create Free Page Bitmap
- BfBitSet bitset;
- bitset.Init(numBlocks);
- int numBytes = (numBlocks + 7) / 8;
- memset(bitset.mBits, 0xFF, numBytes);
- for (int i = 0; i < numBlocks; i++)
- bitset.Clear(i);
- // Bits are written in blocks at block nums (mFreePageBitmapIdx + k*CV_BLOCK_SIZE)
- // This is a little strange, but the actual mFreePageBitmapIdx block can only hold enough bits for
- // 128MB of pages, so PSBs over that size get spread at 'CV_BLOCK_SIZE' intervals. This is technically
- // wrong, as it should be 'CV_BLOCK_SIZE*8', but that's an Microsoft bug that can't be fixed now.
- uint8* data = (uint8*)bitset.mBits;
- int bytesLeft = numBytes;
- int curBlockNum = mFreePageBitmapIdx;
- while (bytesLeft > 0)
- {
- int writeBytes = std::min(bytesLeft, CV_BLOCK_SIZE);
- uint8* dataDest = (uint8*)mBlocks[curBlockNum]->mData;
- memcpy(dataDest, data, writeBytes);
- bytesLeft -= writeBytes;
- data += writeBytes;
- curBlockNum += CV_BLOCK_SIZE;
- }
- // Do actual write
- for (auto block : mBlocks)
- {
- if (block->mData != NULL)
- WriteBlock(block);
- }
- mFS.Close();
- }
|