#include <VMAllocator.h>
Inheritance diagram for VMAllocator:
Public Member Functions | |
VMAllocator (size_t cbAlloc, size_t nLocked=0) | |
Constructs a new VMAllocator. | |
virtual | ~VMAllocator () |
virtual void * | allocate (int *pErrorCode=NULL) |
Allocates a chunk of memory of size determined by the constructor. | |
virtual int | deallocate (void *pMem, int *pErrorCode=NULL) |
Deallocates a chunk of memory. | |
virtual int | setProtection (void *pMem, uint cb, bool readOnly, int *pErrorCode=NULL) |
Changes protection state for a contiguous range of virtual memory. | |
virtual size_t | getBytesAllocated () const |
| |
Private Attributes | |
size_t | cbAlloc |
size_t | nAllocs |
bool | bLockPages |
Definition at line 35 of file VMAllocator.h.
VMAllocator::VMAllocator | ( | size_t | cbAlloc, | |
size_t | nLocked = 0 | |||
) | [explicit] |
Constructs a new VMAllocator.
cbAlloc | number of bytes per allocation; all calls to allocate must specify this same value | |
nLocked | if nonzero, specifies that allocations should be locked in memory, and that no more than the specified number will be allocated at any one time |
Definition at line 38 of file VMAllocator.cpp.
References bLockPages, cbAlloc, and nAllocs.
00039 { 00040 cbAlloc = cbAllocInit; 00041 nAllocs = 0; 00042 if (nLocked) { 00043 #ifdef RLIMIT_MEMLOCK 00044 struct rlimit rl; 00045 if (::getrlimit(RLIMIT_MEMLOCK,&rl)) { 00046 throw SysCallExcn("getrlimit failed"); 00047 } 00048 if (rl.rlim_cur != RLIM_INFINITY) { 00049 // REVIEW: what if other stuff in the same process needs 00050 // locked pages? 00051 rl.rlim_cur = nLocked*cbAlloc; 00052 rl.rlim_max = nLocked*cbAlloc; 00053 if (::setrlimit(RLIMIT_MEMLOCK,&rl)) { 00054 throw SysCallExcn("setrlimit failed"); 00055 } 00056 } 00057 #endif 00058 bLockPages = true; 00059 } else { 00060 bLockPages = false; 00061 } 00062 }
VMAllocator::~VMAllocator | ( | ) | [virtual] |
Definition at line 64 of file VMAllocator.cpp.
References getBytesAllocated().
00065 { 00066 // This assertion indicates that not all allocated pages were deallocated. 00067 // In relation to LER-5976: in debug builds, each allocation is divided 00068 // into 3 sections (two guard pages surrounding the actual allocation). 00069 // The mprotect calls in allocate(int *) can fail in low memory situations 00070 // (the kernel may allocate private memory as it tracks a single mmap 00071 // region being split in three). When this occurs, subsequent munmap calls 00072 // (even on different regions) in deallocate sometimes fail, leading to a 00073 // failure of this assertion. This should not occur in release builds, 00074 // since no guard pages are allocated or protected. NOTE: On Ubuntu Edgy 00075 // Eft (2.6.17-12-generic SMP), the munmap calls in deallocate fails three 00076 // times, then inexplicably begin succeeding. Retrying the failed calls 00077 // then succeeds. 00078 assert(!getBytesAllocated()); 00079 }
void * VMAllocator::allocate | ( | int * | pErrorCode = NULL |
) | [virtual] |
Allocates a chunk of memory of size determined by the constructor.
pErrorCode | on error and if non-NULL, the int referenced is modified to contain the OS error code |
Implements CacheAllocator.
Definition at line 81 of file VMAllocator.cpp.
References bLockPages, cbAlloc, SysCallExcn::getCurrentErrorCode(), and nAllocs.
Referenced by RandomAccessFileDeviceTest::testAsyncIO().
00082 { 00083 #ifdef HAVE_MMAP 00084 00085 uint cbActualAlloc = cbAlloc; 00086 #ifndef NDEBUG 00087 // For a debug build, allocate "fence" regions before and after each 00088 // allocated buffer. This helps to catch stray pointers around buffer 00089 // boundaries. The fence size is one OS memory page, since that's 00090 // the minimum unit of protection, and also guarantees 512-byte 00091 // alignment for O_DIRECT file access. 00092 cbActualAlloc += 2*getpagesize(); 00093 #endif 00094 00095 void *v = ::mmap( 00096 NULL,cbActualAlloc, 00097 PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0); 00098 if (v == MAP_FAILED) { 00099 if (pErrorCode != NULL) { 00100 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00101 } 00102 return NULL; 00103 } 00104 00105 #ifndef NDEBUG 00106 PBuffer p = static_cast<PBuffer>(v); 00107 memset(p, 0xFE, getpagesize()); 00108 if (::mprotect(p, getpagesize(), PROT_NONE)) { 00109 if (pErrorCode != NULL) { 00110 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00111 } 00112 ::munmap(v,cbAlloc); 00113 return NULL; 00114 } 00115 p += getpagesize(); 00116 memset(p, 0xFF, cbAlloc); 00117 v = p; 00118 p += cbAlloc; 00119 memset(p, 0xFE, getpagesize()); 00120 if (::mprotect(p, getpagesize(), PROT_NONE)) { 00121 if (pErrorCode != NULL) { 00122 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00123 } 00124 ::munmap(v,cbAlloc); 00125 return NULL; 00126 } 00127 #endif 00128 00129 if (bLockPages) { 00130 if (::mlock(v,cbAlloc)) { 00131 if (pErrorCode != NULL) { 00132 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00133 } 00134 ::munmap(v,cbAlloc); 00135 return NULL; 00136 } 00137 } 00138 #else 00139 void *v = malloc(cbAlloc); 00140 if (v == NULL) { 00141 if (pErrorCode != NULL) { 00142 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00143 } 00144 return NULL; 00145 } 00146 #endif 00147 ++nAllocs; 00148 return v; 00149 }
int VMAllocator::deallocate | ( | void * | pMem, | |
int * | pErrorCode = NULL | |||
) | [virtual] |
Deallocates a chunk of memory.
pMem | the allocated memory | |
pErrorCode | on error and if non-NULL, the int referenced is modified to contain the OS error code |
Implements CacheAllocator.
Definition at line 151 of file VMAllocator.cpp.
References bLockPages, cbAlloc, free(), SysCallExcn::getCurrentErrorCode(), and nAllocs.
Referenced by RandomAccessFileDeviceTest::testAsyncIO().
00152 { 00153 #ifdef HAVE_MMAP 00154 if (bLockPages) { 00155 if (::munlock(p,cbAlloc)) { 00156 if (pErrorCode != NULL) { 00157 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00158 } 00159 return -1; 00160 } 00161 } 00162 00163 uint cbActualAlloc = cbAlloc; 00164 #ifndef NDEBUG 00165 PBuffer p2 = static_cast<PBuffer>(p); 00166 p2 -= getpagesize(); 00167 p = p2; 00168 cbActualAlloc += 2*getpagesize(); 00169 #endif 00170 if (::munmap((caddr_t)p,cbActualAlloc)) { 00171 if (pErrorCode != NULL) { 00172 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00173 } 00174 return -1; 00175 } 00176 #else 00177 free(p); 00178 #endif 00179 --nAllocs; 00180 00181 return 0; 00182 }
int VMAllocator::setProtection | ( | void * | pMem, | |
uint | cb, | |||
bool | readOnly, | |||
int * | pErrorCode = NULL | |||
) | [virtual] |
Changes protection state for a contiguous range of virtual memory.
pMem | start of range | |
cb | number of bytes in range | |
readOnly | true for read-only; false for read-write (TODO jvs 7-Feb-2006: support no-access as well) | |
pErrorCode | on error and if non-NULL, the int referenced is modified to contain the OS error code |
Implements CacheAllocator.
Definition at line 189 of file VMAllocator.cpp.
References SysCallExcn::getCurrentErrorCode().
00191 { 00192 // FIXME jvs 7-Feb-2006: use autoconf to get HAVE_MPROTECT instead 00193 #ifdef HAVE_MMAP 00194 int prot = PROT_READ; 00195 if (!readOnly) { 00196 prot |= PROT_WRITE; 00197 } 00198 if (::mprotect(pMem, cb, prot)) { 00199 if (pErrorCode != NULL) { 00200 *pErrorCode = SysCallExcn::getCurrentErrorCode(); 00201 } 00202 return -1; 00203 } 00204 #endif 00205 00206 return 0; 00207 }
size_t VMAllocator::getBytesAllocated | ( | ) | const [virtual] |
Implements CacheAllocator.
Definition at line 184 of file VMAllocator.cpp.
References cbAlloc, and nAllocs.
Referenced by ~VMAllocator().
size_t VMAllocator::cbAlloc [private] |
Definition at line 38 of file VMAllocator.h.
Referenced by allocate(), deallocate(), getBytesAllocated(), and VMAllocator().
size_t VMAllocator::nAllocs [private] |
Definition at line 39 of file VMAllocator.h.
Referenced by allocate(), deallocate(), getBytesAllocated(), and VMAllocator().
bool VMAllocator::bLockPages [private] |
Definition at line 40 of file VMAllocator.h.
Referenced by allocate(), deallocate(), and VMAllocator().