From df2ed3acda93691d264b5450535a04a4e7ba04b3 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Fri, 19 Apr 2024 08:12:31 +0200 Subject: [PATCH] TP2: copy of TP1 --- TP/TP2/rendu/Makefile | 14 +++ TP/TP2/rendu/config.h | 7 ++ TP/TP2/rendu/linked_list.c | 125 +++++++++++++++++++++++++ TP/TP2/rendu/linked_list.h | 24 +++++ TP/TP2/rendu/mmap.c | 181 +++++++++++++++++++++++++++++++++++++ TP/TP2/rendu/mmap.h | 36 ++++++++ TP/TP2/rendu/test.c | 43 +++++++++ TP/TP2/rendu/vmap.c | 162 +++++++++++++++++++++++++++++++++ TP/TP2/rendu/vmap.h | 41 +++++++++ TP/TP2/sujet.pdf | Bin 0 -> 21190 bytes 10 files changed, 633 insertions(+) create mode 100644 TP/TP2/rendu/Makefile create mode 100644 TP/TP2/rendu/config.h create mode 100644 TP/TP2/rendu/linked_list.c create mode 100644 TP/TP2/rendu/linked_list.h create mode 100644 TP/TP2/rendu/mmap.c create mode 100644 TP/TP2/rendu/mmap.h create mode 100644 TP/TP2/rendu/test.c create mode 100644 TP/TP2/rendu/vmap.c create mode 100644 TP/TP2/rendu/vmap.h create mode 100644 TP/TP2/sujet.pdf diff --git a/TP/TP2/rendu/Makefile b/TP/TP2/rendu/Makefile new file mode 100644 index 0000000..8b54c7f --- /dev/null +++ b/TP/TP2/rendu/Makefile @@ -0,0 +1,14 @@ +SRC = $(wildcard *.c) +OBJ = $(filter-out build/main.o build/test.o, $(SRC:%.c=build/%.o)) +FLAGS = -Wall -Wextra -g -O3 + +all: build/test + +build/test: test.c $(OBJ) + gcc $^ -o $@ $(FLAGS) + +build/%.o: %.c %.h + gcc -c $< -o $@ $(FLAGS) + +clean: + rm -f build/* diff --git a/TP/TP2/rendu/config.h b/TP/TP2/rendu/config.h new file mode 100644 index 0000000..f3a822f --- /dev/null +++ b/TP/TP2/rendu/config.h @@ -0,0 +1,7 @@ +#ifndef DEF_CONFIG_H +#define DEF_CONFIG_H + +#define PAGE_SIZE 4096 +#define PAGE_COUNT 100 + +#endif \ No newline at end of file diff --git a/TP/TP2/rendu/linked_list.c b/TP/TP2/rendu/linked_list.c new file mode 100644 index 0000000..cb57aa9 --- /dev/null +++ b/TP/TP2/rendu/linked_list.c @@ -0,0 +1,125 @@ +// linked list +#include +#include +#include + +#include "linked_list.h" + + +linkedList* createLinkedList() { + linkedList *list = (linkedList*)malloc(sizeof(linkedList)); + list->head = NULL; + return list; +} + +//insert link at the first location +void insertFirst(linkedList *list, int key, void *data) { + //create a link + node *link = (node*) malloc(sizeof(node)); + + link->key = key; + link->data = data; + + //point it to old first node + link->next = list->head; + + //point first to new first node + list->head = link; +} + +//delete first item +node* deleteFirst(linkedList *list) { + if (!list->head) { + return NULL; + } + + //save reference to first link + node *tempLink = list->head; + + //mark next to first link as first + list->head = list->head->next; + + //return the deleted link + return tempLink; +} + +//find a link with given key +node* find(linkedList *list, int key) { + + //start from the first link + node* current = list->head; + + //if list is empty + if(!current) { + return NULL; + } + + //navigate through list + while(current->key != key) { + + //if it is last node + if(!current->next) { + return NULL; + } else { + //go to next link + current = current->next; + } + } + + //if data found, return the current Link + return current; +} + +//delete a link with given key +node* deleteElement(linkedList *list, int key) { + + //start from the first link + node* current = list->head; + node* previous = NULL; + + //if list is empty + if(!list->head) { + return NULL; + } + + //navigate through list + while(current->key != key) { + + //if it is last node + if(!current->next) { + return NULL; + } else { + //store reference to current link + previous = current; + //move to next link + current = current->next; + } + } + + //found a match, update the link + if(current == list->head) { + //change first to point to next link + list->head = list->head->next; + } else { + //bypass the current link + previous->next = current->next; + } + + return current; +} + +//is list empty +bool isEmpty(linkedList *list) { + return !list->head; +} + +int length(linkedList *list) { + int length = 0; + node *current; + + for(current = list->head; current != NULL; current = current->next) { + length++; + } + + return length; +} \ No newline at end of file diff --git a/TP/TP2/rendu/linked_list.h b/TP/TP2/rendu/linked_list.h new file mode 100644 index 0000000..e935a4d --- /dev/null +++ b/TP/TP2/rendu/linked_list.h @@ -0,0 +1,24 @@ +#ifndef DEF_LLIST_H +#define DEF_LLIST_H + +#include + +typedef struct node { + void *data; + int key; + struct node *next; +} node; + +typedef struct linkedList { + node *head; +} linkedList; + +linkedList* createLinkedList(); +void insertFirst(linkedList *list, int key, void *data); +node* deleteFirst(linkedList *list); +node* find(linkedList *list, int key); +node* deleteElement(linkedList *list, int key); +bool isEmpty(linkedList *list); +int length(linkedList *list); + +#endif \ No newline at end of file diff --git a/TP/TP2/rendu/mmap.c b/TP/TP2/rendu/mmap.c new file mode 100644 index 0000000..0f48f8a --- /dev/null +++ b/TP/TP2/rendu/mmap.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +#define CHECK_FERROR(f) { if (ferror(f)) {fprintf(stderr, "IO Error"); exit(1);} } + +#include "config.h" +#include "mmap.h" + +MMap* mmap_init(){ + MMap *mmap = malloc(sizeof(MMap)); + mmap->size = PAGE_SIZE*PAGE_COUNT; + mmap->memory = malloc(mmap->size); + mmap->count = 0; + mmap->support = malloc(sizeof(PageInfo)); + mmap->support->data = malloc(PAGE_SIZE); + mmap->free_list = createLinkedList(); + // insert PAGE_COUNT pages in the free list + for (int i=0; i < PAGE_COUNT; i++) { + PageInfo *page = malloc(sizeof(PageInfo)); + page->data = mmap->memory + i*PAGE_SIZE; + page->key = i; + insertFirst(mmap->free_list, i, page); + } + mmap->alloc_list = createLinkedList(); + mmap->swap = fopen("/tmp/myswap", "wb+"); + int tmp = -1; + for (int i=0; i < PAGE_COUNT; i++) { + fwrite(&tmp, sizeof(int), 1, mmap->swap); + } + char tmp2 = '\0'; + for (int i=0; i < PAGE_COUNT*PAGE_SIZE; i++) { + fwrite(&tmp2, 1, 1, mmap->swap); + } + return mmap; +} + +void mmap_clean(MMap *mmap) { + free(mmap->memory); + fclose(mmap->swap); + free(mmap); + remove("/tmp/myswap"); +} + +PageInfo* page_alloc(MMap *mmap) { + PageInfo *page = NULL; + page = page_free(mmap); + if (page) { + insertFirst(mmap->alloc_list, page->key, page); + mmap->count++; + } + return page; +} + +PageInfo* page_free(MMap *mmap) { + PageInfo *page = NULL; + node *node = deleteFirst(mmap->free_list); + if (node) { + page = node->data; + } + return page; +} + +int check_page_free_list(MMap *mmap) { + return length(mmap->free_list); +} + +int check_page_alloc(MMap *mmap) { + return length(mmap->alloc_list); +} + +int move_to_swap(MMap *mmap, PageInfo *page) { + int key = -1; + fseek(mmap->swap, 0, SEEK_SET); + CHECK_FERROR(mmap->swap); + + for (int i=0; i < PAGE_COUNT; i++) { + fread(&key, sizeof(int), 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + if (key == -1) { + fseek(mmap->swap, i*sizeof(int), SEEK_SET); + CHECK_FERROR(mmap->swap); + + fwrite(&page->key, sizeof(int), 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + fseek(mmap->swap, PAGE_COUNT*sizeof(int) + i*PAGE_SIZE, SEEK_SET); + CHECK_FERROR(mmap->swap); + + fwrite(page->data, PAGE_SIZE, 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + return 0; + } + } + return -1; +} + +PageInfo* read_from_swap(MMap* mmap, PageInfo *page) { + int key = -1; + fseek(mmap->swap, 0, SEEK_SET); + CHECK_FERROR(mmap->swap); + + for (int i=0; i < PAGE_COUNT; i++) { + (void)fread(&key, sizeof(int), 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + if (key != page->key) + continue; + + fseek(mmap->swap, PAGE_COUNT*sizeof(int) + i*PAGE_SIZE, SEEK_SET); + CHECK_FERROR(mmap->swap); + + fread(page->data, PAGE_SIZE, 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + fseek(mmap->swap, i*sizeof(int), SEEK_SET); + CHECK_FERROR(mmap->swap); + + int tmp = -1; + fwrite(&tmp, sizeof(int), 1, mmap->swap); + CHECK_FERROR(mmap->swap); + + return page; + } + return NULL; +} + +PageInfo* page_lookup(MMap* mmap, int key) { + node* data = find(mmap->alloc_list, key); + if (data) { + return data->data; + } + + mmap->support->key = key; + PageInfo* page = read_from_swap(mmap, mmap->support); + if (page) { // Move one elem from mem to swap + PageInfo* swapped_page = deleteFirst(mmap->alloc_list)->data; + move_to_swap(mmap, swapped_page); + + memcpy(swapped_page->data, mmap->support->data, PAGE_SIZE); + swapped_page->key = key; + insertFirst(mmap->alloc_list, key, swapped_page); + return page; + } + return NULL; +} + +void page_remove(MMap *mmap, int key) { + PageInfo* page = page_lookup(mmap, key); + if (!page) + return; + + deleteElement(mmap->alloc_list, key); + mmap->count--; +} + +PageInfo *page_create(MMap *mmap, bool *moved_to_swap) { + if (mmap->count >= 2*PAGE_COUNT) + return NULL; + + PageInfo* page = page_alloc(mmap); + *moved_to_swap = false; + + if (page) + return page; + + // Another page has been moved to swap + *moved_to_swap = true; + + page = deleteFirst(mmap->alloc_list)->data; + move_to_swap(mmap, page); + // Reuse swapped page for the new one + page->key = mmap->count; + mmap->count++; + insertFirst(mmap->alloc_list, page->key, page); + + return page; +} \ No newline at end of file diff --git a/TP/TP2/rendu/mmap.h b/TP/TP2/rendu/mmap.h new file mode 100644 index 0000000..5a0d268 --- /dev/null +++ b/TP/TP2/rendu/mmap.h @@ -0,0 +1,36 @@ +#ifndef DEF_MMAP_H +#define DEF_MMAP_H + +#include +#include + +#include "linked_list.h" + +typedef struct PageInfo { + int key; + void *data; +} PageInfo; + +typedef struct MMap { + void *memory; + int size; + int count; + PageInfo *support; + linkedList *free_list; + linkedList *alloc_list; + FILE *swap; +} MMap; + +MMap* mmap_init(); +void mmap_clean(MMap *mmap); +PageInfo* page_alloc(MMap *mmap); +PageInfo* page_free(MMap *mmap); +int check_page_free_list(MMap *mmap); +int check_page_alloc(MMap *mmap); +int move_to_swap(MMap *mmap, PageInfo *page); +PageInfo* read_from_swap(MMap* mmap, PageInfo *page); +PageInfo *page_lookup(MMap *mmap, int key); +void page_remove(MMap *mmap, int key); +PageInfo *page_create(MMap *mmap, bool *moved_to_swap); + +#endif \ No newline at end of file diff --git a/TP/TP2/rendu/test.c b/TP/TP2/rendu/test.c new file mode 100644 index 0000000..2cdb95c --- /dev/null +++ b/TP/TP2/rendu/test.c @@ -0,0 +1,43 @@ +#include +#include + +#include "vmap.h" + +int main() { + // Add more tests here + VMap* vmap = vmap_init(); + + char* real1 = malloc(sizeof(char)*32); + real1[0] = 'h'; + real1[1] = 'e'; + real1[2] = 'l'; + real1[3] = 'l'; + real1[4] = 'o'; + real1[5] = '!'; + real1[6] = '\0'; + + char* data1 = my_malloc(vmap, 32*sizeof(char)); + char* data2 = my_malloc(vmap, 32*sizeof(char)); + + vmap_copy_from_memory(vmap, real1, data1, 8); + + my_copy(vmap, data1, data2, 32*sizeof(char)); + + char* real = malloc(sizeof(char)*32); + + vmap_copy_to_memory(vmap, data2, real, 7); + + if (strcmp(real1, real1)) { + printf("%d\n", strcmp(real, real1)); + fprintf(stderr, "copy test failed\n"); + return 1; + } + + free(real); + free(real1); + + my_free(vmap, data1); + my_free(vmap, data2); + + return 0; +} diff --git a/TP/TP2/rendu/vmap.c b/TP/TP2/rendu/vmap.c new file mode 100644 index 0000000..bc5874f --- /dev/null +++ b/TP/TP2/rendu/vmap.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "vmap.h" + +VMap* vmap_init() { + VMap* vmap = (VMap*)malloc(sizeof(VMap)); + vmap->mmap = mmap_init(); + vmap->pages = createLinkedList(); + vmap->index = 0; + + return vmap; +} + +PageMapInfo* vmap_new_page(VMap* vmap) { + PageMapInfo* page = (PageMapInfo*)malloc(sizeof(PageMapInfo)); + + bool moved; + page->key = page_create(vmap->mmap, &moved)->key; + page->start = vmap->index; + page->cursor = 0; + page->nb_allocs = 0; + page->swapped = moved; + + vmap->index += PAGE_SIZE; + + insertFirst(vmap->pages, page->start, page); + + return page; +} + +int page_map_available_size(PageMapInfo* page) { + int avail = page->start + PAGE_SIZE - page->cursor; + assert(avail >= 0); + return avail; +} + + +void vmap_free_page(VMap* vmap, PageMapInfo* page) { + deleteElement(vmap->pages, page->key); + page_remove(vmap->mmap, page->key); + free(page); +} + +PageMapInfo* vmap_get_page(VMap* vmap, void* ptr) { + node* current = vmap->pages->head; + while (current) { + PageMapInfo* page = current->data; + if (page->start <= (int64_t)ptr && page->start+PAGE_SIZE > (int64_t)ptr) { + return page; + } + current = current->next; + } + return NULL; +} + +void vmap_unswap(VMap* vmap, PageMapInfo* page) { + if (!page->swapped) + return; + + read_from_swap(vmap->mmap, page_lookup(vmap->mmap, page->key)); + page->swapped = false; +} + + +void* my_malloc(VMap* vmap, int size) { + if (size > PAGE_SIZE) { + fprintf(stderr, "my_malloc: Requesting too much space: %d > %d\n", size, PAGE_SIZE); + exit(1); + } + + // Parcours de la liste pour trouver un candidat. Sinon, nouvelle page + node* current = vmap->pages->head; + while (current) { + PageMapInfo* page = current->data; + if (page_map_available_size(page) >= size) { + void* ptr = (void*)((uint64_t)page->start+page->cursor); + page->cursor += size; + page->nb_allocs++; + + return ptr; + } + current = current->next; + } + + PageMapInfo* page = vmap_new_page(vmap); + + void* ptr = (void*)((uint64_t)page->start+page->cursor); + page->cursor += size; + page->nb_allocs++; + + return ptr; +} + +void my_free(VMap* vmap, void* ptr) { + PageMapInfo* page = vmap_get_page(vmap, ptr); + + if (!page) { + fprintf(stderr, "my_free: Double free or memory corrupted\n"); + exit(1); + } + + page->nb_allocs--; + if (page->nb_allocs == 0) { + vmap_free_page(vmap, page); + } +} + +void my_copy(VMap* vmap, void* src, void* dst, int size) { + PageMapInfo* page_map_src = vmap_get_page(vmap, src); + PageMapInfo* page_map_dst = vmap_get_page(vmap, dst); + + if (((int64_t)src % PAGE_SIZE) + size >= PAGE_SIZE) { + fprintf(stderr, "my_copy: size not available in this src page\n"); + exit(1); + } + + if (((int64_t)dst % PAGE_SIZE) + size >= PAGE_SIZE) { + fprintf(stderr, "my_copy: size not available in this dst page\n"); + exit(1); + } + + if (page_map_src->swapped) { + vmap_unswap(vmap, page_map_src); + } + if (page_map_dst->swapped) { + vmap_unswap(vmap, page_map_dst); + } + + PageInfo* page_src = page_lookup(vmap->mmap, page_map_src->key); + PageInfo* page_dst = page_lookup(vmap->mmap, page_map_dst->key); + + memcpy(page_dst->data+((int64_t)src % PAGE_SIZE), page_src->data+((int64_t)dst % PAGE_SIZE), size); +} + +void vmap_copy_to_memory(struct VMap *vmap, void *src, void *dst, int size) { + PageMapInfo* page_map = vmap_get_page(vmap, src); + PageInfo* page = page_lookup(vmap->mmap, page_map->key); + + if (!page) { + fprintf(stderr, "vmap_copy_to_memory: page not found\n"); + exit(1); + } + + memcpy(page->data + ((int64_t)src % PAGE_SIZE), dst, size); +} + +void vmap_copy_from_memory(struct VMap *vmap, void *src, void *dst, int size) { + PageMapInfo* page_map = vmap_get_page(vmap, dst); + PageInfo* page = page_lookup(vmap->mmap, page_map->key); + + if (!page) { + fprintf(stderr, "vmap_copy_to_memory: page not found\n"); + exit(1); + } + + memcpy(src, page->data + ((int64_t)dst % PAGE_SIZE), size); +} \ No newline at end of file diff --git a/TP/TP2/rendu/vmap.h b/TP/TP2/rendu/vmap.h new file mode 100644 index 0000000..e834308 --- /dev/null +++ b/TP/TP2/rendu/vmap.h @@ -0,0 +1,41 @@ +#ifndef DEF_VMAP_H +#define DEF_VMAP_H + +#include "mmap.h" + +typedef struct VMap { + MMap* mmap; + linkedList* pages; + int index; // index of virt memory +} VMap; + +typedef struct PageMapInfo { + int start; + int key; // key for mmap + int cursor; // Last allocation end + int nb_allocs; // Free page if 0 + bool swapped; +} PageMapInfo; + +VMap* vmap_init(); + +/** + * Get page hosting a certain pointer +*/ +PageMapInfo* vmap_get_page(VMap* vmap, void* ptr); + +/** + * From implemented memory to real memory +*/ +void vmap_copy_to_memory(struct VMap *vmap, void *src, void *dst, int size); + +/** + * From real memory to implemented memory +*/ +void vmap_copy_from_memory(struct VMap *vmap, void *src, void *dst, int size); + +void* my_malloc(VMap* vmap, int size); +void my_free(VMap* vmap, void* ptr); +void my_copy(VMap* vmap, void* src, void* dst, int size); + +#endif \ No newline at end of file diff --git a/TP/TP2/sujet.pdf b/TP/TP2/sujet.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e253fac385c42e665765d47086c98ec36e81e35f GIT binary patch literal 21190 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 L2?;$D1j~N_<-dgt literal 0 HcmV?d00001