📄 heap.c
字号:
default: /* Old size is a fragment; type is logarithm to base two of the fragment size. */ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) /* The new size is the same kind of fragment. */ result = ptr; else { /* The new size is different; allocate a new space, and copy the lesser of the new size and the old. */ result = _fusion_shmalloc( heap, size ); if (result == NULL) return NULL; direct_memcpy (result, ptr, MIN (size, (size_t) 1 << type)); _fusion_shfree( heap, ptr ); } break; } return result;}/* Return memory to the heap. */void_fusion_shfree( shmalloc_heap *heap, void *ptr ){ int type; size_t block, blocks; register size_t i; struct list *prev, *next; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %p )\n", __FUNCTION__, heap, ptr ); D_MAGIC_ASSERT( heap, shmalloc_heap ); if (ptr == NULL) return; block = BLOCK (ptr); type = heap->heapinfo[block].busy.type; switch (type) { case 0: /* Get as many statistics as early as we can. */ heap->chunks_used--; heap->bytes_used -= heap->heapinfo[block].busy.info.size * BLOCKSIZE; heap->bytes_free += heap->heapinfo[block].busy.info.size * BLOCKSIZE; /* Find the free cluster previous to this one in the free list. Start searching at the last block referenced; this may benefit programs with locality of allocation. */ i = heap->heapindex; if (i > block) while (i > block) i = heap->heapinfo[i].free.prev; else { do i = heap->heapinfo[i].free.next; while (i > 0 && i < block); i = heap->heapinfo[i].free.prev; } /* Determine how to link this block into the free list. */ if (block == i + heap->heapinfo[i].free.size) { /* Coalesce this block with its predecessor. */ heap->heapinfo[i].free.size += heap->heapinfo[block].busy.info.size; block = i; } else { /* Really link this block back into the free list. */ heap->heapinfo[block].free.size = heap->heapinfo[block].busy.info.size; heap->heapinfo[block].free.next = heap->heapinfo[i].free.next; heap->heapinfo[block].free.prev = i; heap->heapinfo[i].free.next = block; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block; heap->chunks_free++; } /* Now that the block is linked in, see if we can coalesce it with its successor (by deleting its successor from the list and adding in its size). */ if (block + heap->heapinfo[block].free.size == heap->heapinfo[block].free.next) { heap->heapinfo[block].free.size += heap->heapinfo[heap->heapinfo[block].free.next].free.size; heap->heapinfo[block].free.next = heap->heapinfo[heap->heapinfo[block].free.next].free.next; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block; heap->chunks_free--; } blocks = heap->heapinfo[block].free.size;/* FIXME: as this is used when kernel is detected as >= 2.6.19.2 only, this fallback definition should be ok for now */#ifndef MADV_REMOVE#define MADV_REMOVE 9#endif /* Punch a hole into the tmpfs file to really free RAM. */ if (fusion_config->madv_remove) madvise( ADDRESS(block), blocks * BLOCKSIZE, MADV_REMOVE ); /* Now see if we can truncate the end. */ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == heap->heaplimit && __shmalloc_brk( heap, 0 ) == ADDRESS (block + blocks)) { register size_t bytes = blocks * BLOCKSIZE; heap->heaplimit -= blocks; __shmalloc_brk( heap, -bytes ); heap->heapinfo[heap->heapinfo[block].free.prev].free.next = heap->heapinfo[block].free.next; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = heap->heapinfo[block].free.prev; block = heap->heapinfo[block].free.prev; heap->chunks_free--; heap->bytes_free -= bytes; } /* Set the next search to begin at this block. */ heap->heapindex = block; break; default: /* Do some of the statistics. */ heap->chunks_used--; heap->bytes_used -= 1 << type; heap->chunks_free++; heap->bytes_free += 1 << type; /* Get the address of the first free fragment in this block. */ prev = (struct list *) ((char *) ADDRESS (block) + (heap->heapinfo[block].busy.info.frag.first << type));#if 1 /* Adapted from Mike */ if ((int)heap->heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 && heap->fragblocks[type] > 1)#else if ((int)heap->heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)#endif { /* If all fragments of this block are free, remove them from the fragment list and free the whole block. */#if 1 /* Adapted from Mike */ heap->fragblocks[type]--;#endif next = prev; for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) next = next->next; prev->prev->next = next; if (next != NULL) next->prev = prev->prev; heap->heapinfo[block].busy.type = 0; heap->heapinfo[block].busy.info.size = 1; /* Keep the statistics accurate. */ heap->chunks_used++; heap->bytes_used += BLOCKSIZE; heap->chunks_free -= BLOCKSIZE >> type; heap->bytes_free -= BLOCKSIZE; _fusion_shfree( heap, ADDRESS (block) ); } else if (heap->heapinfo[block].busy.info.frag.nfree != 0) { /* If some fragments of this block are free, link this fragment into the fragment list after the first free fragment of this block. */ next = (struct list *) ptr; next->next = prev->next; next->prev = prev; prev->next = next; if (next->next != NULL) next->next->prev = next; heap->heapinfo[block].busy.info.frag.nfree++; } else { /* No fragments of this block are free, so link this fragment into the fragment list and announce that it is the first free fragment of this block. */ prev = (struct list *) ptr; heap->heapinfo[block].busy.info.frag.nfree = 1; heap->heapinfo[block].busy.info.frag.first = (unsigned long int) ((unsigned long int) ((char *) ptr - (char *) NULL) % BLOCKSIZE >> type); prev->next = heap->fraghead[type].next; prev->prev = &heap->fraghead[type]; prev->prev->next = prev; if (prev->next != NULL) prev->next->prev = prev; } break; }}/**********************************************************************************************************************/DirectResult__shmalloc_init_heap( FusionSHM *shm, const char *filename, void *addr_base, int space, int *ret_fd, int *ret_size ){ DirectResult ret; int size; FusionSHMShared *shared; int heapsize = (space + BLOCKSIZE-1) / BLOCKSIZE; int fd = -1; shmalloc_heap *heap = NULL; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d, %p, %p )\n", __FUNCTION__, shm, filename, addr_base, space, ret_fd, ret_size ); D_MAGIC_ASSERT( shm, FusionSHM ); D_ASSERT( filename != NULL ); D_ASSERT( addr_base != NULL ); D_ASSERT( ret_fd != NULL ); D_ASSERT( ret_size != NULL ); shared = shm->shared; D_MAGIC_ASSERT( shared, FusionSHMShared ); D_ASSERT( shared->tmpfs[0] != 0 ); size = BLOCKALIGN(sizeof(shmalloc_heap)) + BLOCKALIGN( heapsize * sizeof(shmalloc_info) ); D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename ); /* open the virtual file */ fd = open( filename, O_RDWR | O_CREAT | O_TRUNC, 0660 ); if (fd < 0) { ret = errno2result(errno); D_PERROR( "Fusion/SHM: Could not open shared memory file '%s'!\n", filename ); goto error; } if (fusion_config->shmfile_gid != (gid_t)-1) { /* chgrp the SH_FILE dev entry */ if (fchown( fd, -1, fusion_config->shmfile_gid ) != 0) D_WARN( "Fusion/SHM: Changing owner on %s failed... continuing on.", filename ); } fchmod( fd, 0660 ); ftruncate( fd, size ); D_DEBUG_AT( Fusion_SHMHeap, " -> mmaping shared memory file... (%d bytes)\n", size ); /* map it shared */ heap = mmap( addr_base, size + space, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0 ); if (heap == MAP_FAILED) { ret = errno2result(errno); D_PERROR( "Fusion/SHM: Could not mmap shared memory file '%s'!\n", filename ); goto error; } if (heap != addr_base) { D_ERROR( "Fusion/SHM: mmap() returned address (%p) differs from requested (%p)\n", heap, addr_base ); ret = DFB_FUSION; goto error; } D_DEBUG_AT( Fusion_SHMHeap, " -> done.\n" ); heap->size = size; heap->heapsize = heapsize; heap->heapinfo = (void*) heap + BLOCKALIGN(sizeof(shmalloc_heap)); heap->heapbase = (char*) heap->heapinfo; D_MAGIC_SET( heap, shmalloc_heap ); *ret_fd = fd; *ret_size = size; return DFB_OK;error: if (heap) munmap( heap, size ); if (fd != -1) { close( fd ); unlink( filename ); } return ret;}DirectResult__shmalloc_join_heap( FusionSHM *shm, const char *filename, void *addr_base, int size, int *ret_fd ){ DirectResult ret; FusionSHMShared *shared; int fd = -1; shmalloc_heap *heap = NULL; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d, %p )\n", __FUNCTION__, shm, filename, addr_base, size, ret_fd ); D_MAGIC_ASSERT( shm, FusionSHM ); D_ASSERT( filename != NULL ); D_ASSERT( addr_base != NULL ); D_ASSERT( size >= sizeof(shmalloc_heap) ); D_ASSERT( ret_fd != NULL ); shared = shm->shared; D_MAGIC_ASSERT( shared, FusionSHMShared ); D_ASSERT( shared->tmpfs[0] != 0 ); D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename ); /* open the virtual file */ fd = open( filename, O_RDWR ); if (fd < 0) { ret = errno2result(errno); D_PERROR( "Fusion/SHM: Could not open shared memory file '%s'!\n", filename ); goto error; } D_DEBUG_AT( Fusion_SHMHeap, " -> mmaping shared memory file... (%d bytes)\n", size ); /* map it shared */ heap = mmap( addr_base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0 ); if (heap == MAP_FAILED) { ret = errno2result(errno); D_PERROR( "Fusion/SHM: Could not mmap shared memory file '%s'!\n", filename ); goto error; } if (heap != addr_base) { D_ERROR( "Fusion/SHM: mmap() returned address (%p) differs from requested (%p)\n", heap, addr_base ); ret = DFB_FUSION; goto error; } D_MAGIC_ASSERT( heap, shmalloc_heap ); D_DEBUG_AT( Fusion_SHMHeap, " -> done.\n" ); *ret_fd = fd; return DFB_OK;error: if (heap) munmap( heap, size ); if (fd != -1) close( fd ); return ret;}void *__shmalloc_brk( shmalloc_heap *heap, int increment ){ FusionSHMShared *shm; FusionWorld *world; FusionSHMPool *pool; FusionSHMPoolShared *shared; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %d )\n", __FUNCTION__, heap, increment ); D_MAGIC_ASSERT( heap, shmalloc_heap ); shared = heap->pool; D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); shm = shared->shm; D_MAGIC_ASSERT( shm, FusionSHMShared ); world = _fusion_world( shm->world ); D_MAGIC_ASSERT( world, FusionWorld ); pool = &world->shm.pools[shared->index]; D_MAGIC_ASSERT( pool, FusionSHMPool ); if (increment) { int new_size = heap->size + increment; if (new_size > shared->max_size) { D_WARN( "maximum shared memory size exceeded!" ); fusion_dbg_print_memleaks( shared ); return NULL; } if (ftruncate( pool->fd, new_size ) < 0) { D_PERROR( "Fusion/SHM: ftruncating shared memory file failed!\n" ); return NULL; } heap->size = new_size; } return shared->addr_base + heap->size - increment;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -