/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, or visit . ***********************************************************************/ #define WIN32_LEAN_AND_MEAN #define STRICT #include #include "SharedPool.h" #include "miniport.h" /*******************************************************************\ \*******************************************************************/ inline void* PageReserve(unsigned npages) { return VirtualAlloc(NULL, npages*4096, MEM_RESERVE, PAGE_READWRITE); } inline bool PageCommit(void* p, unsigned npages) { return !!VirtualAlloc(p, npages*4096, MEM_COMMIT, PAGE_READWRITE); } inline unsigned PageFree(void* p) { return VirtualFree(p, 0, MEM_RELEASE); } /*******************************************************************\ \*******************************************************************/ class SharedPool { char* latest_block_next_free_byte; char* latest_block_end; unsigned latest_block_index; int locked; char* blocks[18]; public: static void* Create(int _locked); void* Allocate(unsigned len); void Clear(); void Delete(); }; inline void* SharedPool::Create(int _locked) { char* block = (char*)PageReserve(1); if (!block) { return 0; } if (!PageCommit(block, 1)) { PageFree(block); return 0; } SharedPool* self = (SharedPool*)block; self->latest_block_next_free_byte = block + sizeof(SharedPool); self->latest_block_end = block + 4096; self->locked = _locked; self->blocks[0] = block; return self; } inline void* SharedPool::Allocate(unsigned len) { len = (len+3) & -4; char* alloc_end = latest_block_next_free_byte + len; if (alloc_end > latest_block_end) { // Current block isn't big enough; allocate a new one. The size of // block N is at least 4K * 2^N, to ensure that we'll run out of // virtual address space before we run out of array slots. unsigned pages_to_alloc = max((len + 4095U) >> 12, 2U << latest_block_index); char* new_block = (char*)PageReserve(pages_to_alloc); if (new_block == 0) { return 0; } latest_block_next_free_byte = new_block; latest_block_end = new_block + pages_to_alloc*4096; ++latest_block_index; blocks[latest_block_index] = new_block; alloc_end = new_block + len; } char* first_uncommitted_byte = (char*)(((unsigned)latest_block_next_free_byte + 4095) & -4096); if (alloc_end > first_uncommitted_byte) { unsigned pages_to_commit = (alloc_end - first_uncommitted_byte + 4095) >> 12; if (!PageCommit(first_uncommitted_byte, pages_to_commit)) { return 0; } } void* rtn = latest_block_next_free_byte; latest_block_next_free_byte = alloc_end; return rtn; } inline void SharedPool::Clear() { for (unsigned i=1; i<=latest_block_index; ++i) { PageFree(blocks[i]); } latest_block_next_free_byte = blocks[0] + sizeof(SharedPool); latest_block_end = blocks[0] + 4096; latest_block_index = 0; } inline void SharedPool::Delete() { for (unsigned i=1; i<=latest_block_index; ++i) { PageFree(blocks[i]); } PageFree(blocks[0]); } void* SharedPool_Create(int locked) { return SharedPool::Create(locked); } void* SharedPool_Alloc(void* self, unsigned len) { return ((SharedPool*)self)->Allocate(len); } void SharedPool_Clear(void* self) { ((SharedPool*)self)->Clear(); } void SharedPool_Delete(void* self) { ((SharedPool*)self)->Delete(); }