From 0fd6bec4a399f508cab5fafe5ad0e7de43f5a220 Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Thu, 8 Dec 2022 10:43:22 -0500 Subject: [PATCH 1/3] Improve human readability of list_head functions. Add message of the day suggesting to use the command. --- files/etc/motd | 1 + mentos/inc/klib/list_head.h | 184 +++++++++++------------ mentos/src/descriptor_tables/interrupt.c | 6 +- mentos/src/fs/ext2.c | 8 +- mentos/src/fs/procfs.c | 14 +- mentos/src/fs/vfs.c | 2 +- mentos/src/hardware/timer.c | 14 +- mentos/src/klib/ndtree.c | 8 +- mentos/src/mem/buddysystem.c | 12 +- mentos/src/mem/paging.c | 6 +- mentos/src/mem/slab.c | 26 ++-- mentos/src/process/process.c | 2 +- mentos/src/process/scheduler.c | 8 +- mentos/src/process/wait.c | 4 +- mentos/src/system/signal.c | 6 +- programs/login.c | 2 + 16 files changed, 148 insertions(+), 155 deletions(-) diff --git a/files/etc/motd b/files/etc/motd index e69de29..fa2afea 100644 --- a/files/etc/motd +++ b/files/etc/motd @@ -0,0 +1 @@ +Call `man` to have a list of all the commands. \ No newline at end of file diff --git a/mentos/inc/klib/list_head.h b/mentos/inc/klib/list_head.h index e15d10e..f000c97 100644 --- a/mentos/inc/klib/list_head.h +++ b/mentos/inc/klib/list_head.h @@ -19,8 +19,7 @@ typedef struct list_head { /// @param ptr The &list_head pointer. /// @param type The type of the struct this is embedded in. /// @param member The name of the list_head within the struct. -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) +#define list_entry(ptr, type, member) container_of(ptr, type, member) /// @brief Iterates over a list. /// @param pos The &list_head to use as a loop cursor. @@ -49,124 +48,115 @@ typedef struct list_head { for (list_head * (pos) = (head)->next; (pos) != (head); (pos) = (pos)->next) /// @brief Initializes the list_head. -/// @param head The head for your list. -#define list_head_init(head) (head)->next = (head)->prev = (head) - -/// @brief Initializes the list_head. -/// @param head The head for your list. -#define list_head_size(head) \ - ({ \ - unsigned __list_head_size = 0; \ - list_for_each_decl(it, head) __list_head_size += 1; \ - __list_head_size; \ - }) - -/// @brief Insert element l2 after l1. -static inline void list_head_insert_after(list_head *l1, list_head *l2) +/// @param head The head of your list. +static inline void list_head_init(list_head *head) { - // [La]->l1 La<-[l1]->Lb <-[l2]-> l1<-[Lb] - - list_head *l1_next = l1->next; - // [La]->l1 La<-[l1]->l2 <-[l2]-> l1<-[Lb] - l1->next = l2; - // [La]->l1 La<-[l1]->l2 l1<-[l2]-> l1<-[Lb] - l2->prev = l1; - // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l1<-[Lb] - l2->next = l1_next; - // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l2<-[Lb] - l1_next->prev = l2; -} - -/// @brief Insert element l2 before l1. -static inline void list_head_insert_before(list_head *l1, list_head *l2) -{ - // [La]->l1 [l2] La<-[l1]->Lb l1<-[Lb] - - list_head *l1_prev = l1->prev; - // [La]->l2 [l2] La<-[l1]->Lb l1<-[Lb] - l1_prev->next = l2; - // [La]->l2 La<-[l2] La<-[l1]->Lb l1<-[Lb] - l2->prev = l1_prev; - // [La]->l2 La<-[l2]->l1 La<-[l1]->Lb l1<-[Lb] - l2->next = l1; - // [La]->l2 La<-[l2]->l1 l2<-[l1]->Lb l1<-[Lb] - l1->prev = l2; -} - -/// @brief Remove l from the list. -/// @param l The element to remove. -static inline void list_head_del(list_head *l) -{ - // [La]->l La<-[l]->Lb l<-[Lb] - - // [La]->Lb La<-[l]->Lb l<-[Lb] - l->prev->next = l->next; - // [La]->Lb La<-[l]->Lb La<-[Lb] - l->next->prev = l->prev; - // [La]->Lb l<-[l]->l La<-[Lb] - l->next = l->prev = l; + head->next = head->prev = head; } /// @brief Tests whether the given list is empty. /// @param head The list to check. /// @return 1 if empty, 0 otherwise. -static inline int list_head_empty(list_head const *head) +static inline int list_head_empty(const list_head *head) { return head->next == head; } -/// Insert a new entry between two known consecutive entries. -static inline void __list_add(list_head *new, list_head *prev, list_head *next) +/// @brief Initializes the list_head. +/// @param head The head for your list. +static inline unsigned list_head_size(const list_head *head) { - // [prev]-> <-[new]-> <-[next] - - // [prev]-> <-[new]-> new<-[next] - next->prev = new; - // [prev]-> <-[new]->next new<-[next] - new->next = next; - // [prev]-> prev<-[new]->next new<-[next] - new->prev = prev; - // [prev]->new prev<-[new]->next new<-[next] - prev->next = new; + unsigned size = 0; + if (!list_head_empty(head)) + list_for_each_decl(it, head) size += 1; + return size; } -/// @brief Insert element l2 before l1. -static inline void list_head_add(list_head *new, list_head *head) +/// @brief Insert the new entry after the given location. +/// @param new_entry the new element we want to insert. +/// @param location the element after which we insert. +static inline void list_head_insert_after(list_head *new_entry, list_head *location) { - __list_add(new, head, head->next); + // We store the old `next` element. + list_head *old_next = location->next; + // We insert our element. + location->next = new_entry; + // We update the `previous` link of our new entry. + new_entry->prev = location; + // We update the `next` link of our new entry. + new_entry->next = old_next; + // We link the previously `next` element to our new entry. + old_next->prev = new_entry; } -/// @brief Insert element l2 before l1. -static inline void list_head_add_tail(list_head *new, list_head *head) +/// @brief Insert the new entry before the given location. +/// @param new_entry the new element we want to insert. +/// @param location the element after which we insert. +static inline void list_head_insert_before(list_head *new_entry, list_head *location) { - __list_add(new, head->prev, head); + // We store the old `previous` element. + list_head *old_prev = location->prev; + // We link the old `previous` element to our new entry. + old_prev->next = new_entry; + // We update the `previous` link of our new entry. + new_entry->prev = old_prev; + // We update the `next` link of our new entry. + new_entry->next = location; + // Finally, we close the link with the old insertion location element. + location->prev = new_entry; } -/// @brief Removes an element from the list pointer, it's used when we have a possibly -/// null list pointer and want to pop an element from it -static inline list_head *list_head_pop(list_head *listp) +/// @brief Removes the given entry from the list it is contained in. +/// @param entry the entry we want to remove. +static inline void list_head_remove(list_head *entry) { - if (list_head_empty(listp)) - return NULL; - - list_head *value = listp->next; - list_head_del(listp->next); - - return value; + // Check if the element is actually in a list. + if (!list_head_empty(entry)) { + // We link the `previous` element to the `next` one. + entry->prev->next = entry->next; + // We link the `next` element to the `previous` one. + entry->next->prev = entry->prev; + // We initialize the entry again. + list_head_init(entry); + } } -static inline list_head *list_head_front(list_head *listp) +/// @brief Removes an element from the list, it's used when we have a possibly +/// null list pointer and want to pop an element from it. +/// @param head the head of the list. +/// @return a list_head pointing to the element we removed, NULL on failure. +static inline list_head *list_head_pop(list_head *head) { - return listp->next; + // Check if the list is not empty. + if (!list_head_empty(head)) { + // Store the pointer. + list_head *value = head->next; + // Remove the element from the list. + list_head_remove(head->next); + // Return the pointer to the element. + return value; + } + return NULL; } -/// Merges the elements of l2, into the elements of l1. -static inline void list_head_merge(list_head *l1, list_head *l2) +/// @brief Append the `secondary` list at the end of the `main` list. +/// @param main the main list where we append the secondary list. +/// @param secondary the secondary list, which gets appended, and re-initialized as empty. +static inline void list_head_append(list_head *main, list_head *secondary) { - l1->prev->next = l2->next; - l2->next->prev = l1->prev; - l2->prev->next = l1; - l1->prev = l2->prev; - // Initialize the second list. - list_head_init(l2); -} \ No newline at end of file + // Check that both lists are actually filled with entries. + if (!list_head_empty(main) && !list_head_empty(secondary)) { + // Connect the last element of the main list to the first one of the secondary list. + main->prev->next = secondary->next; + // Connect the first element of the secondary list to the last one of the main list. + secondary->next->prev = main->prev; + + // Connect the last element of the secondary list to our main. + secondary->prev->next = main; + // Connect our main to the last element of the secondary list. + main->prev = secondary->prev; + + // Re-initialize the secondary list. + list_head_init(secondary); + } +} diff --git a/mentos/src/descriptor_tables/interrupt.c b/mentos/src/descriptor_tables/interrupt.c index 4a5c11b..333c29d 100644 --- a/mentos/src/descriptor_tables/interrupt.c +++ b/mentos/src/descriptor_tables/interrupt.c @@ -51,7 +51,7 @@ static inline irq_struct_t *__irq_struct_alloc() /// @brief Destroys an irq struct. static inline void __irq_struct_dealloc(irq_struct_t *irq_struct) { - list_head_del(&irq_struct->siblings); + list_head_remove(&irq_struct->siblings); kmem_cache_free(irq_struct); } @@ -81,7 +81,7 @@ int irq_install_handler(unsigned i, interrupt_handler_t handler, char *descripti irq_struct->description = description; irq_struct->handler = handler; // Add the handler to the list of his siblings. - list_head_add_tail(&irq_struct->siblings, &shared_interrupt_handlers[i]); + list_head_insert_before(&irq_struct->siblings, &shared_interrupt_handlers[i]); return 0; } @@ -102,7 +102,7 @@ int irq_uninstall_handler(unsigned i, interrupt_handler_t handler) irq_struct_t *irq_struct = list_entry(it, irq_struct_t, siblings); assert(irq_struct && "Something went wrong."); if (irq_struct->handler == handler) { - list_head_del(&irq_struct->siblings); + list_head_remove(&irq_struct->siblings); } __irq_struct_dealloc(irq_struct); } diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index bc64e20..97d157c 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -2259,7 +2259,7 @@ static vfs_file_t *ext2_creat(const char *path, mode_t permission) goto close_parent_return_null; } // Add the vfs_file to the list of associated files. - list_head_add_tail(&file->siblings, &fs->opened_files); + list_head_insert_before(&file->siblings, &fs->opened_files); } return file; } @@ -2378,7 +2378,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) return NULL; } // Add the vfs_file to the list of associated files. - list_head_add_tail(&file->siblings, &fs->opened_files); + list_head_insert_before(&file->siblings, &fs->opened_files); } return file; } @@ -2487,7 +2487,7 @@ static int ext2_close(vfs_file_t *file) } pr_debug("ext2_close(ino: %d, file: \"%s\")\n", file->ino, file->name); // Remove the file from the list of opened files. - list_head_del(&file->siblings); + list_head_remove(&file->siblings); // Free the cache. kmem_cache_free(file); return 0; @@ -3040,7 +3040,7 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) goto free_all; } // Add the root to the list of opened files. - list_head_add_tail(&fs->root->siblings, &fs->opened_files); + list_head_insert_before(&fs->root->siblings, &fs->opened_files); // Dump the filesystem details for debugging. ext2_dump_filesystem(fs); diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index 4dea6fa..cf87879 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -253,7 +253,7 @@ static inline procfs_file_t *procfs_create_file(const char *path, unsigned flags // List of all the PROCFS files. list_head_init(&procfs_file->siblings); // Add the file to the list of opened files. - list_head_add_tail(&procfs_file->siblings, &fs.files); + list_head_insert_before(&procfs_file->siblings, &fs.files); // Time of last access. procfs_file->atime = sys_time(NULL); // Time of last data modification. @@ -282,7 +282,7 @@ static inline int procfs_destroy_file(procfs_file_t *procfs_file) } pr_debug("procfs_destroy_file(%p) `%s`\n", procfs_file, procfs_file->name); // Remove the file from the list of opened files. - list_head_del(&procfs_file->siblings); + list_head_remove(&procfs_file->siblings); // Free the cache. kmem_cache_free(procfs_file); // Decrease the number of files. @@ -467,7 +467,7 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) // Update file access. procfs_file->atime = sys_time(NULL); // Add the vfs_file to the list of associated files. - list_head_add_tail(&vfs_file->siblings, &procfs_file->files); + list_head_insert_before(&vfs_file->siblings, &procfs_file->files); return vfs_file; } // Check if the user did not want to open a directory, but it is. @@ -486,7 +486,7 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) // Update file access. procfs_file->atime = sys_time(NULL); // Add the vfs_file to the list of associated files. - list_head_add_tail(&vfs_file->siblings, &procfs_file->files); + list_head_insert_before(&vfs_file->siblings, &procfs_file->files); return vfs_file; } // When both O_CREAT and O_DIRECTORY are specified in flags and the file @@ -508,7 +508,7 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) return NULL; } // Add the vfs_file to the list of associated files. - list_head_add_tail(&vfs_file->siblings, &procfs_file->files); + list_head_insert_before(&vfs_file->siblings, &procfs_file->files); pr_debug("Created file `%s`.\n", path); return vfs_file; } @@ -523,7 +523,7 @@ static int procfs_close(vfs_file_t *file) assert(file && "Received null file."); //pr_debug("procfs_close(%p): VFS file : %p\n", file, file); // Remove the file from the list of `files` inside its corresponding `procfs_file_t`. - list_head_del(&file->siblings); + list_head_remove(&file->siblings); // Free the memory of the file. kmem_cache_free(file); return 0; @@ -778,7 +778,7 @@ static vfs_file_t *procfs_mount_callback(const char *path, const char *device) vfs_file_t *vfs_file = procfs_create_file_struct(procfs_file); assert(vfs_file && "Failed to create vfs_file."); // Add the vfs_file to the list of associated files. - list_head_add_tail(&vfs_file->siblings, &procfs_file->files); + list_head_insert_before(&vfs_file->siblings, &procfs_file->files); // Initialize the proc_root. return vfs_file; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 88b9d04..5a85272 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -416,7 +416,7 @@ int vfs_mount(const char *path, vfs_file_t *new_fs_root) // Set the pointer. sb->root = new_fs_root; // Add to the list. - list_head_add(&sb->mounts, &vfs_super_blocks); + list_head_insert_after(&sb->mounts, &vfs_super_blocks); } spinlock_unlock(&vfs_spinlock); pr_debug("Correctly mounted '%s' on '%s'...\n", new_fs_root->name, path); diff --git a/mentos/src/hardware/timer.c b/mentos/src/hardware/timer.c index 0280638..f3bb9af 100644 --- a/mentos/src/hardware/timer.c +++ b/mentos/src/hardware/timer.c @@ -314,7 +314,7 @@ static void __add_timer_tvec_base(tvec_base_t *base, struct timer_list *timer) } pr_debug("Adding timer at time_index: %d in tv%d\n", index, tv_index); - list_head_add_tail(&timer->entry, vec); + list_head_insert_before(&timer->entry, vec); #ifdef ENABLE_REAL_TIMER_SYSTEM_DUMP __dump_all_tvec_slots(base); @@ -347,7 +347,7 @@ static void __rem_timer_tvec_base(tvec_base_t *base, struct timer_list *timer) } pr_debug("Removing timer at time_index: %d in tv%d\n", index, tv_index); - list_head_del(&timer->entry); + list_head_remove(&timer->entry); #ifdef ENABLE_REAL_TIMER_SYSTEM_DUMP __dump_all_tvec_slots(base); @@ -364,7 +364,7 @@ static int cascate(tvec_base_t *base, timer_vec *tv, int time_index, int tv_inde struct list_head *it, *tmp; list_for_each_safe (it, tmp, tv->vec + time_index) { struct timer_list *timer = list_entry(it, struct timer_list, entry); - list_head_del(it); + list_head_remove(it); __add_timer_tvec_base(base, timer); } @@ -425,7 +425,7 @@ void run_timer_softirq() spinlock_lock(&base->lock); // Removes timer from list - list_head_del(it); + list_head_remove(it); kfree(timer); } } @@ -453,7 +453,7 @@ void run_timer_softirq() // Removes timer from list pr_debug("Removing dynamic timer...\n"); - list_head_del(it); + list_head_remove(it); kfree(timer); } } @@ -479,7 +479,7 @@ void add_timer(struct timer_list *timer) #ifdef ENABLE_REAL_TIMER_SYSTEM __add_timer_tvec_base(base, timer); #else - list_head_add_tail(&timer->entry, &base->list); + list_head_insert_before(&timer->entry, &base->list); #endif } @@ -491,7 +491,7 @@ void del_timer(struct timer_list *timer) #ifdef ENABLE_REAL_TIMER_SYSTEM __rem_timer_tvec_base(base, timer); #else - list_head_del(&timer->entry); + list_head_remove(&timer->entry); #endif } diff --git a/mentos/src/klib/ndtree.c b/mentos/src/klib/ndtree.c index 3835f45..444f7de 100644 --- a/mentos/src/klib/ndtree.c +++ b/mentos/src/klib/ndtree.c @@ -112,7 +112,7 @@ ndtree_node_t *ndtree_get_root(ndtree_t *tree) void ndtree_add_child_to_node(ndtree_t *tree, ndtree_node_t *parent, ndtree_node_t *child) { child->parent = parent; - list_head_add(&child->siblings, &parent->children); + list_head_insert_after(&child->siblings, &parent->children); ++tree->size; } @@ -172,7 +172,7 @@ static void __ndtree_tree_dealloc_rec(ndtree_t *tree, ndtree_node_t *node, ndtre { ndtree_node_t *entry = list_entry(it, ndtree_node_t, siblings); it_save = it->prev; - list_head_del(it); + list_head_remove(it); it = it_save; __ndtree_tree_dealloc_rec(tree, entry, node_cb); } @@ -249,7 +249,7 @@ int ndtree_tree_remove_node_with_cb(ndtree_t *tree, ndtree_node_t *node, ndtree_ { if (tree && node) { // Remove the node from the parent list. - list_head_del(&node->siblings); + list_head_remove(&node->siblings); // If the node has children, we need to migrate them. if (!list_head_empty(&node->children)) { // The new parent, by default it is NULL. @@ -269,7 +269,7 @@ int ndtree_tree_remove_node_with_cb(ndtree_t *tree, ndtree_node_t *node, ndtree_ child->parent = new_parent; } // Merge the lists. - list_head_merge(new_list, &node->children); + list_head_append(new_list, &node->children); } if (node_cb) node_cb(tree, node); diff --git a/mentos/src/mem/buddysystem.c b/mentos/src/mem/buddysystem.c index da6e4ad..a381339 100644 --- a/mentos/src/mem/buddysystem.c +++ b/mentos/src/mem/buddysystem.c @@ -148,7 +148,7 @@ block_found: page = list_entry(/* ... */, /* ... */, /* ... */); // Remove the descriptor of its first page frame. - list_head_del(&/* ... */); + list_head_remove(&/* ... */); // Set the page as allocated, thus, remove the flag FREE_PAGE. __bb_clear_flag(/* ... */, /* ... */); @@ -182,7 +182,7 @@ block_found: assert(/* ... */ &&!/* ... */); // Insert buddy as first element in the list of available blocks (free_list). - list_head_add(&/* ... */.siblings, &/* ... */); + list_head_insert_after(&/* ... */.siblings, &/* ... */); // Increase the number of free block of the free_area_t. /* ... */ += 1; @@ -277,7 +277,7 @@ void bb_free_pages(bb_instance_t *instance, bb_page_t *page) /* ... */; // Insert coalesced as first element in the free list. - list_head_add(&/* ... */, &/* ... */); + list_head_insert_after(&/* ... */, &/* ... */); // Increase the number of free block of the free_area_t. /* ... */; @@ -342,7 +342,7 @@ void buddy_system_init(bb_instance_t *instance, // Set the page as root. __bb_set_flag(page, ROOT_PAGE); // Insert the page inside the list of free pages of the area. - list_head_add_tail(&page->location.siblings, &area->free_list); + list_head_insert_before(&page->location.siblings, &area->free_list); // Increase the number of free block of the area. area->nr_free++; // Move to the next page. @@ -388,7 +388,7 @@ static void __cache_extend(bb_instance_t *instance, int count) { for (int i = 0; i < count; i++) { bb_page_t *page = bb_alloc_pages(instance, 0); - list_head_add(&page->location.cache, &instance->free_pages_cache_list); + list_head_insert_after(&page->location.cache, &instance->free_pages_cache_list); instance->free_pages_cache_size++; } } @@ -417,7 +417,7 @@ static bb_page_t *__cached_alloc(bb_instance_t *instance) static void __cached_free(bb_instance_t *instance, bb_page_t *page) { - list_head_add(&page->location.cache, &instance->free_pages_cache_list); + list_head_insert_after(&page->location.cache, &instance->free_pages_cache_list); if (instance->free_pages_cache_size > HIGH_WATERMARK_LEVEL) { // Free pages to the buddy system diff --git a/mentos/src/mem/paging.c b/mentos/src/mem/paging.c index dedc532..9af1ac3 100644 --- a/mentos/src/mem/paging.c +++ b/mentos/src/mem/paging.c @@ -104,7 +104,7 @@ uint32_t create_vm_area(mm_struct_t *mm, new_segment->vm_mm = mm; // Update memory descriptor list of vm_area_struct. - list_head_add(&new_segment->vm_list, &mm->mmap_list); + list_head_insert_after(&new_segment->vm_list, &mm->mmap_list); mm->mmap_cache = new_segment; // Update memory descriptor info. @@ -152,7 +152,7 @@ uint32_t clone_vm_area(mm_struct_t *mm, vm_area_struct_t *area, int cow, uint32_ } // Update memory descriptor list of vm_area_struct. - list_head_add(&new_segment->vm_list, &mm->mmap_list); + list_head_insert_after(&new_segment->vm_list, &mm->mmap_list); mm->mmap_cache = new_segment; // Update memory descriptor info. @@ -607,7 +607,7 @@ void destroy_process_image(mm_struct_t *mm) // Delete segment from the mmap it = segment->vm_list.next; - list_head_del(&segment->vm_list); + list_head_remove(&segment->vm_list); --mm->map_count; kmem_cache_free(segment); diff --git a/mentos/src/mem/slab.c b/mentos/src/mem/slab.c index 119073c..da1b01f 100644 --- a/mentos/src/mem/slab.c +++ b/mentos/src/mem/slab.c @@ -71,11 +71,11 @@ static int __alloc_slab_page(kmem_cache_t *cachep, gfp_t flags) // Build the objects structures for (unsigned int i = 0; i < page->slab_objcnt; i++) { kmem_obj *obj = KMEM_OBJ(cachep, pg_addr + cachep->size * i); - list_head_add(&obj->objlist, &page->slab_freelist); + list_head_insert_after(&obj->objlist, &page->slab_freelist); } // Add the page to the slab list and update the counters - list_head_add(&page->slabs, &cachep->slabs_free); + list_head_insert_after(&page->slabs, &cachep->slabs_free); cachep->total_num += page->slab_objcnt; cachep->free_num += page->slab_objcnt; @@ -132,7 +132,7 @@ static void __kmem_cache_create(kmem_cache_t *cachep, const char *name, unsigned __kmem_cache_refill(cachep, start_count, flags); - list_head_add(&cachep->cache_list, &kmem_caches_list); + list_head_insert_after(&cachep->cache_list, &kmem_caches_list); } static inline void *__kmem_cache_alloc_slab(kmem_cache_t *cachep, page_t *slab_page) @@ -161,7 +161,7 @@ static inline void __kmem_cache_free_slab(kmem_cache_t *cachep, page_t *slab_pag cachep->free_num -= slab_page->slab_objfree; cachep->total_num -= slab_page->slab_objcnt; // Clear objcnt, used as a flag to check if the page belongs to the slab - slab_page->slab_objcnt = 0; + slab_page->slab_objcnt = 0; slab_page->container.slab_main_page = NULL; // Reset all non-root slab pages @@ -225,7 +225,7 @@ void kmem_cache_destroy(kmem_cache_t *cachep) } kmem_cache_free(cachep); - list_head_del(&cachep->cache_list); + list_head_remove(&cachep->cache_list); } #ifdef ENABLE_CACHE_TRACE @@ -251,16 +251,16 @@ void *kmem_cache_alloc(kmem_cache_t *cachep, gfp_t flags) // Add a free slab to partial list because in any case an element will // be removed before the function returns list_head *free_slab = list_head_pop(&cachep->slabs_free); - list_head_add(free_slab, &cachep->slabs_partial); + list_head_insert_after(free_slab, &cachep->slabs_partial); } - page_t *slab_page = list_entry(list_head_front(&cachep->slabs_partial), page_t, slabs); + page_t *slab_page = list_entry(cachep->slabs_partial.next, page_t, slabs); void *ptr = __kmem_cache_alloc_slab(cachep, slab_page); // If the slab is now full, add it to the full slabs list if (slab_page->slab_objfree == 0) { list_head *slab_full_elem = list_head_pop(&cachep->slabs_partial); - list_head_add(slab_full_elem, &cachep->slabs_full); + list_head_insert_after(slab_full_elem, &cachep->slabs_full); } #ifdef ENABLE_CACHE_TRACE pr_notice("CHACE-ALLOC 0x%p in %-20s at %s:%d\n", ptr, cachep->name, file, line); @@ -292,23 +292,23 @@ void kmem_cache_free(void *ptr) kmem_obj *obj = KMEM_OBJ(cachep, ptr); // Add object to the free list - list_head_add(&obj->objlist, &slab_page->slab_freelist); + list_head_insert_after(&obj->objlist, &slab_page->slab_freelist); slab_page->slab_objfree++; cachep->free_num++; // Now page is completely free if (slab_page->slab_objfree == slab_page->slab_objcnt) { // Remove page from partial list - list_head_del(&slab_page->slabs); + list_head_remove(&slab_page->slabs); // Add page to free list - list_head_add(&slab_page->slabs, &cachep->slabs_free); + list_head_insert_after(&slab_page->slabs, &cachep->slabs_free); } // Now page is not full, so change its list else if (slab_page->slab_objfree == 1) { // Remove page from full list - list_head_del(&slab_page->slabs); + list_head_remove(&slab_page->slabs); // Add page to partial list - list_head_add(&slab_page->slabs, &cachep->slabs_partial); + list_head_insert_after(&slab_page->slabs, &cachep->slabs_partial); } } diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index b7c35ee..1e0105f 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -171,7 +171,7 @@ static inline task_struct *__alloc_task(task_struct *source, task_struct *parent // If we have a parent, set the sibling child relation. if (parent) { // Set the new_process as child of current. - list_head_add_tail(&proc->sibling, &parent->children); + list_head_insert_before(&proc->sibling, &parent->children); } if (source) memcpy(&proc->thread, &source->thread, sizeof(thread_struct_t)); diff --git a/mentos/src/process/scheduler.c b/mentos/src/process/scheduler.c index 2c46bdf..f2d3b37 100644 --- a/mentos/src/process/scheduler.c +++ b/mentos/src/process/scheduler.c @@ -108,7 +108,7 @@ void scheduler_enqueue_task(task_struct *process) runqueue.curr = process; } // Add the new process at the end. - list_head_add_tail(&process->run_list, &runqueue.queue); + list_head_insert_before(&process->run_list, &runqueue.queue); // Increment the number of active processes. ++runqueue.num_active; } @@ -116,7 +116,7 @@ void scheduler_enqueue_task(task_struct *process) void scheduler_dequeue_task(task_struct *process) { // Delete the process from the list of running processes. - list_head_del(&process->run_list); + list_head_remove(&process->run_list); // Decrement the number of active processes. --runqueue.num_active; if (process->se.is_periodic) @@ -484,7 +484,7 @@ pid_t sys_waitpid(pid_t pid, int *status, int options) // Finalize the VFS structures. vfs_destroy_task(entry); // Remove entry from children of parent. - list_head_del(&entry->sibling); + list_head_remove(&entry->sibling); // Remove entry from the scheduling queue. scheduler_dequeue_task(entry); // Delete the task_struct. @@ -535,7 +535,7 @@ void sys_exit(int exit_code) } pr_debug("}\n"); // Plug the list of children. - list_head_merge(&init_proc->children, &runqueue.curr->children); + list_head_append(&init_proc->children, &runqueue.curr->children); // Print the list of children. pr_debug("New list of init children (%d): {\n", init_proc->pid); list_for_each_decl(it, &init_proc->children) diff --git a/mentos/src/process/wait.c b/mentos/src/process/wait.c index e7bca1b..3b16a10 100644 --- a/mentos/src/process/wait.c +++ b/mentos/src/process/wait.c @@ -14,12 +14,12 @@ static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq) { - list_head_add_tail(&wq->task_list, &head->task_list); + list_head_insert_before(&wq->task_list, &head->task_list); } static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq) { - list_head_del(&wq->task_list); + list_head_remove(&wq->task_list); } void init_waitqueue_entry(wait_queue_entry_t *wq, struct task_struct *task) diff --git a/mentos/src/system/signal.c b/mentos/src/system/signal.c index 8d6f7d7..75105bd 100644 --- a/mentos/src/system/signal.c +++ b/mentos/src/system/signal.c @@ -157,7 +157,7 @@ static int __send_signal(int sig, siginfo_t *info, struct task_struct *t) __unlock_task_sighand(t); return -EAGAIN; } - list_head_add_tail(&q->list, &t->pending.list); + list_head_insert_before(&q->list, &t->pending.list); if (info != SEND_SIG_NOINFO) memcpy(&q->info, info, sizeof(siginfo_t)); // Set that there is a signal pending. @@ -219,7 +219,7 @@ static inline void __collect_signal(int sig, sigpending_t *list, siginfo_t *info if (queue_entry) { pr_debug("__collect_signal(%d, %p, %p) : Remove and delete sigqueue entry : %p.\n", sig, list, info, queue_entry); // Remove the entry from the queue. - list_head_del(&queue_entry->list); + list_head_remove(&queue_entry->list); // Copy the details about the entry inside the info structure. __copy_siginfo(info, &queue_entry->info); // Free the memory for the queue entry. @@ -346,7 +346,7 @@ static void __rm_from_queue(sigset_t *mask, sigpending_t *q) int sig = entry->info.si_signo; if (sigismember(mask, sig)) { - list_head_del(it); + list_head_remove(it); kfree(entry); } } diff --git a/programs/login.c b/programs/login.c index de9d6e3..51e1f86 100644 --- a/programs/login.c +++ b/programs/login.c @@ -205,6 +205,8 @@ int main(int argc, char **argv) // Set the user id. setuid(pwd->pw_uid); + printf("\n"); + // Print /etc/motd if it exists. __print_message_file("/etc/motd"); From 5aaddd467c2981673f26991d9c95a8b6c733605d Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Thu, 8 Dec 2022 11:26:31 -0500 Subject: [PATCH 2/3] Improve human readability of the Round-Robin algorithm. --- mentos/src/process/scheduler_algorithm.c | 84 ++++++++++++------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/mentos/src/process/scheduler_algorithm.c b/mentos/src/process/scheduler_algorithm.c index 8400980..4d4fef4 100644 --- a/mentos/src/process/scheduler_algorithm.c +++ b/mentos/src/process/scheduler_algorithm.c @@ -22,78 +22,78 @@ /// @param task the task to update. static void __update_task_statistics(task_struct *task); +/// @brief Checks if the given task is actually a periodic task. +/// @param task the task to check. +/// @return true if the task is periodic, false otherwise. +static inline bool_t __is_periodic_task(task_struct *task) +{ + // Check if the task is a periodic one and it is not under analysis. + return task->se.is_periodic && !task->se.is_under_analysis; +} + /// @brief Employs time-sharing, giving each job a timeslice, and is also /// preemptive since the scheduler forces the task out of the CPU once /// the timeslice expires. /// @param runqueue list of all processes. -/// @param skip_periodic tells the algorithm if there are periodic processes -/// in the list, and in that case it needs to skip them. +/// @param skip_periodic tells the algorithm if there are periodic processes in +/// the list, and in that case it needs to skip them. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_rr(runqueue_t *runqueue, bool_t skip_periodic) { - // If there is just one task, return it. - if ((runqueue->curr->run_list.next == &runqueue->queue) && - (runqueue->curr->run_list.prev == &runqueue->queue)) { + // If there is just one task, return it; no need to do anything. + if (list_head_size(&runqueue->curr->run_list) <= 1) { return runqueue->curr; } - // By default, the next task is the current one. - task_struct *next = NULL, *entry = NULL; - // Search for the next task (BEWARE: We do not start from the head, so INSIDE skip the head). + // Search for the next task (we do not start from the head, so INSIDE, skip the head). list_for_each_decl(it, &runqueue->curr->run_list) { // Check if we reached the head of list_head, and skip it. if (it == &runqueue->queue) continue; // Get the current entry. - entry = list_entry(it, task_struct, run_list); - + task_struct *entry = list_entry(it, task_struct, run_list); // We consider only runnable processes if (entry->state != TASK_RUNNING) continue; - - // Skip the task if it is a periodic one, we are issued to skip - // periodic tasks, and the entry is not a periodic task under - // analysis. - if (entry->se.is_periodic && skip_periodic && !entry->se.is_under_analysis) + // If entry is a periodic task, and we were asked to skip periodic tasks, skip it. + if (__is_periodic_task(entry) && skip_periodic) continue; - // We have our next entry. - next = entry; - break; + return entry; } - return next; + return NULL; } /// @brief Is a non-preemptive algorithm, where each task is assigned a /// priority. Processes with highest priority are executed first, while -/// processes with same priority are executed on first-come/first-served -/// basis. Priority can be decided based on memory requirements, time -/// requirements or any other resource requirement. +/// processes with same priority are executed on first-come/first-served basis. +/// Priority can be decided based on memory requirements, time requirements or +/// any other resource requirement. /// @param runqueue list of all processes. -/// @param skip_periodic tells the algorithm if there are periodic processes -/// in the list, and in that case it needs to skip them. +/// @param skip_periodic tells the algorithm if there are periodic processes in +/// the list, and in that case it needs to skip them. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_priority(runqueue_t *runqueue, bool_t skip_periodic) { return __scheduler_rr(runqueue, skip_periodic); } -/// @brief It aims at giving a fair share of CPU time to processes, and -/// achieves that by associating a virtual runtime to each of them. It always -/// tries to run the task with the smallest vruntime (i.e., the task which -/// executed least so far). It always tries to split up CPU time between -/// runnable tasks as close to "ideal multitasking hardware" as possible. +/// @brief It aims at giving a fair share of CPU time to processes, and achieves +/// that by associating a virtual runtime to each of them. It always tries to +/// run the task with the smallest vruntime (i.e., the task which executed least +/// so far). It always tries to split up CPU time between runnable tasks as +/// close to "ideal multitasking hardware" as possible. /// @param runqueue list of all processes. -/// @param skip_periodic tells the algorithm if there are periodic processes -/// in the list, and in that case it needs to skip them. +/// @param skip_periodic tells the algorithm if there are periodic processes in +/// the list, and in that case it needs to skip them. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_cfs(runqueue_t *runqueue, bool_t skip_periodic) { return __scheduler_rr(runqueue, skip_periodic); } -/// @brief Executes the task with the earliest absolute deadline among all -/// the ready tasks. +/// @brief Executes the task with the earliest absolute deadline among all the +/// ready tasks. /// @param runqueue list of all processes. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_aedf(runqueue_t *runqueue) @@ -101,10 +101,10 @@ static inline task_struct *__scheduler_aedf(runqueue_t *runqueue) return __scheduler_rr(runqueue, false); } -/// @brief Executes the task with the earliest absolute DEADLINE among all -/// the ready tasks. When a task was executed, and its period is starting -/// again, it must be set as 'executable again', and its deadline and next_period -/// must be updated. +/// @brief Executes the task with the earliest absolute DEADLINE among all the +/// ready tasks. When a task was executed, and its period is starting again, it +/// must be set as 'executable again', and its deadline and next_period must be +/// updated. /// @param runqueue list of all processes. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_edf(runqueue_t *runqueue) @@ -112,11 +112,11 @@ static inline task_struct *__scheduler_edf(runqueue_t *runqueue) return __scheduler_rr(runqueue, false); } -/// @brief Executes the task with the earliest next PERIOD among all the -/// ready tasks. -/// @details When a task was executed, and its period is starting again, it -/// must be set as 'executable again', and its deadline and next_period must -/// be updated. +/// @brief Executes the task with the earliest next PERIOD among all the ready +/// tasks. +/// @details When a task was executed, and its period is starting again, it must +/// be set as 'executable again', and its deadline and next_period must be +/// updated. /// @param runqueue list of all processes. /// @return the next task on success, NULL on failure. static inline task_struct *__scheduler_rm(runqueue_t *runqueue) From a64ce2f81d1e581744b37cce4f406b0272635251 Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Thu, 8 Dec 2022 11:28:17 -0500 Subject: [PATCH 3/3] Update version. --- doc/doxygen/Doxyfile | 2 +- mentos/inc/version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 553c528..85ae8c8 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = MentOS # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.4.0 +PROJECT_NUMBER = 0.5.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/mentos/inc/version.h b/mentos/inc/version.h index a82eb80..60e92eb 100644 --- a/mentos/inc/version.h +++ b/mentos/inc/version.h @@ -18,10 +18,10 @@ #define OS_MAJOR_VERSION 0 /// Minor version of the operating system. -#define OS_MINOR_VERSION 4 +#define OS_MINOR_VERSION 5 /// Micro version of the operating system. -#define OS_MICRO_VERSION 0 +#define OS_MICRO_VERSION 1 /// Helper to transform the given argument into a string. #define OS_STR_HELPER(x) #x