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 }