Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/qcommon/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static int minfragment = MINFRAGMENT; // may be adjusted at runtime
static memzone_t *mainzone;
static memzone_t *smallzone;

static int mainzone_static[MAINZONE_STATIC_SIZE/sizeof(int)]; //static mainzone memory
int mainzone_static[MAINZONE_STATIC_SIZE/sizeof(int)]; //static mainzone memory
//
static const char *tagName[ TAG_COUNT ] = {
"FREE",
Expand Down
1 change: 1 addition & 0 deletions code/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
extern "C" {
#endif

extern int mainzone_static[];

typedef struct zone_stats_s {
int zoneSegments;
Expand Down
87 changes: 87 additions & 0 deletions code/tests/memory.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "memory.hxx"
#include "../qcommon/qcommon.h"
#include <algorithm>
#include <cstdlib>
#include <memory>
#include <vector>

namespace Memory {

namespace Constants {

static constexpr std::size_t kMemorySize = MAINZONE_STATIC_SIZE;
static constexpr int *kMemory = &mainzone_static[0];

}; // namespace Constants

static std::shared_ptr<int[]> currentFork = nullptr;
static std::vector<std::shared_ptr<int[]>> forks;

}; // namespace Memory

/**
* @brief Dumps current fork to memory
*/
static void DumpCurrentFork() {
if (!Memory::currentFork)
return;

const int *currentForkBegin = Memory::currentFork.get();
const int *currentForkEnd = Memory::currentFork.get() +
(Memory::Constants::kMemorySize / sizeof(int));

std::copy(currentForkBegin, currentForkEnd, Memory::Constants::kMemory);
}

/**
* @brief Loads memory content to current fork
*/
static void LoadToCurrentFork() {
if (!Memory::currentFork)
return;

const int *memoryBegin = Memory::Constants::kMemory;
const int *memoryEnd = Memory::Constants::kMemory +
(Memory::Constants::kMemorySize / sizeof(int));

std::copy(memoryBegin, memoryEnd, Memory::currentFork.get());
}

/**
* @brief Allocates and initializes new fork.
*
* @return int* - fork
*/
static std::shared_ptr<int[]> ForkFromMainzone() {
std::shared_ptr<int[]> fork(
new int[Memory::Constants::kMemorySize / sizeof(int)]);

std::copy(Memory::Constants::kMemory,
Memory::Constants::kMemory + (MAINZONE_STATIC_SIZE / sizeof(int)),
fork.get());

return fork;
}

std::size_t ForkMemory() {
// Syncronize previous fork with memory
LoadToCurrentFork();

Memory::currentFork = ForkFromMainzone();
Memory::forks.push_back(Memory::currentFork);

return Memory::forks.size() - 1;
}

void SwitchFork(std::size_t id) {
if (Memory::currentFork == Memory::forks.at(id))
return;

// Syncronize previous fork with memory
LoadToCurrentFork();

Memory::currentFork = Memory::forks[id];

// Dump newly loaded fork into memory
DumpCurrentFork();
}
20 changes: 20 additions & 0 deletions code/tests/memory.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once
#include <cstddef>

/**
* @brief Creates an independent copy of the current zone memory state and
* returns a unique fork ID. The new fork starts as an exact replica but
* evolves separately.
*
* @note Used in tests. Test group may share memory, but tests may be shuffled
* and we don't want them to corrupt each other's memory.
*
* @return std::size_t
*/
std::size_t ForkMemory();

/**
* @brief Activates the specified fork, making its memory state the current
* working context for subsequent operations.
*/
void SwitchFork(std::size_t id);
19 changes: 10 additions & 9 deletions code/tests/test_cg_superhud_configparser.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
#include <cstring>
#include "../cgame/cg_superhud_private.h"
#include "../qcommon/qcommon.h"
#include "memory.hxx"

namespace
static void shud_test_init()
{
bool initialized = false;
void shud_test_init()
{
if (initialized) return;
Com_InitZoneMemory();
CG_SHUDParserInit();
initialized = true;
}
static bool initialized = false;
static std::size_t forkId = ForkMemory();

SwitchFork(forkId);

if (initialized) return;
Com_InitZoneMemory();
CG_SHUDParserInit();
initialized = true;
}


Expand Down
13 changes: 10 additions & 3 deletions code/tests/test_osp_drawstring.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@

#include "../cgame/cg_local.h"
#include "../qcommon/qcommon.h"
#include "memory.hxx"

static void InitZoneMemory() {
static std::size_t forkId = ForkMemory();

SwitchFork(forkId);
Com_InitZoneMemory();
}

TEST_CASE("Prepare string", "[cgame][cg_drawtools.c]")
{
char out[1024];
Com_InitZoneMemory();
InitZoneMemory();

CG_OSPDrawStringPrepare("text", out, 1024);
CHECK(strncmp("text", out, 4) == 0);
Expand Down Expand Up @@ -51,7 +58,7 @@ TEST_CASE("Prepare string", "[cgame][cg_drawtools.c]")

TEST_CASE("Text compiler", "[API][cg_drawtools.c]")
{
Com_InitZoneMemory();
InitZoneMemory();
CHECK(CG_CompileText(NULL, 0) == NULL);
CHECK(CG_CompileText("", 0) == NULL);

Expand Down Expand Up @@ -332,7 +339,7 @@ TEST_CASE("Text compiler", "[API][cg_drawtools.c]")

TEST_CASE("Text compiler: bug ^^0 ", "[API][cg_drawtools.c]")
{
Com_InitZoneMemory();
InitZoneMemory();
CHECK(CG_CompileText(NULL, 0) == NULL);
CHECK(CG_CompileText("", 0) == NULL);

Expand Down
11 changes: 9 additions & 2 deletions code/tests/test_qcommon_zone_allocator.cxx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#include <catch2/catch_test_macros.hpp>

#include "../qcommon/qcommon.h"
#include "memory.hxx"

static void InitZoneMemory() {
static std::size_t forkId = ForkMemory();

SwitchFork(forkId);
Com_InitZoneMemory();
}

TEST_CASE("Test memory allocator", "[qcommon][memory][zone_allocator]")
{
Com_InitZoneMemory();
InitZoneMemory();

void *ptr = Z_Malloc(100);

Expand All @@ -16,7 +23,7 @@ TEST_CASE("Test memory allocator", "[qcommon][memory][zone_allocator]")

TEST_CASE("Test memory allocator, overflow", "[qcommon][memory][zone_allocator]")
{
Com_InitZoneMemory();
InitZoneMemory();

// too big
void *ptr1 = Z_Malloc(MAINZONE_STATIC_SIZE);
Expand Down
Loading