diff --git a/programs/develop/ktcc/trunk/libc.obj/samples/build_all.sh b/programs/develop/ktcc/trunk/libc.obj/samples/build_all.sh index fb6e57cf7..236637699 100644 --- a/programs/develop/ktcc/trunk/libc.obj/samples/build_all.sh +++ b/programs/develop/ktcc/trunk/libc.obj/samples/build_all.sh @@ -23,5 +23,7 @@ cp clayer/logo.png /tmp0/1/tcc_samples/logo.png ../tcc defgen.c -o /tmp0/1/tcc_samples/defgen ../tcc pipe.c -o /tmp0/1/tcc_samples/pipe ../tcc futex.c -o /tmp0/1/tcc_samples/futex +../tcc malloc_test.c -o /tmp0/1/tcc_samples/malloc_test +../tcc atexit_test.c -o /tmp0/1/tcc_samples/atexit_test "/sys/File managers/Eolite" /tmp0/1/tcc_samples exit diff --git a/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c b/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c index a90d3c618..95c3c3442 100644 --- a/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c +++ b/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c @@ -4,23 +4,28 @@ #include #include "../source/stdlib/_mem.h" -#define RUN_TEST(func) \ - do { \ - printf("---\tRUN TEST: %s\t---\n", #func); \ - if (func()) { \ +#define RUN_TEST(func) \ + do { \ + printf("---\tRUN TEST: %s\t---\n", #func); \ + if (func()) { \ printf("[SUCCESS]\tTest %s is ok.\n\n", #func); \ - } else { \ + } else { \ printf("[FAIL]\tTest %s failed.\n\n", #func); \ - exit(EXIT_FAILURE); \ - } \ + exit(EXIT_FAILURE); \ + } \ } while (0) // c behind a and b -#define IN_RANGE(a, b, c) (a > c && c > b) +#define IN_RANGE(a, b, c, len) ((a > c && c > b) || ((a > c + len && c + len > b))) bool test_malloc_basic_allocation() { - return malloc(sizeof(int)); + void* ptr = malloc(sizeof(int)); + + if (ptr) + free(ptr); + + return ptr; } bool test_malloc_zero_bytes() { @@ -29,37 +34,46 @@ bool test_malloc_zero_bytes() bool test_malloc_multiple_allocations() { - void* ptr[1024]; + void* ptr[512]; for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) { ptr[i] = malloc(i); if (ptr[i] == NULL) { - printf("fail alloc %d bytes\n", i); return false; } } for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) { - for (int j = i + 1; j < sizeof(ptr) / sizeof(*ptr) - i - 1; j++) { - if (ptr[i] == ptr[j]) { - printf("ptrs[%d] == ptrs[%d].\n", i, j); - return false; - } else if (IN_RANGE( - GET_MEM_NODE_HEADER(ptr[i])->size + (char*)GET_MEM_NODE_HEADER(ptr[i]), - (char*)ptr[i], - (char*)GET_MEM_NODE_HEADER(ptr[j]))) { - printf("node %p in node %p", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[j])); - // additional info - printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[i])->size, GET_MEM_NODE_HEADER(ptr[i])->free, GET_MEM_NODE_HEADER(ptr[i])->next, GET_MEM_NODE_HEADER(ptr[i])->last); - printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[j]), GET_MEM_NODE_HEADER(ptr[j])->size, GET_MEM_NODE_HEADER(ptr[j])->free, GET_MEM_NODE_HEADER(ptr[j])->next, GET_MEM_NODE_HEADER(ptr[j])->last); - exit(EXIT_FAILURE); + for (int j = 1; j < sizeof(ptr) / sizeof(*ptr); j++) { + if (i != j) { + if (ptr[i] == ptr[j]) { + printf("ptrs[%d] == ptrs[%d].\n", i, j); + return false; + } else if (IN_RANGE( + (char*)GET_MEM_NODE_HEADER(ptr[i]) + GET_MEM_NODE_HEADER(ptr[i])->size, + (char*)GET_MEM_NODE_HEADER(ptr[i]), + (char*)GET_MEM_NODE_HEADER(ptr[j]), + GET_MEM_NODE_HEADER(ptr[j])->size)) { + printf("node %p in node %p", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[j])); + // additional info + printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[i])->size, GET_MEM_NODE_HEADER(ptr[i])->free, GET_MEM_NODE_HEADER(ptr[i])->next, GET_MEM_NODE_HEADER(ptr[i])->last); + printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[j]), GET_MEM_NODE_HEADER(ptr[j])->size, GET_MEM_NODE_HEADER(ptr[j])->free, GET_MEM_NODE_HEADER(ptr[j])->next, GET_MEM_NODE_HEADER(ptr[j])->last); + exit(EXIT_FAILURE); + } } } } + for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) { + free(ptr[i]); + } + return true; } bool test_malloc_data_integrity() { + const char* As = "AAA"; + const char* Cs = "CCC"; + char* A = (char*)malloc(10); char* B = (char*)malloc(10); char* C = (char*)malloc(10); @@ -72,18 +86,18 @@ bool test_malloc_data_integrity() return false; } - strcpy(A, "AAA"); - strcpy(C, "CCC"); + strcpy(A, As); + strcpy(C, Cs); free(B); - if (strcmp(A, "AAA") != 0) { + if (strcmp(A, As) != 0) { printf("A data is broken after free(B). A = '%s'\n", A); free(A); free(C); return false; } - if (strcmp(C, "CCC") != 0) { + if (strcmp(C, Cs) != 0) { printf("C data is broken after free(B). C = '%s'\n", C); free(A); free(C); @@ -96,7 +110,12 @@ bool test_malloc_data_integrity() } bool test_malloc_large_allocation() { - return malloc(1024 * 1024 * 8); // alloc 4mb + void* ptr = malloc(1024 * 1024 * 16); // alloc 16mb + + if (ptr) + free(ptr); + + return ptr; } bool test_malloc_allocation_and_free() { @@ -104,6 +123,160 @@ bool test_malloc_allocation_and_free() return true; } +void fill_buffer(void *ptr, size_t size, unsigned char pattern) { + if (ptr) { + memset(ptr, pattern, size); + } +} + +bool check_buffer(void *ptr, size_t size, unsigned char pattern) { + if (!ptr) { + return false; // Нельзя проверить NULL + } + unsigned char *byte_ptr = (unsigned char *)ptr; + for (size_t i = 0; i < size; ++i) { + if (byte_ptr[i] != pattern) { + fprintf(stderr, "Ошибка: Байт %zu не соответствует паттерну. Ожидалось %02X, получено %02X\n", + i, pattern, byte_ptr[i]); + return false; + } + } + return true; +} + +bool test_realloc_basic_grow() { + size_t old_size = 10; + size_t new_size = 20; + int *ptr = (int *)malloc(old_size * sizeof(int)); + + if (ptr == NULL) { + return false; + } + fill_buffer(ptr, old_size * sizeof(int), 0xAA); + + int *new_ptr = (int *)realloc(ptr, new_size * sizeof(int)); + + if (new_ptr == NULL) { + free(ptr); // Оригинальный блок все еще действителен + return false; + } + + // Проверяем, что старые данные сохранились + if (!check_buffer(new_ptr, old_size * sizeof(int), 0xAA)) { + free(new_ptr); + return false; + } + + // Проверяем, что новый участок доступен для записи + fill_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB); + if (!check_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB)) { + free(new_ptr); + return false; + } + + free(new_ptr); + return true; +} + +bool test_realloc_basic_shrink() { + size_t old_size = 20; + size_t new_size = 10; + int *ptr = (int *)malloc(old_size * sizeof(int)); + + if (ptr == NULL) { + return false; + } + fill_buffer(ptr, old_size * sizeof(int), 0xCC); + + int *new_ptr = (int *)realloc(ptr, new_size * sizeof(int)); + + if (new_ptr == NULL) { + free(ptr); + return false; + } + + if (!check_buffer(new_ptr, new_size * sizeof(int), 0xCC)) { + free(new_ptr); + return false; + } + + free(new_ptr); + return true; +} + +bool test_realloc_same_size() { + size_t size = 15; + int *ptr = (int *)malloc(size * sizeof(int)); + + if (ptr == NULL) { + return false; + } + fill_buffer(ptr, size * sizeof(int), 0xDD); + + int *new_ptr = (int *)realloc(ptr, size * sizeof(int)); + + if (new_ptr == NULL) { + free(ptr); + return false; + } + + // Проверяем, что данные сохранились + if (!check_buffer(new_ptr, size * sizeof(int), 0xDD)) { + free(new_ptr); + return false; + } + + free(new_ptr); + + return true; +} + +bool test_realloc_null_ptr() { + size_t size = 25; + void *ptr = realloc(NULL, size); + + if (ptr == NULL) { + return false; + } + + // Проверяем, что память доступна + fill_buffer(ptr, size, 0xEE); + if (!check_buffer(ptr, size, 0xEE)) { + free(ptr); + return false; + } + + free(ptr); + + return true; +} + +bool test_realloc_to_zero_size() { + size_t old_size = 30; + void *ptr = malloc(old_size); + + if (ptr == NULL) { + return false; + } + fill_buffer(ptr, old_size, 0xFF); + + void *new_ptr = realloc(ptr, 0); + + // Стандарт C11 (7.22.3.5) говорит, что realloc(ptr, 0) может вернуть NULL + // или указатель, который можно передать free(). + // Если возвращается NULL, оригинальный указатель ptr все еще действителен и должен быть освобожден. + // Если возвращается не-NULL, оригинальный ptr недействителен, а новый ptr должен быть освобожден. + if (new_ptr == NULL) { + printf("realloc(ptr, 0) return NULL.\n"); + free(ptr); // Освобождаем оригинальный ptr + } else { + printf("realloc(ptr, 0) return: %p.\n", new_ptr); + free(new_ptr); // Освобождаем новый ptr + } + return true; +} + + int main() { RUN_TEST(test_malloc_basic_allocation); @@ -112,6 +285,12 @@ int main() RUN_TEST(test_malloc_data_integrity); RUN_TEST(test_malloc_large_allocation); RUN_TEST(test_malloc_basic_allocation); + RUN_TEST(test_malloc_allocation_and_free); + RUN_TEST(test_realloc_basic_grow); + RUN_TEST(test_realloc_basic_shrink); + RUN_TEST(test_realloc_same_size); + RUN_TEST(test_realloc_null_ptr); + RUN_TEST(test_realloc_to_zero_size); return 0; } \ No newline at end of file diff --git a/programs/develop/ktcc/trunk/libc.obj/source/Tupfile.lua b/programs/develop/ktcc/trunk/libc.obj/source/Tupfile.lua index d0f566055..1782dd9eb 100755 --- a/programs/develop/ktcc/trunk/libc.obj/source/Tupfile.lua +++ b/programs/develop/ktcc/trunk/libc.obj/source/Tupfile.lua @@ -2,13 +2,6 @@ if tup.getconfig("NO_TCC") ~= "" then return end -function AddPrefix(prefix, t) - for i, v in pairs(t) do - t[i] = prefix .. v - end - return t -end - CC = "kos32-tcc" CFLAGS = " -r -nostdinc -nostdlib -DGNUC -D_BUILD_LIBC -Wall -Werror" @@ -43,6 +36,10 @@ GAS_SRC = { "string/memmove.s", } +FASM_SRC = { + "crt/crt0.asm", +} + LIBC_OBJS = { "libc.c" } tup.append_table(LIBC_OBJS, tup.foreach_rule(GAS_SRC, "as --32 %f -o %o", "%B.o")) @@ -50,8 +47,4 @@ tup.append_table(LIBC_OBJS, tup.foreach_rule(GAS_SRC, "as --32 %f -o %o", "%B.o" tup.rule(LIBC_OBJS, CC .. CFLAGS .. INCLUDES .. " %f -o %o " .. " && strip %o --strip-unneeded ", "libc.o") tup.rule("libc.o", "objconv -fcoff32 %f %o " .. tup.getconfig("KPACK_CMD"), "%B.obj") -CRT0_ASM_SRC = AddPrefix("crt/", { - "crt0.asm", -}) - -tup.rule(CRT0_ASM_SRC, "fasm %f %o", "%B.o") +tup.rule(FASM_SRC, "fasm %f %o", "%B.o") diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_exit.c b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_exit.c index 36178f0cb..aba8bbce9 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_exit.c +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_exit.c @@ -6,7 +6,7 @@ void _exit(int status) { // return error and this is not abort if (status && status != 128) { - printf("exit code: %d\n", status); + fprintf(stderr, "exit code: %d\n", status); } if (__con_is_load) { diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_mem.h b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_mem.h index 385cf6cc2..afcf74a89 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_mem.h +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/_mem.h @@ -14,6 +14,8 @@ struct mem_node { struct mem_block { size_t size; // Size of the allocated memory block. + + size_t a; // align to 8bytes }; // Macro to get a pointer to the user data area from a mem_node pointer. @@ -32,13 +34,39 @@ struct mem_block { // Macro to check if two adjacent memory nodes are in the same block. // Checks if the end of the left node's allocated space is the start of the right node. -#define MEM_NODES_ARE_IN_ONE_BLOCK(left, right) (GET_MEM_NODE_PTR(left) + left->size == (char*)right) +#define MEM_NODES_ARE_IN_ONE_BLOCK(left, right) (GET_MEM_NODE_PTR(left) + ((struct mem_node*)left)->size == (char*)right) -// Size of the blocks allocated at a time. +// Size of the blocks allocated by `_ksys_alloc` #define ALLOC_BLOCK_SIZE 4096 +// Macro to merge two adjacent memory nodes. +#define CHECK_SIDE_IN_OTHER_BLOCK(node, side) (side == NULL || ((side != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, side))) + +inline struct mem_node* __mem_MERGE_MEM_NODES(struct mem_node* base, struct mem_node* addition) +{ + // addition is free && nodes base and addition both in one block, else merge is impossible + if (MEM_NODE_IS_FREE(addition) && MEM_NODES_ARE_IN_ONE_BLOCK(base, addition)) { + // just change size + const size_t s = addition->size + sizeof(struct mem_node); + base->size += s; + base->free += s; + + // and delete addition from list + if (addition->next != NULL) { + addition->next->last = base; + base->next = addition->next; + } else { + base->next = NULL; + } + return base; + } + return NULL; +} + // Static pointer to the first memory node in the linked list. // This acts as the head of the memory pool. static struct mem_node* __mem_node = NULL; +static struct mem_node* __last_biggest_mem_node = NULL; + #endif // _LIBC_STDLIB_MEM_ diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/abort.c b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/abort.c index 32921e23a..884da55d4 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/abort.c +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/abort.c @@ -6,7 +6,7 @@ void abort() { ksys_thread_t t; _ksys_thread_info(&t, -1); - printf("\nAbort in %d\n", t.pid); + fprintf(stderr, "\nAbort in %d\n", t.pid); _exit(128); } diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/free.c b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/free.c index 3d3a9ae4f..3bf22277b 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/free.c +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/free.c @@ -3,27 +3,6 @@ #include #include "_mem.h" -// Macro to merge two adjacent memory nodes. -#define CHECK_SIDE_IN_OTHER_BLOCK(node, side) (side == NULL || ((side != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, side))) - -inline void __mem_MERGE_MEM_NODES(struct mem_node* base, struct mem_node* addition) -{ - if (MEM_NODE_IS_FREE(addition) && MEM_NODES_ARE_IN_ONE_BLOCK(base, addition)) { - // just change size - const size_t s = addition->size + sizeof(struct mem_node); - base->size += s; - base->free = base->size; - - // and delete addition from list - if (addition->next != NULL) { - addition->next->last = base; - base->next = addition->next; - } else { - base->next = NULL; - } - } -} - void free(void* ptr) { // Handle NULL pointer. @@ -36,45 +15,83 @@ void free(void* ptr) // Mark the memory node as free. node->free = node->size; + if (__last_biggest_mem_node == node) { + if (node->last) { + __last_biggest_mem_node = node->last; // anyway node will be merged with next + // and last and last will have size = last + node + next(if its free too) + } + } + // Merge with the next node if possible. if (node->next != NULL) __mem_MERGE_MEM_NODES(node, node->next); // Merge with the previous node if possible. if (node->last != NULL) - __mem_MERGE_MEM_NODES(node->last, node); + node = __mem_MERGE_MEM_NODES(node->last, node); - // If the current node is not adjacent to either the next or previous node, - // it might be a separate block that can be freed. - if ((node->next == NULL || ((node->next != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, node->next))) - && (node->last == NULL || ((node->last != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node->last, node)))) { + if (node) { - // Get a pointer to the mem_block header from the mem_node header. - struct mem_block* block = (struct mem_block*)(((char*)node) - sizeof(struct mem_block)); + // If the current node is not adjacent to either the next or previous node, + // it might be a separate block that can be freed. + if (MEM_NODE_IS_FREE(node) // check it because node maybe was merged with last + && (node->last == NULL || !MEM_NODES_ARE_IN_ONE_BLOCK(node, node->next)) + && (node->last == NULL || !MEM_NODES_ARE_IN_ONE_BLOCK(node->last, node))) { - // Check if the block size matches the node size. - if (block->size == node->size + sizeof(struct mem_block) + sizeof(struct mem_node)) { + // Get a pointer to the mem_block header from the mem_node header. + struct mem_block* block = (struct mem_block*)(((char*)node) - sizeof(struct mem_block)); - // Update the linked list pointers to remove the current node. - if (node->last != NULL) - node->last->next = node->next; + // Check if the block size matches the node size. + if (block->size == node->size + sizeof(struct mem_block) + sizeof(struct mem_node)) { - if (node->next != NULL) - node->next->last = node->last; + // Update the linked list pointers to remove the current node. + if (node->last != NULL) + node->last->next = node->next; - // Update the head of the linked list if necessary. - if (__mem_node == node) { - if (node->last != NULL) { - __mem_node = node->last; - } else if (node->next != NULL) { - __mem_node = node->next; - } else { - __mem_node = NULL; + if (node->next != NULL) + node->next->last = node->last; + + // Update the head of the linked list if necessary. + if (__mem_node == node) { + if (node->last != NULL) { + __mem_node = node->last; + } else if (node->next != NULL) { + __mem_node = node->next; + } else { + __mem_node = NULL; + } } - } - // Free the memory block using the ksys_free function. - _ksys_free(block); + struct mem_node* a = node->next; + struct mem_node* b = node->last; + + if (!a && !b) { + __last_biggest_mem_node = NULL; + } else if (a && !b) { + __last_biggest_mem_node = a; + } else if (!a && b) { + __last_biggest_mem_node = b; + } else if (a && b) { + __last_biggest_mem_node = (a->free > b->free) ? a : b; + } + + if (__last_biggest_mem_node == node) { + if (node->next && !(node->last)) { + __last_biggest_mem_node = node->next; + } else if (node->last && !(node->next)) { + __last_biggest_mem_node = node->last; + } else if (node->next && node->last) { + if (node->last->free > node->next->free) { + __last_biggest_mem_node = node->last; + } else { + __last_biggest_mem_node = node->next; + } + } + } + + // Free the memory block using the ksys_free function. + _ksys_free(block); + } } } } diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/malloc.c b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/malloc.c index b102c0ae8..bd076c6c4 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/malloc.c +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/malloc.c @@ -2,48 +2,74 @@ #include #include #include +#include #include "_mem.h" // Macro to align a value to a specified alignment. // Ensures that the allocated memory is aligned to a certain boundary (e.g., 16 bytes). #define __mem_align(value, align) ((value + align - 1) & ~(align - 1)) -void* malloc(size_t size) +static struct mem_node* __new_mem_node_from_exist(struct mem_node* current_node, size_t size, bool* from_empty_node) { - // Handle zero-size allocation. - if (size == 0) { - return NULL; - } - - // Align the size to 16 bytes. - size = __mem_align(size, 16); - - struct mem_node* current_node = __mem_node; // Start at the head of the linked list. - struct mem_node* new_node = NULL; // Pointer to the new node that will be created. - - // Iterate through the linked list of memory nodes. - while (current_node != NULL) { - // Check if the current node has enough free space for the requested size. - if (size + sizeof(struct mem_node) <= current_node->free) { + struct mem_node* new_node = NULL; + // Check if the current node has enough free space for the requested size. + if (size + sizeof(struct mem_node) <= current_node->free) { + *from_empty_node = MEM_NODE_IS_FREE(current_node); + if (*from_empty_node) { + new_node = current_node; + } else { // Calculate the used memory in current node const size_t s = GET_MEM_NODE_USED_MEM(current_node); // Create a new memory node after the current node's used space. new_node = (struct mem_node*)(GET_MEM_NODE_PTR(current_node) + s); - // Set the size of the new node. - new_node->size = current_node->free - sizeof(struct mem_node); - // Update current node's size current_node->size = s; + // Set the size of the new node. + // for new node give all free space in current node + new_node->size = current_node->free - sizeof(struct mem_node); + // Mark current node as used. current_node->free = 0; - - break; // Found a suitable node, exit the loop. } - current_node = current_node->next; // Move to the next node in the list. + } + return new_node; +} + +void* malloc(size_t size) +{ + char b[32]; + + // Handle zero-size allocation. + if (size == 0) { + return NULL; + } + + // Align the size to 8 bytes. + size = __mem_align(size, 8); + + struct mem_node* current_node = NULL; + struct mem_node* new_node = NULL; // Pointer to the new node that will be created. + bool from_empty_node = false; + + if (__last_biggest_mem_node != NULL) + new_node = __new_mem_node_from_exist(__last_biggest_mem_node, size, &from_empty_node); // try find free space in last created node + + // if cant find in __last_biggest_mem_node + if (new_node == NULL) { + current_node = __mem_node; // Start at the head of the linked list. + + // Iterate through the linked list of memory nodes. + while (current_node != NULL) { + new_node = __new_mem_node_from_exist(current_node, size, &from_empty_node); + if (new_node) + break; // Found a suitable node, exit the loop. + + current_node = current_node->next; // Move to the next node in the list. + } } // If no suitable node was found in the existing list: @@ -60,6 +86,8 @@ void* malloc(size_t size) return NULL; // Return NULL to indicate allocation failure. } + block->size = s; + // Create a new memory node after the mem_block header. new_node = (struct mem_node*)(block + sizeof(struct mem_block)); @@ -70,22 +98,24 @@ void* malloc(size_t size) // Set the free space in the new node. new_node->free = new_node->size - size; - // Set the last pointer of the new node to the current node. - new_node->last = current_node; + if (!from_empty_node) { + // Set the last pointer of the new node to the current node. + new_node->last = current_node; - // Link the new node into the linked list. - if (current_node != NULL) { - // Set the next pointer of the current node to the new node. - new_node->next = current_node->next; + // Link the new node into the linked list. + if (current_node != NULL) { + // Set the next pointer of the current node to the new node. + new_node->next = current_node->next; - // Update the last pointer of the next node, if it exists. - if (current_node->next != NULL) { - current_node->next->last = new_node; + // Update the last pointer of the next node, if it exists. + if (current_node->next != NULL) { + current_node->next->last = new_node; + } + current_node->next = new_node; + } else { + // If the current node is NULL, the new node is the first node in the list. + new_node->next = NULL; } - current_node->next = new_node; - } else { - // If the current node is NULL, the new node is the first node in the list. - new_node->next = NULL; } // If the linked list was empty, set the head to the new node. @@ -93,6 +123,10 @@ void* malloc(size_t size) __mem_node = new_node; } + if (__last_biggest_mem_node == NULL || new_node->free > __last_biggest_mem_node->free) { + __last_biggest_mem_node = new_node; + } + // Return a pointer to the user data area of the new node. return GET_MEM_NODE_PTR(new_node); } diff --git a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/realloc.c b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/realloc.c index f3828d804..a8ef2f9bd 100644 --- a/programs/develop/ktcc/trunk/libc.obj/source/stdlib/realloc.c +++ b/programs/develop/ktcc/trunk/libc.obj/source/stdlib/realloc.c @@ -3,33 +3,60 @@ #include #include "_mem.h" +// realloc mem. using if other ways not working +void* fail_realloc(void* ptr, size_t newsize) +{ + // Allocate a new block of memory with the new size. + void* new_ptr = malloc(newsize); + + // If both the old pointer and the new pointer are not NULL: + if (ptr != NULL && new_ptr != NULL) { + // Copy the data from the old block to the new block. + memcpy(new_ptr, ptr, min(newsize, GET_MEM_NODE_USED_MEM(GET_MEM_NODE_HEADER(ptr)))); + } + + if (ptr) { + free(ptr); // Free the old block. + } + + return new_ptr; +} + void* realloc(void* ptr, size_t newsize) { - // Handle NULL pointer. - if (ptr == NULL) - return NULL; - // Get a pointer to the mem_node header from the user data pointer. - struct mem_node* node = GET_MEM_NODE_HEADER(ptr); - void* new_ptr; + void* new_ptr = NULL; + struct mem_node* node = NULL; - // If the new size is smaller than or equal to the current size: - if (node->size >= newsize) { - // Update the free space in the current node. - node->free = node->size - newsize; - // Return the original pointer. - new_ptr = ptr; - } else { - // Allocate a new block of memory with the new size. - new_ptr = malloc(newsize); + if (ptr && newsize) { - // If both the old pointer and the new pointer are not NULL: - if (ptr != NULL && new_ptr != NULL) { - // Copy the data from the old block to the new block. - memcpy(new_ptr, ptr, min(newsize, node->size)); - // Free the old block. - free(ptr); + // Get a pointer to the mem_node header from the user data pointer. + node = GET_MEM_NODE_HEADER(ptr); + + if (node->size >= newsize) { // current node have enough mem + // it work always if newsize is smaller + // Update the free space in the current node. + node->free = node->size - newsize; + // Return the original pointer. + new_ptr = ptr; + } else if (node->next && MEM_NODE_IS_FREE(node->next) && node->size + node->next->size >= newsize) { + // So what happens here is that the node merges with the next node if their volume is sufficient. + // And a reallock is called in the hopes that the first condition will be met. + // if merge failed realloc anyway return pointer, but it will got from `fail_realloc` + // it faster than merge with last node, because its not make a copy/move + new_ptr = realloc(GET_MEM_NODE_PTR(__mem_MERGE_MEM_NODES(node, node->next)), newsize); + } else if (node->last && MEM_NODE_IS_FREE(node->last) && node->size + node->last->size >= newsize) { + struct mem_node* l = node->last; + + l = __mem_MERGE_MEM_NODES(l, node); + if (l) + memmove(GET_MEM_NODE_PTR(l), ptr, GET_MEM_NODE_USED_MEM(node)); + new_ptr = realloc(GET_MEM_NODE_PTR(l), newsize); + } else { + new_ptr = fail_realloc(ptr, newsize); } + } else { + new_ptr = fail_realloc(ptr, newsize); } // Return the new pointer.