void* HeapManager::allocBlock(unsigned char alloc_size, char type, bool protect) { assert(alloc_size <= 255); unsigned char block_size; char* ptr = getAddress(alloc_size, block_size); if (ptr == NULL) { printf("We ran out of memory\n"); exit(1); } #if DEBUG_HEAP_ALLOC printf("ALLOC %i %i\n", (int)(ptr - heap), type); #endif int next_free_block_size = 0; // I'm not at the end of heap, there is block after me if (block_size != 0) { next_free_block_size = block_size - alloc_size - HEAP_HEAD_SIZE; // if new free block would be smaller than minimum, // use whole block as is and do nothing, since we // reached other set-up block if (next_free_block_size < HEAP_MIN_BLOCK_SIZE) { alloc_size = block_size; // else create new block with new size } else { write_block_size(ptr + FULL_BLOCK_SIZE(alloc_size), (unsigned char)next_free_block_size); write_block_flags(ptr + FULL_BLOCK_SIZE(alloc_size), 0, 0, 1); } } else { write_block_size(ptr + FULL_BLOCK_SIZE(alloc_size), 0); write_block_flags(ptr + FULL_BLOCK_SIZE(alloc_size), 0, 0, 1); } write_block_size(ptr, alloc_size); write_block_flags(ptr, type, (char)(protect ? GC_PROTECTED : GC_WHITE), false); if (next_free_block == ptr) { next_free_block += FULL_BLOCK_SIZE(alloc_size); } return ptr + HEAP_HEAD_SIZE; }
void HeapManager::purgeHeap(bool force) { unsigned char block_size; char type, color; bool free; next_free_block = NULL; char* prev_block = NULL; unsigned char prev_size = 0; int p = 0; while (p < HEAP_SIZE - HEAP_HEAD_SIZE - HEAP_MIN_BLOCK_SIZE) { char* block = heap+p; read_block_size(block, block_size); if (block_size == 0) { // reached the end of used space if (next_free_block == NULL) { next_free_block = block; } if (prev_block != NULL) { write_block_size(prev_block, 0); } break; } read_block_flags(block, type, color, free); // free white blocks if (!free && (color == GC_WHITE || force)) { #if DEBUG_HEAP_ALLOC printf("DEALLOC %i\n", (int)(block - heap)); #endif switch(type) { case GC_TABLE: ((Table*) (block + HEAP_HEAD_SIZE))->~Table(); break; case GC_UPVAL: ((UpvalueRef*) (block + HEAP_HEAD_SIZE))->~UpvalueRef(); break; case GC_CLOSURE: ((Closure*) (block + HEAP_HEAD_SIZE))->~Closure(); break; case GC_STRING: ((StringObject*)(block + HEAP_HEAD_SIZE))->~StringObject(); break; case GC_NATIVE: ((Native*) (block + HEAP_HEAD_SIZE))->~Native(); break; case GC_FILE: ((File*) (block + HEAP_HEAD_SIZE))->~File(); break; default: break; } free = true; } if (!free) { write_block_flags(block, type, (char)(color == GC_PROTECTED ? GC_PROTECTED : GC_WHITE), free); prev_block = NULL; } else { if (next_free_block == NULL) { next_free_block = block; } // if possible, merge with previous free block if (prev_block != NULL && prev_size + block_size + HEAP_HEAD_SIZE <= HEAP_MAX_BLOCK_SIZE) { write_block_size(prev_block, (unsigned char)(prev_size + block_size + HEAP_HEAD_SIZE)); prev_size = (unsigned char)(prev_size + block_size + HEAP_HEAD_SIZE); // otherwise just mark block as free } else { write_block_flags(block, type, GC_WHITE, free); prev_block = block; prev_size = block_size; } } p += FULL_BLOCK_SIZE(block_size); } }
static errcode_t undo_write_tdb(io_channel channel, unsigned long long block, int count) { int size, sz; unsigned long long block_num, backing_blk_num; errcode_t retval = 0; ext2_loff_t offset; struct undo_private_data *data; TDB_DATA tdb_key, tdb_data; unsigned char *read_ptr; unsigned long long end_block; data = (struct undo_private_data *) channel->private_data; if (data->tdb == NULL) { /* * Transaction database not initialized */ return 0; } if (count == 1) size = channel->block_size; else { if (count < 0) size = -count; else size = count * channel->block_size; } /* * Data is stored in tdb database as blocks of tdb_data_size size * This helps in efficient lookup further. * * We divide the disk to blocks of tdb_data_size. */ offset = (block * channel->block_size) + data->offset ; block_num = offset / data->tdb_data_size; end_block = (offset + size) / data->tdb_data_size; tdb_transaction_start(data->tdb); while (block_num <= end_block ) { tdb_key.dptr = (unsigned char *)&block_num; tdb_key.dsize = sizeof(block_num); /* * Check if we have the record already */ if (tdb_exists(data->tdb, tdb_key)) { /* Try the next block */ block_num++; continue; } /* * Read one block using the backing I/O manager * The backing I/O manager block size may be * different from the tdb_data_size. * Also we need to recalcuate the block number with respect * to the backing I/O manager. */ offset = block_num * data->tdb_data_size; backing_blk_num = (offset - data->offset) / channel->block_size; count = data->tdb_data_size + ((offset - data->offset) % channel->block_size); retval = ext2fs_get_mem(count, &read_ptr); if (retval) { tdb_transaction_cancel(data->tdb); return retval; } memset(read_ptr, 0, count); actual_size = 0; if ((count % channel->block_size) == 0) sz = count / channel->block_size; else sz = -count; retval = io_channel_read_blk64(data->real, backing_blk_num, sz, read_ptr); if (retval) { if (retval != EXT2_ET_SHORT_READ) { free(read_ptr); tdb_transaction_cancel(data->tdb); return retval; } /* * short read so update the record size * accordingly */ tdb_data.dsize = actual_size; } else { tdb_data.dsize = data->tdb_data_size; } tdb_data.dptr = read_ptr + ((offset - data->offset) % channel->block_size); #ifdef DEBUG printf("Printing with key %lld data %x and size %d\n", block_num, tdb_data.dptr, tdb_data.dsize); #endif if (!data->tdb_written) { data->tdb_written = 1; /* Write the blocksize to tdb file */ retval = write_block_size(data->tdb, data->tdb_data_size); if (retval) { tdb_transaction_cancel(data->tdb); retval = EXT2_ET_TDB_ERR_IO; free(read_ptr); return retval; } } retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT); if (retval == -1) { /* * TDB_ERR_EXISTS cannot happen because we * have already verified it doesn't exist */ tdb_transaction_cancel(data->tdb); retval = EXT2_ET_TDB_ERR_IO; free(read_ptr); return retval; } free(read_ptr); /* Next block */ block_num++; } tdb_transaction_commit(data->tdb); return retval; }