不明白 sbrk 是如何工作的,以及为什么我的结构无法访问

Don't understand how sbrk works and why my structure cannot be accessed

提问人:uRSs 提问时间:11/10/2023 更新时间:11/10/2023 访问量:17

问:

// SPDX-License-Identifier: BSD-3-Clause

#include "osmem.h"
#include <sys/mman.h>
#include <sys/types.h>
#include <assert.h>
#include "block_meta.h"

#define MMAP_THRESHOLD (128 * 1024)
#define METADATA_SIZE (sizeof(struct block_meta))
// #define MAP_FAILED ((void *)-1)
int first_malloc = 0;

// struct block_meta {
//     size_t size;
//     int status;
//     struct block_meta *prev;
//     struct block_meta *next;
// };

void *global_base = NULL;

// goes through the list of blocks and finds the first free block that is big enough
struct block_meta *find_free_block(struct block_meta **last, size_t size) {
    struct block_meta *current = global_base;
    while (current && !(current->status && current->size >= size)) {
        *last = current;
        current = current->next;
    }
    return current;
}

// requests space from the OS using sbrk or mmap
struct block_meta *request_space(struct block_meta *last, size_t size) {
    struct block_meta *block;

    // if size < threshold, use sbrk
    if (size < MMAP_THRESHOLD) {
        // get the beginning of the new block of memory
        block = sbrk(0);

        // allocate more memory - reduce the number of sbrk system calls
        if (first_malloc == 0)
        {
            first_malloc = 1;
            block = sbrk(MMAP_THRESHOLD);

            // ((void *)block == request);
            // if (request == MAP_FAILED) return NULL;
        }
        else
        {
            void *request = sbrk(size + METADATA_SIZE);
            assert((void *)block == request);

            if (request == MAP_FAILED) return NULL;

            if (last) {
                last->next = block;
            }
        }

        block->size = size;
        block->next = NULL;
        block->status = STATUS_ALLOC;

        return block;
    }
    else
    {
        // use mmap
        block = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        // if mappping failed, return null
        if (block == MAP_FAILED) return NULL;

        // set the next pointer of the last block to point to the newly mapped block
        if (last)
            last->next = block;

        // set the block's next to null
        block->next = NULL;
        block->status = STATUS_MAPPED;
        block->size = size;

        return block;
    }
}

void *os_malloc(size_t size) {
    struct block_meta *block;

    // allign the size of the memory to the nearest bigger multiple of 8
    int align = 8;
    int offset = size + sizeof(struct block_meta);
    int padding = -offset & (align - 1);
    int alligned_size = (offset + (align - 1)) & -align;

    // invalid size
    if (size <= 0) return NULL;

    if (!global_base) 
    {  
        // First call.
        // request space
        block = request_space(NULL, size);

        // request failed
        if (!block) return NULL;

        // set the new head of the list
        global_base = block;

        // block->status = STATUS_ALLOC;
        block->size = alligned_size;
        block->next = NULL;
    } 
    else 
    {
        struct block_meta *last = global_base;
        block = find_free_block(&last, size);

        if (!block) 
        {
            // Failed to find free block.
            block = request_space(last, size);

            // failed to request space
            if (!block) return NULL;
        } 
        else 
        {  // Found free block
                  // TODO: consider splitting block here.
            block->status = STATUS_ALLOC;
        }
    }
    return (block + 1);
}

// returns the pointer to the allocated data, not the meta data
struct block_meta *get_block_ptr(void *ptr)
{
    return (struct block_meta*)ptr - 1;
}


void os_free(void *ptr) 
{
    if (!ptr)
        return;

    struct block_meta *block_ptr = get_block_ptr(ptr);

    if (block_ptr->status == STATUS_ALLOC)
    {
        block_ptr->status = STATUS_FREE;
    }
    else
    {
        block_ptr->status = STATUS_FREE;
        munmap(block_ptr, block_ptr->size);
    }
}

void *os_calloc(size_t nmemb, size_t size) {
    /* TODO: Implement os_calloc */
    return NULL;
}

void *os_realloc(void *ptr, size_t size) {
    /* TODO: Implement os_realloc */
    return NULL;
}

我正在尝试通过我自己的 malloc 实现来了解 sbrk 和 mmap 是如何工作的。当我尝试使用 sbrk 路由遍历第一个 malloc 时,我正在预先分配更多空间,以尽量减少以后对 sbrk 函数的调用次数。这也需要更多的工作,但现在我不明白为什么当我尝试访问 block->size 或 block->next 时,我会出现 seg 错误。我认为我对 sbrk 的理解完全是垃圾:)

Ubuntu 内存 操作系统 malloc

评论


答: 暂无答案