commit d2ed6f4dbec88868b42ec90ae6707e25a7dba95b
parent 82b49fd168f0c3c91518f68a37c9e3fd8216f049
Author: Chris Bracken <chris@bracken.jp>
Date: Sat, 22 Oct 2022 00:16:04 -0700
Extract malloc/free to memory.h
This also renames the .cc files to .c files since these no longer
include C++ code.
Diffstat:
5 files changed, 185 insertions(+), 175 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_definitions(-std=c++17)
+add_definitions(-std=c17)
set(CXX_FLAGS
"-Wall"
@@ -13,6 +13,7 @@ set(CXX_TEST_FLAGS
)
add_executable(main
- main.cc
+ main.c
+ memory.c
)
target_compile_options(main PRIVATE ${CXX_FLAGS})
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#include "memory.h"
+
+int main(int argc, char** argv) {
+ print_brk();
+ print_alloc_list();
+ printf("\n");
+
+ void *p = malloc(20);
+ printf("*** malloced a block\n");
+ print_block(p);
+ print_brk();
+ print_alloc_list();
+ printf("\n");
+
+ free(p);
+ printf("*** freed a block\n");
+ print_brk();
+ print_alloc_list();
+}
diff --git a/src/main.cc b/src/main.cc
@@ -1,173 +0,0 @@
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-struct header_t {
- size_t size;
- struct header_t *next;
- unsigned char is_free;
-};
-
-struct header_t *get_free_block(size_t size);
-void *malloc(size_t size);
-void print_brk();
-void print_header(struct header_t *header);
-void print_block(void *p);
-void print_alloc_list();
-
-static struct header_t *head, *tail;
-static pthread_mutex_t global_malloc_lock;
-
-////////////////////////////////////////////////////////////////////////
-// Implementation.
-
-/**
- * Return the first free block of at least the specified size, or nullptr if no
- * such block exists.
- */
-struct header_t *get_free_block(size_t size) {
- struct header_t *curr = head;
- while (curr) {
- if (curr->is_free && curr->size >= size)
- return curr;
- curr = curr->next;
- }
- return nullptr;
-}
-
-/**
- * Allocate a block of memory of a specific size on the heap.
- */
-void *malloc(size_t size) {
- size_t total_size;
- void *block;
- struct header_t *header;
-
- if (!size)
- return nullptr;
-
- // Check for free previously-allocated block of the right size.
- pthread_mutex_lock(&global_malloc_lock);
- header = get_free_block(size);
- if (header) {
- header->is_free = 0;
- pthread_mutex_unlock(&global_malloc_lock);
- return (void*)(header + 1);
- }
-
- // If none, allocate a new block.
- total_size = sizeof(struct header_t) + size;
- block = sbrk((int)total_size);
- if (block == (void*)(-1)) {
- pthread_mutex_unlock(&global_malloc_lock);
- return nullptr;
- }
-
- header = (struct header_t*)block;
- header->size = size;
- header->is_free = 0;
- header->next = nullptr;
- if (!head)
- head = header;
- if (tail)
- tail->next = header;
- tail = header;
- pthread_mutex_unlock(&global_malloc_lock);
- return (void*)(header + 1);
-}
-
-/**
- * Frees the specified block.
- */
-void free(void *block) {
- if (!block)
- return;
-
- pthread_mutex_lock(&global_malloc_lock);
-
- // Get block header.
- struct header_t *header = (struct header_t*)block - 1;
-
- void *program_break = sbrk(0);
- if ((char*)block + header->size == program_break) {
- // If we're the last allocated block before brk, decrement it.
- if (head == tail) {
- head = tail = nullptr;
- } else {
- for (struct header_t *p = head; p != nullptr; p = p->next) {
- if (p->next == tail) {
- p->next = nullptr;
- tail = p;
- }
- }
- }
- size_t total_size = sizeof(struct header_t) + header->size;
- sbrk(-(int)total_size);
- pthread_mutex_unlock(&global_malloc_lock);
- return;
- } else {
- // Otherwise, mark the block as free.
- header->is_free = 1;
- }
-
- pthread_mutex_unlock(&global_malloc_lock);
-}
-
-/**
- * Compute and report brk.
- */
-void print_brk() {
- void *p = sbrk(0);
- if (p == (void*)(-1))
- fprintf(stderr, "sbrk() failed\n");
- printf("brk: %p\n", p);
-}
-
-void print_header(struct header_t *header) {
- printf("hdr: %p\n", header);
- if (!header) {
- return;
- }
- printf("size: %#zx\n", header->size);
- printf("free: %s\n", header->is_free ? "true" : "false");
-}
-
-/**
- * Print the header for a block.
- */
-void print_block(void *block) {
- printf("addr: %p\n", block);
- if (!block)
- return;
- struct header_t *h = (struct header_t*)(block) - 1;
- print_header(h);
-}
-
-/**
- * Print the alloc list.
- */
-void print_alloc_list() {
- printf("== head\n");
- print_header(head);
- printf("== tail\n");
- print_header(tail);
-}
-
-int main(int argc, char** argv) {
- print_brk();
- printf("Header size is: %#zx\n", sizeof(struct header_t));
- print_alloc_list();
- printf("\n");
-
- void *p = malloc(20);
- printf("*** malloced a block\n");
- print_block(p);
- print_brk();
- print_alloc_list();
- printf("\n");
-
- free(p);
- printf("*** freed a block\n");
- print_brk();
- print_alloc_list();
-}
diff --git a/src/memory.c b/src/memory.c
@@ -0,0 +1,140 @@
+#include "memory.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// An allocation header block.
+//
+// Allocation header blocks sit immediately before the allocated pointer in
+// memory and form a linked list staring at |head| and ending at |tail|.
+struct header_t {
+ size_t size;
+ struct header_t *next;
+ unsigned char is_free;
+};
+
+static struct header_t *head, *tail;
+static pthread_mutex_t global_malloc_lock;
+
+// Returns the first free block of at least the specified size, or null if
+// no such block exists.
+static struct header_t *get_free_block(size_t size);
+
+// Print header struct debug dump.
+void print_header(struct header_t *header);
+
+static struct header_t *get_free_block(size_t size) {
+ struct header_t *curr = head;
+ while (curr) {
+ if (curr->is_free && curr->size >= size)
+ return curr;
+ curr = curr->next;
+ }
+ return NULL;
+}
+
+void *malloc(size_t size) {
+ size_t total_size;
+ void *block;
+ struct header_t *header;
+
+ if (!size)
+ return NULL;
+
+ // Check for free previously-allocated block of the right size.
+ pthread_mutex_lock(&global_malloc_lock);
+ header = get_free_block(size);
+ if (header) {
+ header->is_free = 0;
+ pthread_mutex_unlock(&global_malloc_lock);
+ return (void*)(header + 1);
+ }
+
+ // If none, allocate a new block.
+ total_size = sizeof(struct header_t) + size;
+ block = sbrk((int)total_size);
+ if (block == (void*)-1) {
+ pthread_mutex_unlock(&global_malloc_lock);
+ return NULL;
+ }
+
+ header = (struct header_t*)block;
+ header->size = size;
+ header->is_free = 0;
+ header->next = NULL;
+ if (!head)
+ head = header;
+ if (tail)
+ tail->next = header;
+ tail = header;
+ pthread_mutex_unlock(&global_malloc_lock);
+ return (void*)(header + 1);
+}
+
+void free(void *block) {
+ if (!block)
+ return;
+
+ pthread_mutex_lock(&global_malloc_lock);
+
+ // Get block header.
+ struct header_t *header = (struct header_t*)block - 1;
+
+ void *program_break = sbrk(0);
+ if ((char*)block + header->size == program_break) {
+ // If we're the last allocated block before brk, decrement it.
+ if (head == tail) {
+ head = tail = NULL;
+ } else {
+ for (struct header_t *p = head; p != NULL; p = p->next) {
+ if (p->next == tail) {
+ p->next = NULL;
+ tail = p;
+ }
+ }
+ }
+ size_t total_size = sizeof(struct header_t) + header->size;
+ sbrk(-(int)total_size);
+ pthread_mutex_unlock(&global_malloc_lock);
+ return;
+ } else {
+ // Otherwise, mark the block as free.
+ header->is_free = 1;
+ }
+
+ pthread_mutex_unlock(&global_malloc_lock);
+}
+
+void print_brk() {
+ void *p = sbrk(0);
+ if (p == (void*)(-1))
+ fprintf(stderr, "sbrk() failed\n");
+ printf("brk: %p\n", p);
+}
+
+void print_header(struct header_t *header) {
+ printf("hdr: %p\n", header);
+ printf("sizeof(hdr): %#zx\n", sizeof(struct header_t));
+ if (!header) {
+ return;
+ }
+ printf("size: %#zx\n", header->size);
+ printf("free: %s\n", header->is_free ? "true" : "false");
+}
+
+void print_block(void *block) {
+ printf("addr: %p\n", block);
+ if (!block)
+ return;
+ struct header_t *h = (struct header_t*)(block) - 1;
+ print_header(h);
+}
+
+void print_alloc_list() {
+ printf("== head\n");
+ print_header(head);
+ printf("== tail\n");
+ print_header(tail);
+}
+
diff --git a/src/memory.h b/src/memory.h
@@ -0,0 +1,21 @@
+#ifndef MEMORY_H_
+#define MEMORY_H_
+
+#include <unistd.h>
+
+// Allocate a block of memory of a specific size on the heap.
+void *malloc(size_t size);
+
+// Frees the specified block.
+void free(void *block);
+
+// Compute and write the program break to stdout.
+void print_brk();
+
+// Write debug info for a block to stdout.
+void print_block(void *p);
+
+// Write debug info for the allocations list to stdout.
+void print_alloc_list();
+
+#endif // MEMORY_H_