diff --git a/Makefile b/Makefile index 23e1279..e91b585 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,64 @@ # Define compiler and options C_COMPILER = gcc -C_OPTIONS = -Wall -pedantic -Wextra -g +C_OPTIONS = C_LINK_OPTIONS = -lm CUNIT_LINK = -lcunit C_COVERAGE = gcov -abcfu --coverage R_COVERAGE = gcovr -r . --html --html-details -o coverage.html # Source and object files -REF = src/ref.c -REF_OBJ = src/ref.o +REF = src/refmem.c TEST_SRC = test/test.c -TEST_OBJ = test/test.o HASH = src/lib/lib_hash_table.c -HASH_OBJ = src/lib/lib_hash_table.o LIST = src/lib/lib_linked_list.c -LIST_OBJ = src/lib/lib_linked_list.o + + +# Object files +OBJ_DIR = obj +SRC_DIR = src +LIB_DIR = lib +TEST_DIR = test +REF_OBJ = $(OBJ_DIR)/refmem.o +TEST_OBJ = $(OBJ_DIR)/$(TEST_DIR)/test.o +HASH_OBJ = $(OBJ_DIR)/$(LIB_DIR)/lib_hash_table.o +LIST_OBJ = $(OBJ_DIR)/$(LIB_DIR)/lib_linked_list.o # Pattern rule to compile .c files into .o files -%.o: %.c +$(OBJ_DIR)/%.o: src/%.c + $(C_COMPILER) $(C_OPTIONS) -c $< -o $@ + +$(OBJ_DIR)/lib/%.o: src/lib/%.c + $(C_COMPILER) $(C_OPTIONS) -c $< -o $@ + +$(OBJ_DIR)/test/%.o: test/%.c $(C_COMPILER) $(C_OPTIONS) -c $< -o $@ # Target for the reference executable -ref: $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) - $(C_COMPILER) $(C_LINK_OPTIONS) $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) -o $@ $(CUNIT_LINK) +all: $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) + $(C_COMPILER) $(C_LINK_OPTIONS) $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) -o $@ $(CUNIT_LINK) run: ref - valgrind --leak-check=full --show-leak-kinds=all ./ref + valgrind --leak-check=full --show-leak-kinds=all ./refmem + +demo: + $(MAKE) -C demo run_frontend + +memdemo: + $(MAKE) -C demo full_val_frontend # Target for the test executable -ref_test: $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) - $(C_COMPILER) $(C_LINK_OPTIONS) $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) -o $@ $(CUNIT_LINK) - valgrind --leak-check=full --show-leak-kinds=all ./ref_test +test: $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) + $(C_COMPILER) $(C_LINK_OPTIONS) $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) -o $(OBJ_DIR)/test/test $(CUNIT_LINK) + $(OBJ_DIR)/test/test + $(MAKE) -C demo backend_tests + $(MAKE) -C demo run_backend_tests + +memtest: $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) + $(C_COMPILER) $(C_LINK_OPTIONS) $(REF_OBJ) $(TEST_OBJ) $(HASH_OBJ) $(LIST_OBJ) -o $(OBJ_DIR)/test/test $(CUNIT_LINK) + valgrind --leak-check=full --show-leak-kinds=all $(OBJ_DIR)/test/test + $(MAKE) -C demo backend_tests + $(MAKE) -C demo full_val_backend_tests + gdb: ref gdb ./ref --tui @@ -45,4 +73,6 @@ coverage: cov # Clean up generated files clean: - rm -f src/*.o inlupp2_DONOTTOUCH/generic_data_structures/*.o test/*.o ref* cov* test.c.* \ No newline at end of file + rm -f obj/*.o obj/*/*.o obj/test/test obj/backend_tests obj/frontend *.gcda *.gcno ref* cov* test.c.* + +.PHONY: demo all \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index c78074f..0000000 --- a/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# [Oboy] - -To run: -make ref_test -runs test suite of ref.c test.c with valgrind - -make cov -runs coverage on ref.c test.c - -Inside /src/inlupp2 - -make backend_tests -compiles inlupp 2 tests - -make full_val_backend_tests -runs compiled inlupp 2 tests with valgrind - -make ‎backend_tests_cov‎ -runs compiled inlupp 2 tests with valgrind - -make frontend -compiles frontend inlupp2 - -make full_val_frontend -runs valgrind on frontend program in inlupp2 diff --git a/all b/all new file mode 100644 index 0000000..d9b5d16 Binary files /dev/null and b/all differ diff --git a/src/inlupp2/business_logic/backend.h b/demo/business_logic/backend.h similarity index 99% rename from src/inlupp2/business_logic/backend.h rename to demo/business_logic/backend.h index 1a84a2d..8caaf15 100644 --- a/src/inlupp2/business_logic/backend.h +++ b/demo/business_logic/backend.h @@ -8,7 +8,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" /** diff --git a/src/inlupp2/business_logic/cart.c b/demo/business_logic/cart.c similarity index 99% rename from src/inlupp2/business_logic/cart.c rename to demo/business_logic/cart.c index 0c5c41b..71eff69 100644 --- a/src/inlupp2/business_logic/cart.c +++ b/demo/business_logic/cart.c @@ -10,7 +10,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" #define Successful(o) (o.success == true) #define Unsuccessful(o) (o.success == false) diff --git a/src/inlupp2/business_logic/common.c b/demo/business_logic/common.c similarity index 98% rename from src/inlupp2/business_logic/common.c rename to demo/business_logic/common.c index 01f4918..6ee3659 100644 --- a/src/inlupp2/business_logic/common.c +++ b/demo/business_logic/common.c @@ -10,7 +10,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" bool pointer_is_null(void *ptr) { diff --git a/src/inlupp2/business_logic/common.h b/demo/business_logic/common.h similarity index 100% rename from src/inlupp2/business_logic/common.h rename to demo/business_logic/common.h diff --git a/src/inlupp2/business_logic/merch.c b/demo/business_logic/merch.c similarity index 99% rename from src/inlupp2/business_logic/merch.c rename to demo/business_logic/merch.c index 2437abd..41f4257 100644 --- a/src/inlupp2/business_logic/merch.c +++ b/demo/business_logic/merch.c @@ -10,8 +10,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" - +#include "../../src/refmem.h" diff --git a/src/inlupp2/business_logic/shop.c b/demo/business_logic/shop.c similarity index 97% rename from src/inlupp2/business_logic/shop.c rename to demo/business_logic/shop.c index 4d626b4..14d29bf 100644 --- a/src/inlupp2/business_logic/shop.c +++ b/demo/business_logic/shop.c @@ -10,7 +10,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" void shop_destructor(obj *shop) { if (!shop) return; diff --git a/src/inlupp2/coverage.txt b/demo/coverage.txt similarity index 100% rename from src/inlupp2/coverage.txt rename to demo/coverage.txt diff --git a/src/inlupp2/generic_data_structures/common.h b/demo/generic_data_structures/common.h similarity index 100% rename from src/inlupp2/generic_data_structures/common.h rename to demo/generic_data_structures/common.h diff --git a/src/inlupp2/generic_data_structures/hash_table.c b/demo/generic_data_structures/hash_table.c similarity index 99% rename from src/inlupp2/generic_data_structures/hash_table.c rename to demo/generic_data_structures/hash_table.c index a0d6504..b0317a7 100644 --- a/src/inlupp2/generic_data_structures/hash_table.c +++ b/demo/generic_data_structures/hash_table.c @@ -5,7 +5,7 @@ #include #include #include "linked_list.h" -#include "../../ref.h" +#include "../../src/refmem.h" #define Success(k, v) \ (ioopm_option_t) { .success = true, .key = k, .value = v } diff --git a/src/inlupp2/generic_data_structures/hash_table.h b/demo/generic_data_structures/hash_table.h similarity index 100% rename from src/inlupp2/generic_data_structures/hash_table.h rename to demo/generic_data_structures/hash_table.h diff --git a/src/inlupp2/generic_data_structures/hash_table_tests.c b/demo/generic_data_structures/hash_table_tests.c similarity index 100% rename from src/inlupp2/generic_data_structures/hash_table_tests.c rename to demo/generic_data_structures/hash_table_tests.c diff --git a/src/inlupp2/generic_data_structures/iterator.h b/demo/generic_data_structures/iterator.h similarity index 100% rename from src/inlupp2/generic_data_structures/iterator.h rename to demo/generic_data_structures/iterator.h diff --git a/src/inlupp2/generic_data_structures/linked_list.c b/demo/generic_data_structures/linked_list.c similarity index 99% rename from src/inlupp2/generic_data_structures/linked_list.c rename to demo/generic_data_structures/linked_list.c index 5faf5b4..6d66fe9 100644 --- a/src/inlupp2/generic_data_structures/linked_list.c +++ b/demo/generic_data_structures/linked_list.c @@ -4,7 +4,7 @@ #include #include "common.h" #include -#include "../../ref.h" +#include "../../src/refmem.h" #define null_elem \ (elem_t) { 0 } diff --git a/src/inlupp2/generic_data_structures/linked_list.h b/demo/generic_data_structures/linked_list.h similarity index 100% rename from src/inlupp2/generic_data_structures/linked_list.h rename to demo/generic_data_structures/linked_list.h diff --git a/src/inlupp2/generic_data_structures/linked_list_tests.c b/demo/generic_data_structures/linked_list_tests.c similarity index 100% rename from src/inlupp2/generic_data_structures/linked_list_tests.c rename to demo/generic_data_structures/linked_list_tests.c diff --git a/src/inlupp2/generic_utils/utils.c b/demo/generic_utils/utils.c similarity index 98% rename from src/inlupp2/generic_utils/utils.c rename to demo/generic_utils/utils.c index 6e6b424..c74df12 100644 --- a/src/inlupp2/generic_utils/utils.c +++ b/demo/generic_utils/utils.c @@ -4,7 +4,7 @@ extern char *strdup(const char *); #include //för isdigit #include #include "utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" bool not_empty(char *str) { diff --git a/src/inlupp2/generic_utils/utils.h b/demo/generic_utils/utils.h similarity index 100% rename from src/inlupp2/generic_utils/utils.h rename to demo/generic_utils/utils.h diff --git a/demo/makefile b/demo/makefile new file mode 100644 index 0000000..38772c9 --- /dev/null +++ b/demo/makefile @@ -0,0 +1,117 @@ +# Define compiler and options +CC = gcc +CFLAGS = -g -Wall -pedantic -Wextra -w +LDFLAGS = -lcunit -lm +OBJ_DIR = ../obj +SRC_DIR = ../src +GEN_UTILS_DIR = generic_utils +GEN_DS_DIR = generic_data_structures +BUS_LOGIC_DIR = business_logic +TESTS_DIR = tests +UI_DIR = user_interface +LIB_DIR = ../src/lib + + + +# Source files for frontend +FRONTEND_SRC = $(UI_DIR)/frontend.c $(GEN_UTILS_DIR)/utils.c $(GEN_DS_DIR)/linked_list.c \ + $(GEN_DS_DIR)/hash_table.c $(BUS_LOGIC_DIR)/shop.c $(BUS_LOGIC_DIR)/merch.c \ + $(BUS_LOGIC_DIR)/cart.c $(BUS_LOGIC_DIR)/common.c $(SRC_DIR)/refmem.c \ + $(LIB_DIR)/lib_hash_table.c $(LIB_DIR)/lib_linked_list.c + +# Source files for backend tests +BACKEND_TEST_SRC = $(BUS_LOGIC_DIR)/common.c $(BUS_LOGIC_DIR)/shop.c $(BUS_LOGIC_DIR)/merch.c \ + $(BUS_LOGIC_DIR)/cart.c $(TESTS_DIR)/backend_tests.c $(GEN_UTILS_DIR)/utils.c \ + $(GEN_DS_DIR)/linked_list.c $(GEN_DS_DIR)/hash_table.c $(SRC_DIR)/refmem.c \ + $(LIB_DIR)/lib_hash_table.c $(LIB_DIR)/lib_linked_list.c + +# Targets +.PHONY: all clean run valgrind debug test + +all: frontend backend_tests + +# Frontend target +frontend: $(FRONTEND_SRC) | $(OBJ_DIR) + $(CC) $(CFLAGS) $^ -o $(OBJ_DIR)/frontend $(LDFLAGS) + +run_frontend: frontend + clear + ./$(OBJ_DIR)/frontend + +val_frontend: frontend + valgrind -s ./$(OBJ_DIR)/frontend + +full_val_frontend: frontend + clear + valgrind -s --leak-check=full ./$(OBJ_DIR)/frontend + +clean_frontend: + make clean; make frontend; make run_frontend + +# Backend tests target +backend_tests: $(BACKEND_TEST_SRC) | $(OBJ_DIR) + $(CC) $(CFLAGS) $^ -o $(OBJ_DIR)/backend_tests $(LDFLAGS) + +run_backend_tests: backend_tests + ./$(OBJ_DIR)/backend_tests + +val_backend_tests: backend_tests + valgrind -s ./$(OBJ_DIR)/backend_tests + +full_val_backend_tests: backend_tests + valgrind -s --leak-check=full ./$(OBJ_DIR)/backend_tests + +clean_val_backend_tests: + make clean; make backend_tests; make val_backend_tests + +test: clean_val_backend_tests + +# Debug target +debug: backend_tests + gdb ./$(OBJ_DIR)/backend_tests --tui + +# Coverage target +backend_tests_cov: $(BACKEND_TEST_SRC) | $(OBJ_DIR) + $(CC) $(CFLAGS) $^ -o $(OBJ_DIR)/backend_tests_coverage --coverage $(LDFLAGS) + +cov_run: backend_tests_cov + ./$(OBJ_DIR)/backend_tests_coverage + +gcov: + gcov -b -c $(OBJ_DIR)/backend_tests_coverage.gcda > coverage.txt + +# Old hash target +old_hash: $(GEN_DS_DIR)/hash_table.c $(GEN_DS_DIR)/linked_list.c $(GEN_DS_DIR)/hash_table_tests.c $(SRC_DIR)/refmem.c $(LIB_DIR)/lib_hash_table.c $(LIB_DIR)/lib_linked_list.c + $(CC) $(CFLAGS) $^ -o $(OBJ_DIR)/old_hash $(LDFLAGS) + valgrind -s --leak-check=full ./$(OBJ_DIR)/old_hash + +# Old list target +old_list: $(GEN_DS_DIR)/linked_list.c $(GEN_DS_DIR)/linked_list_tests.c $(SRC_DIR)/refmem.c $(LIB_DIR)/lib_hash_table.c $(LIB_DIR)/lib_linked_list.c + $(CC) $(CFLAGS) $^ -o $(OBJ_DIR)/old_list $(LDFLAGS) + valgrind -s --leak-check=full ./$(OBJ_DIR)/old_list + +old_list_full: old_list + valgrind -s --leak-check=full --show-leak-kinds=all ./$(OBJ_DIR)/old_list + +# Hidden tests +tests_hidden: frontend + @GREEN='\033[1;32m'; \ + RED='\033[1;31m'; \ + NC='\033[0m'; \ + for file in ./$(UI_DIR)/ui-tests/*.txt; do \ + base_name=$$(basename $$file .txt); \ + echo "Running test: $$base_name"; \ + valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./$(OBJ_DIR)/frontend < $$file > temp_output.txt 2>&1; \ + if grep -q "ERROR SUMMARY: 0 errors" temp_output.txt; then \ + echo -e "$$base_name $$GREEN PASSED $$NC"; \ + else \ + echo -e "$$base_name $$RED FAILED $$NC"; \ + cat temp_output.txt; \ + fi; \ + done + @rm -f temp_output.txt + +# Clean target +clean: + rm -rf $(OBJ_DIR) *.gcno *.gcda *.gcov coverage.txt + rm -f frontend backend_tests old_hash ol diff --git a/src/inlupp2/readme.md b/demo/readme.md similarity index 100% rename from src/inlupp2/readme.md rename to demo/readme.md diff --git a/src/inlupp2/tests/backend_tests.c b/demo/tests/backend_tests.c similarity index 99% rename from src/inlupp2/tests/backend_tests.c rename to demo/tests/backend_tests.c index 4a71924..3aa9fa6 100644 --- a/src/inlupp2/tests/backend_tests.c +++ b/demo/tests/backend_tests.c @@ -7,7 +7,7 @@ #include "../generic_data_structures/linked_list.h" #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" -#include "../../ref.h" +#include "../../src/refmem.h" typedef struct merch ioopm_merch_t; typedef struct shelf ioopm_shelf_t; @@ -15,7 +15,6 @@ typedef struct shop ioopm_shop_t; typedef struct shopping_carts shopping_carts_t; typedef struct cart cart_t; typedef struct cart_item cart_item_t; - #define Successful(o) (o.success == true) #define Unsuccessful(o) (o.success == false) diff --git a/src/inlupp2/user_interface/frontend.c b/demo/user_interface/frontend.c similarity index 99% rename from src/inlupp2/user_interface/frontend.c rename to demo/user_interface/frontend.c index aff1cda..0748fca 100644 --- a/src/inlupp2/user_interface/frontend.c +++ b/demo/user_interface/frontend.c @@ -9,7 +9,7 @@ #include "../generic_data_structures/hash_table.h" #include "../generic_data_structures/iterator.h" #include "../generic_utils/utils.h" -#include "../../ref.h" +#include "../../src/refmem.h" #define ValidOptions "AaLlDdEeSsPpCcRr+-=OoQq" diff --git a/src/inlupp2/user_interface/ui-tests/addMerch.txt b/demo/user_interface/ui-tests/addMerch.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/addMerch.txt rename to demo/user_interface/ui-tests/addMerch.txt diff --git a/src/inlupp2/user_interface/ui-tests/addMultipleMerch.txt b/demo/user_interface/ui-tests/addMultipleMerch.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/addMultipleMerch.txt rename to demo/user_interface/ui-tests/addMultipleMerch.txt diff --git a/src/inlupp2/user_interface/ui-tests/createCart.txt b/demo/user_interface/ui-tests/createCart.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/createCart.txt rename to demo/user_interface/ui-tests/createCart.txt diff --git a/src/inlupp2/user_interface/ui-tests/editMerchInShelf.txt b/demo/user_interface/ui-tests/editMerchInShelf.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/editMerchInShelf.txt rename to demo/user_interface/ui-tests/editMerchInShelf.txt diff --git a/src/inlupp2/user_interface/ui-tests/editOneMerch.txt b/demo/user_interface/ui-tests/editOneMerch.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/editOneMerch.txt rename to demo/user_interface/ui-tests/editOneMerch.txt diff --git a/src/inlupp2/user_interface/ui-tests/editOneMerchInStock.txt b/demo/user_interface/ui-tests/editOneMerchInStock.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/editOneMerchInStock.txt rename to demo/user_interface/ui-tests/editOneMerchInStock.txt diff --git a/src/inlupp2/user_interface/ui-tests/listMerchPaging.txt b/demo/user_interface/ui-tests/listMerchPaging.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/listMerchPaging.txt rename to demo/user_interface/ui-tests/listMerchPaging.txt diff --git a/src/inlupp2/user_interface/ui-tests/quitWithMerchInCart.txt b/demo/user_interface/ui-tests/quitWithMerchInCart.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/quitWithMerchInCart.txt rename to demo/user_interface/ui-tests/quitWithMerchInCart.txt diff --git a/src/inlupp2/user_interface/ui-tests/removeCartWithMerch.txt b/demo/user_interface/ui-tests/removeCartWithMerch.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/removeCartWithMerch.txt rename to demo/user_interface/ui-tests/removeCartWithMerch.txt diff --git a/src/inlupp2/user_interface/ui-tests/removeMany.txt b/demo/user_interface/ui-tests/removeMany.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/removeMany.txt rename to demo/user_interface/ui-tests/removeMany.txt diff --git a/src/inlupp2/user_interface/ui-tests/removeOne.txt b/demo/user_interface/ui-tests/removeOne.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/removeOne.txt rename to demo/user_interface/ui-tests/removeOne.txt diff --git a/src/inlupp2/user_interface/ui-tests/replenishMerch.txt b/demo/user_interface/ui-tests/replenishMerch.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/replenishMerch.txt rename to demo/user_interface/ui-tests/replenishMerch.txt diff --git a/src/inlupp2/user_interface/ui-tests/replenishMerchAdv.txt b/demo/user_interface/ui-tests/replenishMerchAdv.txt similarity index 100% rename from src/inlupp2/user_interface/ui-tests/replenishMerchAdv.txt rename to demo/user_interface/ui-tests/replenishMerchAdv.txt diff --git a/obj/backend_tests b/obj/backend_tests new file mode 100644 index 0000000..ba6bd7b Binary files /dev/null and b/obj/backend_tests differ diff --git a/obj/frontend b/obj/frontend new file mode 100644 index 0000000..767216b Binary files /dev/null and b/obj/frontend differ diff --git a/obj/test/test b/obj/test/test new file mode 100644 index 0000000..d9b5d16 Binary files /dev/null and b/obj/test/test differ diff --git a/proj/design_report.md b/proj/design_report.md deleted file mode 100644 index 9ae7b33..0000000 --- a/proj/design_report.md +++ /dev/null @@ -1,47 +0,0 @@ -# Design Documentation -This is a memory management library that implements a basic version of reference counting. -It is designed to replace malloc/calloc and free in a program with library functions like -allocate/release. This would make memory management safer avoiding memory leaks. The library -also supports limiting cascading frees. - -# High level Design - -Metadata management: -For each allocated object a metadata struct is stored in a hash table. The struct includes: -- Reference count (rc): Tracks number of active references -- Destructor function pointer: To allow custom destructors for common complex data structures -- Object size in bytes: Used for memory release and validation - -Reference counting: -- Functions retain and release modify the reference count (rc) -- Objects are deallocated when the rc is 0 -- The release function schedules objects for destruction - -Scheduling: -- Objects with rc = 0 are scheduled for destruction using a linked list -- Scheduled objects are processed using free_scheduled_tasks, which frees a set number of - objects per call, as defined by a global cascade limit - -Destructors: -- Default destructor is implemented that can free complex data structures. It manages recursive - destruction of pointer-based objects. -- Custom destructors for hash-tables and linked-lists are made which improve performance for - those data structures - -Memory allocation: -- Objects are allocated using allocate or allocate_array -- A metadata_t struct is associated with each allocated object, storing size and destructor. - -Cleanup: -- Cleanup clears out all objects scheduled for deallocation. - -Shutdown: -- Cleans up all system resources. Frees all objects and destroys hash table and linked list - used in library functions - -# User implementation -For this library to work with any program, one would need to do the following: - -1) Replace malloc/calloc with allocate (or allocate_array) -2) Replace free with release -3) Call shutdown() when program ends. diff --git a/proj/project_report.md b/proj/project_report.md index db14533..ffd95ad 100644 --- a/proj/project_report.md +++ b/proj/project_report.md @@ -3,14 +3,14 @@ # 1 Grupp Vår grupp heter O’boy. Nedan följer information om gruppens medlemmar: -| Namn | E-mail | Aktiva Datum | -|-------------------------|----------------------------------------|---------------------| -| Alexandra Barbu | alexandra.barbu.0105@student.uu.se | 4/12/2024 - End | -| Albin Carlsson | albin.carlsson.9644@student.uu.se | 4/12/2024 - End | -| Einar Eriksson Wahlin | einar.eriksson-wahlin.5775@student.uu.se | 4/12/2024 - End | -| Felix Fagerstedt | email4@example.com | 4/12/2024 - End | -| David Julin | david.carl.julin@gmail.com | 13/1/2025 - End | -| Erika Wallin | erika.wallin.6208@student.uu.se | 4/12/2024 - End | +| Namn | E-mail | Aktiva Datum | +|-------------------------|------------------------------------------|------------------------| +| Alexandra Barbu | alexandra.barbu.0105@student.uu.se | 4/12/2024 - 15/01/2025 | +| Albin Carlsson | albin.carlsson.9644@student.uu.se | 4/12/2024 - 15/01/2025 | +| Einar Eriksson Wahlin | einar.eriksson-wahlin.5775@student.uu.se | 4/12/2024 - 15/01/2025 | +| Felix Fagerstedt | felix.fagerstedt.0046@student.uu.se | 4/12/2024 - 15/01/2025 | +| David Julin | david.julin.1279@student.uu.se | 4/12/2024 - 15/01/2025 | +| Erika Wallin | erika.wallin.6208@student.uu.se | 4/12/2024 - 15/01/2025 | # 2 Kvantifering @@ -24,22 +24,23 @@ I kommande möten vi hade, delade vi upp arbetet i fyra olika sprints, nedan fö Sprint | Startdatum (ursprungligt) | Startdatum (ändrat) | Slutdatum (ursprungligt) | Slutdatum (ändrat) |--------|---------------------------|---------------------|--------------------------|-------------------------- -1 | 4/12/2024 | ändrades ej | 10/12/2024 | 17/12/2024 -2 | 10/12/2024 | 17/12/2024 | 16/12/2024 | 24/12/2024 -3 | 16/12/2024 | 24/12/2024 | 19/12/2024 | 1/1/2025 -4 | 21/12/2024 | 29/12/2024 | 1/1/2025 | 5/1/2025 + 1 | 4/12/2024 | ändrades ej | 10/12/2024 | 17/12/2024 +2 | 10/12/2024 | 17/12/2024 | 16/12/2024 | 24/12/2024 +3 | 16/12/2024 | 24/12/2024 | 19/12/2024 | 1/1/2025 +4 | 21/12/2024 | 29/12/2024 | 1/1/2025 | 5/1/2025 -Vi skrev totalt: //TODO: -* rader C kod -* rader testkod -* rader ”script code” +Vi skrev totalt: +* 242 rader C kod +* 539 rader testkod -Vi hade totalt: //TODO: -* git commits -* git issues -* GitHub issues +Som ett grupp jobbade vi totalt 260 timmar. + +Vi hade totalt: +* 183 git commits +* 34 Pull Requests +* 25 GitHub issues # 3 Process @@ -176,9 +177,9 @@ Den sista sprinten innefattar de sista stegen: att implementera skräpsamlaren i utveckla de befintliga testerna, genomföra små justeringar för att säkerställa programmets funktionalitet, samt skriva klart de olika dokument som behöver lämnas in (rapporter och presentation). Eftersom implementationen verkade vara relativt enkel så tilldelades ett par denna uppgift, medan de andra olika medlemmar fokuserade på olika dokument och -genomföra de små ändringar/tester som behövdes. Eftersom den totala arbetsbelastningen var inte jämnt fördelat i slutet, -valde vi att tilldela större uppdrag till medlemmarna som har arbetat mindre antal timmar, medan de andra fick fokusera -på mindre delar av programmet. +genomföra de små ändringar/tester som behövdes. Dock så hittade vi en stor bugg som ledde till en omstrukturering av +programmet. Eftersom den totala arbetsbelastningen var inte jämnt fördelat i slutet, valde vi att tilldela större +uppdrag till medlemmarna som har arbetat mindre antal timmar, medan de andra fick fokusera på mindre delar av programmet. ## Arbetsuppdelning @@ -192,7 +193,7 @@ Som förväntat visade det sig att största delen av tiden gick åt kodskrivning då många viktiga beslut angående programmets implementation fattades här. Minst tid spenderades på dokumentering eftersom detta är inte lika tidskrävande och gjordes bara en gång i slutet av projektet. -# 7 Reflection //TODO +# 7 Reflection Detta projekt representerar för alla medlemmar den första möjligheten att arbeta i en stor grupp. Även om olika ansvarsområden tilldelades till olika personer så har vi alla försökt delta i varje viktig moment av projektets utveckling och stödja varandra. På en skala från 1 till 7 bedömer vi vår tillfredsställelse med processen till en 6:a. Vi började alltid våra @@ -205,9 +206,9 @@ Vi ser detta som vår största framgång – att kunna fortsätta och hitta lös Därför bedömer vi vår tillfredsställelse med den levererade produkten och kvalitetsgaranti till en 6. Genom att omstrukturera koden från början, säkerställde vi en stabil grund för vidare implementationer. Detta siffra återspeglas i vår -tester kodtäckning som ligger på //TODO: %. Vi har lagt stort fokus på att göra noggranna tester och kodgranskningar så -att vi hamnar inte i samma situation som innan och säkerställer kodkvaliteten. Detta arbete har lett till en pålitlig -produkt som vi kan vara stolta över. +testers kodtäckning : 89% lines executed och 100% branch executed. Vi har lagt stort fokus på att göra noggranna tester +och kodgranskningar så att vi hamnar inte i samma situation som innan och säkerställer kodkvaliteten. Detta arbete har +lett till en pålitlig produkt som vi kan vara stolta över. Sammanfattningsvis är vi nöjda med den levererade produkten. Vi har lärt oss vikten av att ha en detaljerad planering och struktur på programmet samt hur viktigt kommunikation och arbetsuppdelning är när man arbetar i en stor grupp. diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..04ea500 --- /dev/null +++ b/readme.md @@ -0,0 +1,11 @@ +# Getting started +In order to be able to run the program you need to have a C compiler (in our case we use gcc), a virtual machine (if you have non-linux OS), CUnit testing framework, valgrind installed (for checking any memory leaks), and gcov tool installed(for checking the coverage of the tests). + + +## Building and running program +make - compiles all .o files to the obj directory +make test - cleans, compiles and runs tests through valgrind with --leak-check=full flag +make memtest - cleans, compiles and runs tests through valgrind with --leak-check=full flag +make demo - cleans, compiles and runs frontend +make memdemo - cleans, compiles and runs frontend +make clean- cleans all the object files (as well as unnecessary files) \ No newline at end of file diff --git a/src/inlupp2/makefile b/src/inlupp2/makefile deleted file mode 100644 index 8b94310..0000000 --- a/src/inlupp2/makefile +++ /dev/null @@ -1,86 +0,0 @@ -clean: - rm -f *.o frontend backend_tests old_hash old_list *.gcno *.gcda *.gcov backend_tests_coverage - -frontend: user_interface/frontend.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c business_logic/shop.c business_logic/merch.c business_logic/cart.c business_logic/common.c - gcc -g -Wall -pedantic user_interface/frontend.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c business_logic/shop.c business_logic/merch.c business_logic/cart.c business_logic/common.c ../ref.c ../lib/lib_hash_table.c ../lib/lib_linked_list.c -o frontend - -run_frontend: - ./frontend - -val_frontend: - valgrind -s ./frontend - -full_val_frontend: - valgrind -s --leak-check=full ./frontend - -clean_frontend: - make clean; make frontend; make run_frontend - -start: - make clean_frontend - -clean_val_frontend: - make clean; make frontend; make val_frontend - -clean_full_val_frontend: - make clean; make frontend; make full_val_frontend - -backend_tests: business_logic/common.c business_logic/shop.c business_logic/merch.c business_logic/cart.c tests/backend_tests.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c ../ref.c - gcc -g -Wall -pedantic business_logic/common.c business_logic/shop.c business_logic/merch.c business_logic/cart.c tests/backend_tests.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c ../ref.c ../lib/lib_hash_table.c ../lib/lib_linked_list.c -lcunit -o backend_tests - -run_backend_tests: - ./backend_tests - -val_backend_tests: - valgrind -s ./backend_tests - -full_val_backend_tests: - valgrind -s --leak-check=full ./backend_tests - -clean_val_backend_tests: - make clean; make backend_tests; make val_backend_tests - -test: - clean_val_backend_tests - -debug: backend_tests - gdb ./backend_tests --tui - -backend_tests_cov: business_logic/common.c business_logic/shop.c business_logic/merch.c business_logic/cart.c tests/backend_tests.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c - gcc -g -Wall -pedantic business_logic/common.c business_logic/shop.c business_logic/merch.c business_logic/cart.c tests/backend_tests.c generic_utils/utils.c generic_data_structures/linked_list.c generic_data_structures/hash_table.c -lcunit --coverage -o backend_tests_coverage - -cov_run: - ./backend_tests_coverage - -gcov: - gcov -b -c backend_tests_coverage-backend_tests.gcda > coverage.txt - -old_hash: - gcc -g -Wall -pedantic generic_data_structures/hash_table.c generic_data_structures/linked_list.c generic_data_structures/hash_table_tests.c ../ref.c ../lib/lib_hash_table.c ../lib/lib_linked_list.c -lcunit -o old_hash - valgrind -s --leak-check=full ./old_hash - -old_list: - gcc -g -Wall -pedantic generic_data_structures/linked_list.c generic_data_structures/linked_list_tests.c ../ref.c ../lib/lib_hash_table.c ../lib/lib_linked_list.c -lcunit -o old_list - valgrind -s --leak-check=full ./old_list - -old_list_full: - gcc -g -Wall -pedantic generic_data_structures/linked_list.c generic_data_structures/linked_list_tests.c ../ref.c ../lib/lib_hash_table.c ../lib/lib_linked_list.c -lcunit -o old_list - valgrind -s --leak-check=full --show-leak-kinds=all ./old_list - -tests_hidden: frontend - @GREEN='\033[1;32m'; \ - RED='\033[1;31m'; \ - NC='\033[0m'; \ - for file in ./user_interface/ui-tests/*.txt; do \ - base_name=$$(basename $$file .txt); \ - echo "Running test: $$base_name"; \ - valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./frontend < $$file > temp_output.txt 2>&1; \ - if grep -q "ERROR SUMMARY: 0 errors" temp_output.txt; then \ - echo -e "$$base_name $$GREEN PASSED $$NC"; \ - else \ - echo -e "$$base_name $$RED FAILED $$NC"; \ - cat temp_output.txt; \ - fi; \ - done - @rm -f temp_output.txt - diff --git a/src/ref.c b/src/refmem.c similarity index 96% rename from src/ref.c rename to src/refmem.c index cf585f2..bc8c596 100644 --- a/src/ref.c +++ b/src/refmem.c @@ -1,243 +1,243 @@ -#include "ref.h" -#include -#include -#include -#include -#include -#include -#include - -static lib_list_t *schedule_linked_list = NULL; -static lib_hash_table_t *metadata_ht = NULL; -static bool release_in_progress = false; -static const size_t STANDARD_CASCADE_LIMIT = 100; -static size_t CASCADE_LIMIT = 100; - -bool int_equal(lib_elem_t a, lib_elem_t b) { - return a.i == b.i; -} - -static int default_hash_function(lib_elem_t value) { - return value.i; -} - -static void initialize_collector() { - if (!metadata_ht) { - metadata_ht = lib_hash_table_create(int_equal, NULL, default_hash_function); - } - if (!schedule_linked_list) { - schedule_linked_list = lib_linked_list_create(int_equal); // TODO!!! int_equal, but ptr_elem values - } -} - -lib_hash_table_t *get_metadata_ht() { - if (metadata_ht == NULL) { - metadata_ht = lib_hash_table_create(int_equal, NULL, default_hash_function); - } - return metadata_ht; -} - -lib_list_t *get_schedule_linked_list() { - if (!schedule_linked_list) { - schedule_linked_list = lib_linked_list_create(int_equal); // TODO!!! int_equal, but ptr_elem values - } - return schedule_linked_list; -} - -metadata_t *metadata_generate(function1_t destructor, size_t size) { - metadata_t *metadata = calloc(1, sizeof(metadata_t)); - if (!metadata) return NULL; - metadata->rc = 0; - metadata->destructor = destructor; - metadata->size = size; - return metadata; -} - -static metadata_t *get_metadata(obj* object) { - uintptr_t key_as_int = (uintptr_t) object; - lib_option_t found_data = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); - if(!found_data.success) return NULL; - return (metadata_t*) found_data.value.p; -} - -uint8_t rc(obj* object) { - metadata_t *metadata = get_metadata(object); - if (metadata) { - return metadata->rc; - } else { - printf("metadata could not be found!"); - return 0; - } -} - -void release_destructor(obj *to_remove) { - if (!to_remove) return; - metadata_t *metadata = get_metadata(to_remove); - if (metadata) { - metadata->destructor(to_remove); - } -} - -static bool is_valid_pointer(void *object){ - if (!object) return false; - uintptr_t key_as_int = (uintptr_t) object; - lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); - return option.success; -} - -static void destructor_loop(size_t object_size, obj *object) { - for (size_t offset = 0; offset + sizeof(void *) <= object_size; offset++) - { - void **possible_pointer = (void **)((char *)object + offset); - if (is_valid_pointer(*possible_pointer)) - { - release(*possible_pointer); - } - } -} - -static void default_destructor(obj* object) { - if(!object) return; - uintptr_t key_as_int = (uintptr_t) object; - lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); - if (!option.success) return; - metadata_t *metadata = (metadata_t *)(option.value.p); - size_t object_size = metadata->size; - destructor_loop(object_size, object); -} - -static void add_to_schedule(obj *object) { - metadata_t *metadata = get_metadata(object); - if(!metadata) return; - lib_linked_list_append(get_schedule_linked_list(), lib_ptr_elem(object)); - if (metadata->destructor) { - metadata->destructor(object); - } - else { - default_destructor(object); - } -} - -static void task_manager_loop(size_t size) { - size_t freed_size = 0; - size_t cascade_amount = 0; - while ((freed_size < size || cascade_amount < CASCADE_LIMIT) && - lib_linked_list_size(get_schedule_linked_list()) > 0) - { - bool successful1 = false; - obj *to_remove = lib_linked_list_get(get_schedule_linked_list(), 0, &successful1).p; - deallocate(to_remove); - cascade_amount++; - } - release_in_progress = false; -} - -static void schedule_task_manager(obj *object, size_t size) { - release_in_progress = true; - metadata_t *metadata = get_metadata(object); - if(object && metadata) { - if(metadata->rc == 0) { - add_to_schedule(object); - } - } - task_manager_loop(size); -} - -obj *allocate(size_t bytes, function1_t destructor) { - initialize_collector(); - schedule_task_manager(NULL, bytes); - obj *object = calloc(1, bytes); - uintptr_t key_as_int = (uintptr_t) object; - metadata_t *metadata = metadata_generate(destructor, bytes); - lib_hash_table_insert(get_metadata_ht(), lib_int_elem(key_as_int), lib_ptr_elem(metadata)); - return object; -} - -obj *allocate_array(size_t elements, size_t bytes, function1_t destructor) { - size_t total_size = elements * bytes; - return allocate(total_size, destructor); -} - -void deallocate(obj* object) { - if(!object) return; - uintptr_t key_as_int = (uintptr_t)object; - metadata_t *metadata = get_metadata(object); - if(!metadata) return; - assert(rc(object) == 0); - lib_list_option_t exist = lib_linked_list_contains(schedule_linked_list, lib_ptr_elem(object)); - if(exist.success) { - bool successful1 = false; - lib_linked_list_remove(schedule_linked_list, exist.value.i, &successful1); - } - lib_hash_table_remove(get_metadata_ht(), lib_int_elem(key_as_int)); - free(metadata); - free(object); -} - -void retain(obj *object) { - if (!object) return; - uintptr_t key_as_int = (uintptr_t)object; - lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); - if (option.success) { - metadata_t *metadata = (metadata_t *)(option.value.p); - metadata->rc++; - } -} - -void release(obj *object) { - if (!object) return; - metadata_t *metadata = get_metadata(object); - if (!metadata) return; - else if(metadata->rc > 0) { - metadata->rc--; - } - if(metadata->rc == 0) { - if(!release_in_progress){ - schedule_task_manager(object, 0); - } - else { - add_to_schedule(object); - } - } -} - -void cleanup() { - schedule_task_manager(NULL, SIZE_MAX); -} - -static void free_all() { - cleanup(); - lib_linked_list_destroy(get_schedule_linked_list()); - schedule_linked_list = NULL; - lib_hash_table_destroy(get_metadata_ht()); -} - -void shutdown() { - set_cascade_limit(STANDARD_CASCADE_LIMIT); - free_all(); -} - -size_t get_cascade_limit() { - return CASCADE_LIMIT; -} - -void set_cascade_limit(size_t size) { - CASCADE_LIMIT = size; -} - -void str_dummy_destructor(obj *o) { -} - -char *rc_strdup(char *src) { - char *str; - char *p; - int len = 0; - while (src[len]) len++; - str = allocate(len + 1, str_dummy_destructor); - p = str; - while (*src) - *p++ = *src++; - *p = '\0'; - return str; -} - +#include "refmem.h" +#include +#include +#include +#include +#include +#include +#include + +static lib_list_t *schedule_linked_list = NULL; +static lib_hash_table_t *metadata_ht = NULL; +static bool release_in_progress = false; +static const size_t STANDARD_CASCADE_LIMIT = 100; +static size_t CASCADE_LIMIT = 100; + +bool int_equal(lib_elem_t a, lib_elem_t b) { + return a.i == b.i; +} + +static int default_hash_function(lib_elem_t value) { + return value.i; +} + +static void initialize_collector() { + if (!metadata_ht) { + metadata_ht = lib_hash_table_create(int_equal, NULL, default_hash_function); + } + if (!schedule_linked_list) { + schedule_linked_list = lib_linked_list_create(int_equal); // TODO!!! int_equal, but ptr_elem values + } +} + +lib_hash_table_t *get_metadata_ht() { + if (metadata_ht == NULL) { + metadata_ht = lib_hash_table_create(int_equal, NULL, default_hash_function); + } + return metadata_ht; +} + +lib_list_t *get_schedule_linked_list() { + if (!schedule_linked_list) { + schedule_linked_list = lib_linked_list_create(int_equal); // TODO!!! int_equal, but ptr_elem values + } + return schedule_linked_list; +} + +metadata_t *metadata_generate(function1_t destructor, size_t size) { + metadata_t *metadata = calloc(1, sizeof(metadata_t)); + if (!metadata) return NULL; + metadata->rc = 0; + metadata->destructor = destructor; + metadata->size = size; + return metadata; +} + +static metadata_t *get_metadata(obj* object) { + uintptr_t key_as_int = (uintptr_t) object; + lib_option_t found_data = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); + if(!found_data.success) return NULL; + return (metadata_t*) found_data.value.p; +} + +uint8_t rc(obj* object) { + metadata_t *metadata = get_metadata(object); + if (metadata) { + return metadata->rc; + } else { + printf("metadata could not be found!"); + return 0; + } +} + +void release_destructor(obj *to_remove) { + if (!to_remove) return; + metadata_t *metadata = get_metadata(to_remove); + if (metadata) { + metadata->destructor(to_remove); + } +} + +static bool is_valid_pointer(void *object){ + if (!object) return false; + uintptr_t key_as_int = (uintptr_t) object; + lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); + return option.success; +} + +static void destructor_loop(size_t object_size, obj *object) { + for (size_t offset = 0; offset + sizeof(void *) <= object_size; offset++) + { + void **possible_pointer = (void **)((char *)object + offset); + if (is_valid_pointer(*possible_pointer)) + { + release(*possible_pointer); + } + } +} + +static void default_destructor(obj* object) { + if(!object) return; + uintptr_t key_as_int = (uintptr_t) object; + lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); + if (!option.success) return; + metadata_t *metadata = (metadata_t *)(option.value.p); + size_t object_size = metadata->size; + destructor_loop(object_size, object); +} + +static void add_to_schedule(obj *object) { + metadata_t *metadata = get_metadata(object); + if(!metadata) return; + lib_linked_list_append(get_schedule_linked_list(), lib_ptr_elem(object)); + if (metadata->destructor) { + metadata->destructor(object); + } + else { + default_destructor(object); + } +} + +static void task_manager_loop(size_t size) { + size_t freed_size = 0; + size_t cascade_amount = 0; + while ((freed_size < size || cascade_amount < CASCADE_LIMIT) && + lib_linked_list_size(get_schedule_linked_list()) > 0) + { + bool successful1 = false; + obj *to_remove = lib_linked_list_get(get_schedule_linked_list(), 0, &successful1).p; + deallocate(to_remove); + cascade_amount++; + } + release_in_progress = false; +} + +static void schedule_task_manager(obj *object, size_t size) { + release_in_progress = true; + metadata_t *metadata = get_metadata(object); + if(object && metadata) { + if(metadata->rc == 0) { + add_to_schedule(object); + } + } + task_manager_loop(size); +} + +obj *allocate(size_t bytes, function1_t destructor) { + initialize_collector(); + schedule_task_manager(NULL, bytes); + obj *object = calloc(1, bytes); + uintptr_t key_as_int = (uintptr_t) object; + metadata_t *metadata = metadata_generate(destructor, bytes); + lib_hash_table_insert(get_metadata_ht(), lib_int_elem(key_as_int), lib_ptr_elem(metadata)); + return object; +} + +obj *allocate_array(size_t elements, size_t bytes, function1_t destructor) { + size_t total_size = elements * bytes; + return allocate(total_size, destructor); +} + +void deallocate(obj* object) { + if(!object) return; + uintptr_t key_as_int = (uintptr_t)object; + metadata_t *metadata = get_metadata(object); + if(!metadata) return; + assert(rc(object) == 0); + lib_list_option_t exist = lib_linked_list_contains(schedule_linked_list, lib_ptr_elem(object)); + if(exist.success) { + bool successful1 = false; + lib_linked_list_remove(schedule_linked_list, exist.value.i, &successful1); + } + lib_hash_table_remove(get_metadata_ht(), lib_int_elem(key_as_int)); + free(metadata); + free(object); +} + +void retain(obj *object) { + if (!object) return; + uintptr_t key_as_int = (uintptr_t)object; + lib_option_t option = lib_hash_table_lookup(get_metadata_ht(), lib_int_elem(key_as_int)); + if (option.success) { + metadata_t *metadata = (metadata_t *)(option.value.p); + metadata->rc++; + } +} + +void release(obj *object) { + if (!object) return; + metadata_t *metadata = get_metadata(object); + if (!metadata) return; + else if(metadata->rc > 0) { + metadata->rc--; + } + if(metadata->rc == 0) { + if(!release_in_progress){ + schedule_task_manager(object, 0); + } + else { + add_to_schedule(object); + } + } +} + +void cleanup() { + schedule_task_manager(NULL, SIZE_MAX); +} + +static void free_all() { + cleanup(); + lib_linked_list_destroy(get_schedule_linked_list()); + schedule_linked_list = NULL; + lib_hash_table_destroy(get_metadata_ht()); +} + +void shutdown() { + set_cascade_limit(STANDARD_CASCADE_LIMIT); + free_all(); +} + +size_t get_cascade_limit() { + return CASCADE_LIMIT; +} + +void set_cascade_limit(size_t size) { + CASCADE_LIMIT = size; +} + +void str_dummy_destructor(obj *o) { +} + +char *rc_strdup(char *src) { + char *str; + char *p; + int len = 0; + while (src[len]) len++; + str = allocate(len + 1, str_dummy_destructor); + p = str; + while (*src) + *p++ = *src++; + *p = '\0'; + return str; +} + diff --git a/src/ref.h b/src/refmem.h similarity index 96% rename from src/ref.h rename to src/refmem.h index 8beb496..195f6ac 100644 --- a/src/ref.h +++ b/src/refmem.h @@ -1,133 +1,133 @@ -#pragma once -#include -#include -#include -#include -#include "lib/lib_hash_table.h" -#include "lib/lib_linked_list.h" -#include "lib/lib_common.h" - - -// Void pointer used for allocation -typedef void obj; - -// A destructor function pointer -typedef void(*function1_t)(obj *); - -// The data we store when allocating a object -struct metadata { - uint8_t rc; // Reference count - function1_t destructor; // Function to call before freeing - size_t size; // Total size of the user allocation -}; -typedef struct metadata metadata_t; - -/** - * @brief Increases the reference count for a given object. - * - * @param object A pointer to the object whose reference count should be incremented. - */ -void retain(obj *object); - -/** - * @brief Decreases the reference count for a given object and deallocates it if the count reaches zero. - * - * @param object A pointer to the object whose reference count should be decremented. - */ -void release(obj *object); - -/** - * @brief Retrieves the current reference count of an object. - * - * @param object A pointer to the object. - * @return The reference count of the object, or 0 if the object has no metadata. - */ -uint8_t rc(obj *object); - -/** - * @brief Allocates memory for an object and associates it with metadata. - * - * @param bytes The number of bytes to allocate for the object. - * @param destructor A function to be called before deallocating the object. - * @return A pointer to the allocated object, or NULL if allocation fails. - */ -obj *allocate(size_t bytes, function1_t destructor); - -/** - * @brief Allocates memory for an array of objects and associates it with metadata. - * - * @param elements The number of elements in the array. - * @param elem_size The size of each element in bytes. - * @param destructor A function to be called before deallocating the object. - * @return A pointer to the allocated array, or NULL if allocation fails. - */ -obj *allocate_array(size_t elements, size_t elem_size, function1_t destructor); - -/** - * @brief Generates metadata for an object. - * - * @param destructor A function to be called before deallocating the object. - * @param size The size of the object. - * @return A pointer to the generated metadata, or NULL if allocation fails. - */ -metadata_t *metadata_generate(function1_t destructor, size_t size); - -/** - * @brief Deallocates an object by adding it to the schedule and triggering destructors as needed. - * - * @param object A pointer to the object to deallocate. - */ -void deallocate(obj *object); - -/** - * @brief Sets the cascade limit for freeing objects. - * - * @param size The new cascade limit. - */ -void set_cascade_limit(size_t size); - -/** - * @brief Retrieves the current cascade limit for freeing objects. - * - * @return The current cascade limit. - */ -size_t get_cascade_limit(); - -/** - * @brief Cleans up scheduled tasks by freeing all eligible objects. - */ -void cleanup(); - -/** - * @brief Shuts down the memory manager by freeing all resources and clearing metadata. - */ -void shutdown(); - -/** - * @brief Retrieves the global metadata hash table. - * - * @return A pointer to the metadata hash table. - */ -lib_hash_table_t *get_metadata_ht(); - -/** - * @brief Retrieves the global schedule linked list. - * - * @return A pointer to the schedule linked list. - */ -lib_list_t *get_schedule_linked_list(); - -/** - * @brief Creates a new reference-counted copy of the input string. - * - * @param src A pointer to the source string to duplicate. - * @return A pointer to the duplicated string. - */ -char *rc_strdup(char *src); - -/** - * @brief A dummy destructor for strings. - * - * @param o A pointer to the object. - */ -void str_dummy_destructor(obj *o); +#pragma once +#include +#include +#include +#include +#include "lib/lib_hash_table.h" +#include "lib/lib_linked_list.h" +#include "lib/lib_common.h" + + +// Void pointer used for allocation +typedef void obj; + +// A destructor function pointer +typedef void(*function1_t)(obj *); + +// The data we store when allocating a object +struct metadata { + uint8_t rc; // Reference count + function1_t destructor; // Function to call before freeing + size_t size; // Total size of the user allocation +}; +typedef struct metadata metadata_t; + +/** + * @brief Increases the reference count for a given object. + * + * @param object A pointer to the object whose reference count should be incremented. + */ +void retain(obj *object); + +/** + * @brief Decreases the reference count for a given object and deallocates it if the count reaches zero. + * + * @param object A pointer to the object whose reference count should be decremented. + */ +void release(obj *object); + +/** + * @brief Retrieves the current reference count of an object. + * + * @param object A pointer to the object. + * @return The reference count of the object, or 0 if the object has no metadata. + */ +uint8_t rc(obj *object); + +/** + * @brief Allocates memory for an object and associates it with metadata. + * + * @param bytes The number of bytes to allocate for the object. + * @param destructor A function to be called before deallocating the object. + * @return A pointer to the allocated object, or NULL if allocation fails. + */ +obj *allocate(size_t bytes, function1_t destructor); + +/** + * @brief Allocates memory for an array of objects and associates it with metadata. + * + * @param elements The number of elements in the array. + * @param elem_size The size of each element in bytes. + * @param destructor A function to be called before deallocating the object. + * @return A pointer to the allocated array, or NULL if allocation fails. + */ +obj *allocate_array(size_t elements, size_t elem_size, function1_t destructor); + +/** + * @brief Generates metadata for an object. + * + * @param destructor A function to be called before deallocating the object. + * @param size The size of the object. + * @return A pointer to the generated metadata, or NULL if allocation fails. + */ +metadata_t *metadata_generate(function1_t destructor, size_t size); + +/** + * @brief Deallocates an object by adding it to the schedule and triggering destructors as needed. + * + * @param object A pointer to the object to deallocate. + */ +void deallocate(obj *object); + +/** + * @brief Sets the cascade limit for freeing objects. + * + * @param size The new cascade limit. + */ +void set_cascade_limit(size_t size); + +/** + * @brief Retrieves the current cascade limit for freeing objects. + * + * @return The current cascade limit. + */ +size_t get_cascade_limit(); + +/** + * @brief Cleans up scheduled tasks by freeing all eligible objects. + */ +void cleanup(); + +/** + * @brief Shuts down the memory manager by freeing all resources and clearing metadata. + */ +void shutdown(); + +/** + * @brief Retrieves the global metadata hash table. + * + * @return A pointer to the metadata hash table. + */ +lib_hash_table_t *get_metadata_ht(); + +/** + * @brief Retrieves the global schedule linked list. + * + * @return A pointer to the schedule linked list. + */ +lib_list_t *get_schedule_linked_list(); + +/** + * @brief Creates a new reference-counted copy of the input string. + * + * @param src A pointer to the source string to duplicate. + * @return A pointer to the duplicated string. + */ +char *rc_strdup(char *src); + +/** + * @brief A dummy destructor for strings. + * + * @param o A pointer to the object. + */ +void str_dummy_destructor(obj *o); diff --git a/test/test.c b/test/test.c index 6f16d8d..d4e1c5e 100644 --- a/test/test.c +++ b/test/test.c @@ -1,30 +1,27 @@ -#include "../src/ref.h" +#include "../src/refmem.h" #include #include #include #include #include "../src/lib/lib_linked_list.h" -#include "../src/inlupp2/generic_data_structures/linked_list.h" #include #include -struct cell -{ +struct cell { struct cell *cell; int i; char *string; }; + typedef struct lib_link lib_link_t; -struct lib_link -{ +struct lib_link { lib_elem_t value; lib_link_t *previous; lib_link_t *next; }; -void cell_destructor(obj *c) //kanske borde returna Size på det vi tagit bort? -{ +void cell_destructor(obj *c) { //kanske borde returna Size på det vi tagit bort? release(((struct cell *) c)->cell); } @@ -45,8 +42,7 @@ int clean_suite(void) { // Unit tests -void test_allocate_and_deallocate(void) -{ +void test_allocate_and_deallocate(void) { // Set cascade limit set_cascade_limit(1); @@ -161,8 +157,7 @@ void test_default_destructor() { (lib_elem_t) { 0 } // Helper function for testing on links -static lib_link_t *link_create_with_allocate(lib_elem_t value, lib_link_t *previous, lib_link_t *next) -{ +static lib_link_t *link_create_with_allocate(lib_elem_t value, lib_link_t *previous, lib_link_t *next) { lib_link_t *link = allocate(sizeof(lib_link_t), NULL); link->previous = previous; link->next = next; @@ -172,8 +167,7 @@ static lib_link_t *link_create_with_allocate(lib_elem_t value, lib_link_t *previ } -void test_allocate_and_deallocate_links(void) -{ +void test_allocate_and_deallocate_links(void) { // Set cascade limit set_cascade_limit(1); @@ -193,8 +187,7 @@ void test_allocate_and_deallocate_links(void) deallocate(link3); } -void test_allocate_array_then_deallocate(void) -{ +void test_allocate_array_then_deallocate(void) { // Set cascade limit set_cascade_limit(3); @@ -216,8 +209,7 @@ void test_allocate_array_then_deallocate(void) //should not leak when running tests! } -void test_allocate_strings_then_release(void) -{ +void test_allocate_strings_then_release(void) { // Set cascade limit set_cascade_limit(1); @@ -252,7 +244,7 @@ void test_allocate_strings_then_release(void) // free_all(); } -void test_get_and_set_cascade_limit(){ +void test_get_and_set_cascade_limit() { // Set cascade limit set_cascade_limit(2); // Check that get_cascade_limit gets the right limit @@ -269,6 +261,7 @@ void test_get_and_set_cascade_limit(){ // Binary trees typedef struct node node_t; + struct node { int val; node_t *left; @@ -536,4 +529,4 @@ int main() { // Tear down CUnit before exiting CU_cleanup_registry(); return CU_get_error(); -} \ No newline at end of file +} \ No newline at end of file