00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/cache/VMAllocator.h"
00026 #include "fennel/common/SysCallExcn.h"
00027
00028 #include <stdlib.h>
00029 #include <malloc.h>
00030
00031 #ifdef HAVE_MMAP
00032 #include <sys/resource.h>
00033 #include <sys/mman.h>
00034 #endif
00035
00036 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/cache/VMAllocator.cpp#12 $");
00037
00038 VMAllocator::VMAllocator(size_t cbAllocInit,size_t nLocked)
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
00050
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 }
00063
00064 VMAllocator::~VMAllocator()
00065 {
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 assert(!getBytesAllocated());
00079 }
00080
00081 void *VMAllocator::allocate(int *pErrorCode)
00082 {
00083 #ifdef HAVE_MMAP
00084
00085 uint cbActualAlloc = cbAlloc;
00086 #ifndef NDEBUG
00087
00088
00089
00090
00091
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 }
00150
00151 int VMAllocator::deallocate(void *p, int *pErrorCode)
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 }
00183
00184 size_t VMAllocator::getBytesAllocated() const
00185 {
00186 return nAllocs*cbAlloc;
00187 }
00188
00189 int VMAllocator::setProtection(
00190 void *pMem, uint cb, bool readOnly, int *pErrorCode)
00191 {
00192
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 }
00208
00209 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/cache/VMAllocator.cpp#12 $");
00210
00211