KDECore
kvmallocator.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <unistd.h>
00029 #include <sys/mman.h>
00030
00031 #include <qintdict.h>
00032 #include <qmap.h>
00033
00034 #include <ktempfile.h>
00035 #include <kdebug.h>
00036
00037 #include "kvmallocator.h"
00038
00039
00040 #define KVM_ALIGN 4095
00041
00042 struct KVMAllocator::Block
00043 {
00044 off_t start;
00045 size_t length;
00046 size_t size;
00047 void *mmap;
00048 };
00049
00050
00051 class KVMAllocatorPrivate
00052 {
00053 public:
00054 KTempFile *tempfile;
00055 off_t max_length;
00056 QMap<off_t, KVMAllocator::Block> used_blocks;
00057 QMap<off_t, KVMAllocator::Block> free_blocks;
00058 };
00059
00063 KVMAllocator::KVMAllocator()
00064 {
00065 d = new KVMAllocatorPrivate;
00066 d->tempfile = 0;
00067 d->max_length = 0;
00068 }
00069
00073 KVMAllocator::~KVMAllocator()
00074 {
00075 delete d->tempfile;
00076 delete d;
00077 }
00078
00083 KVMAllocator::Block *
00084 KVMAllocator::allocate(size_t _size)
00085 {
00086 if (!d->tempfile)
00087 {
00088 d->tempfile = new KTempFile(QString::null, "vmdata");
00089 d->tempfile->unlink();
00090 }
00091
00092 QMap<off_t,KVMAllocator::Block>::iterator it;
00093 it = d->free_blocks.begin();
00094 while (it != d->free_blocks.end())
00095 {
00096 if (it.data().size > _size)
00097 {
00098 Block &free_block = it.data();
00099 Block block;
00100 kdDebug(180)<<"VM alloc: using block from free list "<<(long)free_block.start<<" size ="<<(long)free_block.size<<" request = "<<_size<< endl;
00101 block.start = free_block.start;
00102 block.length = _size;
00103 block.size = (_size + KVM_ALIGN) & ~KVM_ALIGN;
00104 block.mmap = 0;
00105 free_block.size -= block.size;
00106 free_block.start += block.size;
00107 if (!free_block.size)
00108 d->free_blocks.remove(it);
00109 it = d->used_blocks.replace(block.start, block);
00110 return &(it.data());
00111 }
00112 ++it;
00113 }
00114
00115
00116
00117 Block block;
00118 block.start = d->max_length;
00119 block.length = _size;
00120 block.size = (_size + KVM_ALIGN) & ~KVM_ALIGN;
00121 block.mmap = 0;
00122 kdDebug(180)<<"VM alloc: using new block "<<(long)block.start<<" size ="<<(long)block.size<<" request = "<<_size<< endl;
00123 it = d->used_blocks.replace(block.start, block);
00124 d->max_length += block.size;
00125 return &(it.data());
00126 }
00127
00131 void
00132 KVMAllocator::free(Block *block_p)
00133 {
00134 Block block = *block_p;
00135 if (block.mmap)
00136 {
00137 kdDebug(180)<<"VM free: Block "<<(long)block.start<<" is still mmapped!"<<endl;
00138 return;
00139 }
00140 QMap<off_t,KVMAllocator::Block>::iterator it;
00141 it = d->used_blocks.find(block.start);
00142 if (it == d->used_blocks.end())
00143 {
00144 kdDebug(180)<<"VM free: Block "<<(long)block.start<<" is not allocated."<<endl;
00145 return;
00146 }
00147 d->used_blocks.remove(it);
00148 it = d->free_blocks.replace(block.start, block);
00149 QMap<off_t,KVMAllocator::Block>::iterator before = it;
00150 --before;
00151 if (before != d->free_blocks.end())
00152 {
00153 Block &block_before = before.data();
00154 if ((block_before.start + off_t(block_before.size)) == block.start)
00155 {
00156
00157 kdDebug(180) << "VM merging: Block "<< (long)block_before.start<<
00158 " with "<< (long)block.start<< " (before)" << endl;
00159 block.size += block_before.size;
00160 block.start = block_before.start;
00161 it.data() = block;
00162 d->free_blocks.remove(before);
00163 }
00164 }
00165
00166 QMap<off_t,KVMAllocator::Block>::iterator after = it;
00167 ++after;
00168 if (after != d->free_blocks.end())
00169 {
00170 Block &block_after = after.data();
00171 if ((block.start + off_t(block.size)) == block_after.start)
00172 {
00173
00174 kdDebug(180) << "VM merging: Block "<< (long)block.start<<
00175 " with "<< (long)block_after.start<< " (after)" << endl;
00176 block.size += block_after.size;
00177 it.data() = block;
00178 d->free_blocks.remove(after);
00179 }
00180 }
00181 }
00182
00186 void
00187 KVMAllocator::copy(void *dest, Block *src, int _offset, size_t length)
00188 {
00189 (void) copyBlock(dest, src, _offset, length);
00190 }
00191
00192 bool
00193 KVMAllocator::copyBlock(void *dest, Block *src, int _offset, size_t length)
00194 {
00195
00196 lseek(d->tempfile->handle(), src->start+_offset, SEEK_SET);
00197 if (length == 0)
00198 length = src->length - _offset;
00199 int to_go = length;
00200 int done = 0;
00201 char *buf = (char *) dest;
00202 while(to_go > 0)
00203 {
00204 int n = read(d->tempfile->handle(), buf+done, to_go);
00205 if (n <= 0)
00206 {
00207 if (n < 0)
00208 return false;
00209 else
00210 return true;
00211 }
00212 done += n;
00213 to_go -= n;
00214 }
00215
00216 return true;
00217 }
00218
00222 void
00223 KVMAllocator::copy(Block *dest, void *src, int _offset, size_t length)
00224 {
00225 (void) copyBlock(dest, src, _offset, length);
00226 }
00227
00228 bool
00229 KVMAllocator::copyBlock(Block *dest, void *src, int _offset, size_t length)
00230 {
00231
00232 lseek(d->tempfile->handle(), dest->start+_offset, SEEK_SET);
00233 if (length == 0)
00234 length = dest->length - _offset;
00235 int to_go = length;
00236 int done = 0;
00237 char *buf = (char *) src;
00238 while(to_go > 0)
00239 {
00240 int n = write(d->tempfile->handle(), buf+done, to_go);
00241 if (n <= 0) return false;
00242 done += n;
00243 to_go -= n;
00244 }
00245
00246 return true;
00247 }
00248
00252 void *
00253 KVMAllocator::map(Block *block)
00254 {
00255 if (block->mmap)
00256 return block->mmap;
00257
00258 void *result = mmap(0, block->length, PROT_READ| PROT_WRITE,
00259 MAP_SHARED, d->tempfile->handle(), block->start);
00260 block->mmap = result;
00261 return block->mmap;
00262 }
00263
00267 void
00268 KVMAllocator::unmap(Block *block)
00269 {
00270
00271
00272 munmap((char *)block->mmap, block->length);
00273 block->mmap = 0;
00274 }