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 0000000..e253fac Binary files /dev/null and b/TP/TP2/sujet.pdf differ