HEX
Server: Apache/2.4.59 (Debian)
System: Linux keymana 4.19.0-21-cloud-amd64 #1 SMP Debian 4.19.249-2 (2022-06-30) x86_64
User: lijunjie (1003)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/lijunjie/swoole-cli/swoole-src-4.8.13/src/memory/global_memory.cc
/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <rango@swoole.com>                             |
  +----------------------------------------------------------------------+
*/

#include "swoole.h"
#include "swoole_memory.h"

#include <vector>
#include <mutex>

#define SW_MIN_PAGE_SIZE 4096

namespace swoole {

struct GlobalMemoryImpl {
    bool shared;
    uint32_t pagesize;
    std::mutex lock;
    std::vector<char *> pages;
    uint32_t alloc_offset;
    pid_t create_pid;

  public:
    GlobalMemoryImpl(uint32_t _pagesize, bool _shared);
    char *new_page();
};

struct MemoryBlock {
    uint32_t size;
    uint32_t reserved;
    char memory[0];
};

/**
 * After the memory is allocated,
 * it will not be released until it is recycled by OS when the process exits
 */
GlobalMemory::GlobalMemory(uint32_t pagesize, bool shared) {
    assert(pagesize >= SW_MIN_PAGE_SIZE);
    impl = new GlobalMemoryImpl(pagesize, shared);
}

GlobalMemoryImpl::GlobalMemoryImpl(uint32_t _pagesize, bool _shared) {
    shared = _shared;
    pagesize = SW_MEM_ALIGNED_SIZE_EX(_pagesize, SwooleG.pagesize);
    create_pid = SwooleG.pid;

    if (new_page() == nullptr) {
        throw std::bad_alloc();
    }
}

char *GlobalMemoryImpl::new_page() {
    char *page = (char *) (shared ? sw_shm_malloc(pagesize) : sw_malloc(pagesize));
    if (page == nullptr) {
        return nullptr;
    }

    pages.push_back(page);
    alloc_offset = 0;

    return page;
}

/**
 * The returned memory must be initialized to 0
 */
void *GlobalMemory::alloc(uint32_t size) {
    MemoryBlock *block;
    size = SW_MEM_ALIGNED_SIZE(size);
    uint32_t alloc_size = sizeof(*block) + size;
    std::unique_lock<std::mutex> lock(impl->lock);

    if (alloc_size > impl->pagesize) {
        swoole_warning("failed to alloc %d bytes, exceed the maximum size[%d]", size, impl->pagesize);
        return nullptr;
    }

    if (impl->shared and impl->create_pid != getpid()) {
        GlobalMemoryImpl *old_impl = impl;
        impl = new GlobalMemoryImpl(old_impl->pagesize, old_impl->shared);
    }

    swoole_trace("alloc_size=%u, size=%u", alloc_size, size);

    if (impl->alloc_offset + alloc_size > impl->pagesize) {
        char *page = impl->new_page();
        if (page == nullptr) {
            swoole_warning("alloc memory error");
            return nullptr;
        }
    }

    block = (MemoryBlock *) (impl->pages.back() + impl->alloc_offset);
    impl->alloc_offset += alloc_size;

    block->size = size;

    sw_memset_zero(block->memory, size);
    return block->memory;
}

void GlobalMemory::free(void *ptr) {}

void GlobalMemory::destroy() {
    for (auto page : impl->pages) {
        impl->shared ? ::sw_shm_free(page) : ::sw_free(page);
    }
}

size_t GlobalMemory::capacity() {
    return impl->pagesize - impl->alloc_offset;
}

size_t GlobalMemory::get_memory_size() {
    return impl->pagesize * impl->pages.size();
}

GlobalMemory::~GlobalMemory() {
    delete impl;
}

}  // namespace swoole