Update MentOs code to the latest development version.

This commit is contained in:
Enrico Fraccaroli
2021-10-04 11:44:02 +02:00
parent 6fd063984a
commit b01eccca2e
484 changed files with 42358 additions and 20285 deletions
+38 -21
View File
@@ -1,15 +1,9 @@
/// MentOS, The Mentoring Operating system project
/// @file prio.h
/// @brief Defines processes priority value.
/// @copyright (c) 2019 This file is distributed under the MIT License.
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#define MAX_NICE +19
#define MIN_NICE -20
#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1)
// Priority of a process goes from 0..MAX_PRIO-1, valid RT
// priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
// tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
@@ -21,35 +15,58 @@
// priority to a value higher than any user task.
// Note: MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
/// @brief Max niceness value.
#define MAX_NICE +19
/// @brief Min niceness value.
#define MIN_NICE -20
/// @brief Niceness range.
#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1)
/// @brief Maximum real-time priority.
#define MAX_RT_PRIO 100
/// @brief Maximum priority.
#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH)
/// @brief Default priority.
#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
// Convert user-nice values [ -20 ... 0 ... 19 ]
// to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
// and back.
/// @brief Converts user-nice values [ -20 ... 0 ... 19 ]
/// to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ].
#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO)
/// @brief Converts static priority [ MAX_RT_PRIO..MAX_PRIO-1 ]
/// to user-nice values [ -20 ... 0 ... 19 ].
#define PRIO_TO_NICE(prio) ((prio)-DEFAULT_PRIO)
// 'User priority' is the nice value converted to something we
// can work with better when scaling various scheduler parameters,
// it's a [ 0 ... 39 ] range.
/// @brief 'User priority' is the nice value converted to something we
/// can work with better when scaling various scheduler parameters,
/// it's a [ 0 ... 39 ] range.
#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
/// @brief Provide easy access to the priority value of a task_struct.
#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
/// @brief The maximum priority for a user process.
#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
/// @brief Table that transforms the priority into a weight, used for
/// computing the virtual runtime.
static const int prio_to_weight[NICE_WIDTH] = {
/* 100 */ 88761, 71755, 56483, 46273, 36291,
/* 105 */ 29154, 23254, 18705, 14949, 11916,
/* 110 */ 9548, 7620, 6100, 4904, 3906,
/* 115 */ 3121, 2501, 1991, 1586, 1277,
/* 120 */ 1024, 820, 655, 526, 423,
/* 125 */ 335, 272, 215, 172, 137,
/* 130 */ 110, 87, 70, 56, 45,
/* 135 */ 36, 29, 23, 18, 15
/* 100 */ 88761, 71755, 56483, 46273, 36291,
/* 105 */ 29154, 23254, 18705, 14949, 11916,
/* 110 */ 9548, 7620, 6100, 4904, 3906,
/* 115 */ 3121, 2501, 1991, 1586, 1277,
/* 120 */ 1024, 820, 655, 526, 423,
/* 125 */ 335, 272, 215, 172, 137,
/* 130 */ 110, 87, 70, 56, 45,
/* 135 */ 36, 29, 23, 18, 15
};
/// @brief Transforms the priority to weight.
#define GET_WEIGHT(prio) prio_to_weight[USER_PRIO((prio))]
/// @brief Weight of a default priority.
#define NICE_0_LOAD GET_WEIGHT(DEFAULT_PRIO)
+138 -163
View File
@@ -1,23 +1,14 @@
/// MentOS, The Mentoring Operating system project
/// @file process.h
/// @brief Process data structures and functions.
/// @copyright (c) 2019 This file is distributed under the MIT License.
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "list.h"
#include "tree.h"
#include "clock.h"
#include "types.h"
#include "stdint.h"
#include "stddef.h"
#include "paging.h"
#include "kernel.h"
#include "unistd.h"
#include "list_head.h"
#include "signal_defs.h"
#include "limits.h"
#include "signal.h"
#include "fpu.h"
/// The maximum length of a name for a task_struct.
#define TASK_NAME_MAX_LENGTH 100
@@ -25,179 +16,163 @@
/// The default dimension of the stack of a process (1 MByte).
#define DEFAULT_STACK_SIZE 0x100000
//==== Task state ==============================================================
// Used in tsk->state
/// The task is running.
#define TASK_RUNNING 0x0000
/// The task is interruptible.
#define TASK_INTERRUPTIBLE 0x0001
/// The task is uninterruptible.
#define TASK_UNINTERRUPTIBLE 0x0002
// Used in tsk->exit_state
/// The task is dead.
#define EXIT_DEAD 0x0010
/// The task is zombie.
#define EXIT_ZOMBIE 0x0020
//==============================================================================
/// @brief Every task_struck has a sched_entity. This structure is used to track
/// the statistics of a process. While the other variables also play a role in
/// @brief This structure is used to track the statistics of a process.
/// @details
/// While the other variables also play a role in
/// CFS decisions'algorithm, vruntime is by far the core variable which needs
/// more attention as to understand the scheduling decision process.
/// @details
///
/// The nice value is a user-space and priority 'prio' is the process's actual
/// priority that use by Linux kernel. In linux system priorities are 0 to 139
/// in which 0 to 99 for real time and 100 to 139 for users.
/// The nice value range is -20 to +19 where -20 is highest, 0 default and +19
/// is lowest. relation between nice value and priority is : PR = 20 + NI.
typedef struct sched_entity {
/// Static execution priority.
int prio;
typedef struct sched_entity_t {
/// Static execution priority.
int prio;
/// Start execution time.
time_t start_runtime;
/// Start execution time.
time_t start_runtime;
/// Last context switch time.
time_t exec_start;
/// Last execution time.
time_t exec_runtime;
/// Overall execution time.
time_t sum_exec_runtime;
/// Weighted execution time.
time_t vruntime;
/// Last context switch time.
time_t exec_start;
/// Expected period of the task
time_t period;
/// Absolute deadline
time_t deadline;
/// Absolute time of arrival of the task
time_t arrivaltime;
/// Has already executed
bool_t executed;
/// Determines if it is a periodic task.
bool_t is_periodic;
/// Determines if we need to analyze the WCET of the process.
bool_t is_under_analysis;
/// Beginning of next period
time_t next_period;
/// Worst case execution time
time_t worst_case_exec;
/// Processor utilization factor
double utilization_factor;
} sched_entity_t;
/// Overall execution time.
time_t sum_exec_runtime;
/// weighted execution time.
time_t vruntime;
} sched_entity;
// x86 thread (x86 and FPU registers).
typedef struct thread_struct {
/// 32-bit base pointer register.
uint32_t ebp;
/// 32-bit stack pointer register.
uint32_t useresp;
/// 32-bit base register.
uint32_t ebx;
/// 32-bit data register.
uint32_t edx;
/// 32-bit counter.
uint32_t ecx;
/// 32-bit accumulator register.
uint32_t eax;
/// Instruction Pointer Register.
uint32_t eip;
/// 32-bit flag register.
uint32_t eflags;
/// FS and GS have no hardware-assigned uses.
uint32_t gs;
/// FS and GS have no hardware-assigned uses.
uint32_t fs;
/// Extra Segment determined by the programmer.
uint32_t es;
/// Data Segment.
uint32_t ds;
/// 32-bit destination register.
uint32_t edi;
/// 32-bit source register.
uint32_t esi;
// ///< Code Segment.
// uint32_t cs;
// ///< Stack Segment.
// uint32_t ss;
/// Determines if the FPU is enabled.
bool_t fpu_enabled;
/// Data structure used to save FPU registers.
savefpu fpu_register;
} thread_struct;
/// @brief Stores the status of CPU and FPU registers.
typedef struct thread_struct_t {
/// Stored status of registers.
pt_regs regs;
/// Stored status of registers befor jumping into a signal handler.
pt_regs signal_regs;
/// Determines if the FPU is enabled.
bool_t fpu_enabled;
/// Data structure used to save FPU registers.
savefpu fpu_register;
} thread_struct_t;
/// @brief this is our task object. Every process in the system has this, and
/// it holds a lot of information. Itll hold mm information, its name,
/// statistics, etc..
typedef struct task_struct {
/// The pid of the process.
pid_t pid;
/// The pid of the process.
pid_t pid;
/// The session id of the process
pid_t sid;
/// The Group Id of the process
pid_t gid;
/// The uid of the user owning the process.
pid_t uid;
// -1 unrunnable, 0 runnable, >0 stopped.
/// The current state of the process:
__volatile__ long state;
/// The current opened file descriptors
vfs_file_descriptor_t *fd_list;
/// The maximum supported number of file descriptors
int max_fd;
/// Pointer to process's parent.
struct task_struct *parent;
/// List head for scheduling purposes.
list_head run_list;
/// List of children traced by the process.
list_head children;
/// List of siblings.
list_head sibling;
/// The context of the processors.
thread_struct_t thread;
/// For scheduling algorithms.
sched_entity_t se;
/// Exit code of the process. (parameter of _exit() system call).
int exit_code;
/// The name of the task (Added for debug purpose).
char name[TASK_NAME_MAX_LENGTH];
/// Task's segments.
mm_struct_t *mm;
/// Task's specific error number.
int error_no;
/// The current working directory.
char cwd[PATH_MAX];
// -1 unrunnable, 0 runnable, >0 stopped.
/// The current state of the process:
__volatile__ long state;
// struct signal_struct *signal;
/// Instruction Pointer of the LIBC Signal Handler.
uint32_t sigreturn_eip;
/// Pointer to the processs signal handler descriptor
sighand_t sighand;
/// Mask of blocked signals.
sigset_t blocked;
/// Temporary mask of blocked signals (used by the rt_sigtimedwait() system call)
sigset_t real_blocked;
/// The previous sig mask.
sigset_t saved_sigmask;
/// Data structure storing the private pending signals
sigpending_t pending;
/// Pointer to process's parent.
struct task_struct *parent;
/// Timer for alarm syscall.
struct timer_list* real_timer;
/// List head for scheduling purposes.
list_head run_list;
/// Next value for the real timer (ITIMER_REAL).
unsigned long it_real_incr;
/// Current value for the real timer (ITIMER_REAL).
unsigned long it_real_value;
/// Next value for the virtual timer (ITIMER_VIRTUAL).
unsigned long it_virt_incr;
/// Current value for the virtual timer (ITIMER_VIRTUAL).
unsigned long it_virt_value;
/// Next value for the profiling timer (ITIMER_PROF).
unsigned long it_prof_incr;
/// Current value for the profiling timer (ITIMER_PROF).
unsigned long it_prof_value;
/// List of children traced by the process.
list_head children;
//==== Future work =========================================================
// - task's attributes:
// struct task_struct __rcu *real_parent;
// int exit_state;
// int exit_signal;
// struct thread_info thread_info;
// List of sibling, namely processes created by parent process
// list_head sibling;
/// List of siblings.
list_head sibling;
/// The context of the processors.
thread_struct thread;
/// For scheduling algorithms.
sched_entity se;
/// Exit code of the process. (parameter of _exit() system call).
int exit_code;
/// The name of the task (Added for debug purpose).
char name[TASK_NAME_MAX_LENGTH];
/// Task's segments.
struct mm_struct *mm;
/// Task's specific error number.
int error_no;
/// The current working directory.
char cwd[PATH_MAX];
//==== Future work =========================================================
// - task's attributes:
// struct task_struct __rcu *real_parent;
// int exit_state;
// int exit_signal;
// struct thread_info thread_info;
// List of sibling, namely processes created by parent process
// struct list_head sibling;
// - task's file descriptor:
// struct files_struct *files;
// - task's signal handlers:
// struct signal_struct *signal;
// struct sighand_struct *sighand;
// sigset_t blocked;
// sigset_t real_blocked;
// sigset_t saved_sigmask;
// struct sigpending pending;
//==========================================================================
// - task's file descriptor:
// struct files_struct *files;
// - task's signal handlers:
// struct signal_struct *signal;
// struct sighand_struct_t *sighand;
// sigset_t blocked;
// sigset_t real_blocked;
// sigset_t saved_sigmask;
// struct sigpending pending;
//==========================================================================
} task_struct;
// TODO: doxygen comment.
char *get_current_dir_name();
/// @brief Initialize the task management.
/// @return 1 success, 0 failure.
int init_tasking();
/// @brief Create and spawn the init process.
struct task_struct *create_init_process();
/// @param path Path of the `init` program.
/// @return Pointer to init process.
task_struct *process_create_init(const char *path);
+88 -41
View File
@@ -1,68 +1,115 @@
/// MentOS, The Mentoring Operating system project
/// @file scheduler.h
/// @brief Scheduler structures and functions.
/// @copyright (c) 2019 This file is distributed under the MIT License.
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "clock.h"
#include "kernel.h"
#include "stdint.h"
#include "list_head.h"
#include "process.h"
#include "stddef.h"
typedef struct {
/// Number of queued processes.
size_t num_active;
/// Queue of processes.
list_head queue;
/// The current running process.
task_struct *curr;
/// @brief Structure that contains information about live processes.
typedef struct runqueue_t {
/// Number of queued processes.
size_t num_active;
/// Number of queued periodic processes.
size_t num_periodic;
/// Queue of processes.
list_head queue;
/// The current running process.
task_struct *curr;
} runqueue_t;
/// @brief Structure that describes scheduling parameters.
typedef struct sched_param_t {
/// Static execution priority.
int sched_priority;
/// Expected period of the task
time_t period;
/// Absolute deadline
time_t deadline;
/// Absolute time of arrival of the task
time_t arrivaltime;
/// Is task periodic?
bool_t is_periodic;
} sched_param_t;
/// @brief Initialize the scheduler.
void scheduler_initialize();
/// @brief Returns a non-decreasing unique process id.
/// @return Process identifier (PID).
uint32_t get_new_pid();
/// @brief Initialize the scheduler.
void kernel_initialize_scheduler();
/// @brief Activate the given process.
/// @param process Process that has to be activated.
void enqueue_task(task_struct *process);
/// @brief Removes the given process from the queue.
/// @param process Process that has to be activated.
void dequeue_task(task_struct *process);
/// @brief Returns the number of active processes.
size_t kernel_get_active_processes();
uint32_t scheduler_getpid();
/// @brief Returns the pointer to the current active process.
task_struct *kernel_get_current_process();
/// @return Pointer to the current process.
task_struct *scheduler_get_current_process();
/// @brief Returns the maximum vruntime of all the processes in running state.
/// @return A maximum vruntime value.
time_t scheduler_get_maximum_vruntime();
/// @brief Returns the number of active processes.
/// @return Number of processes.
size_t scheduler_get_active_processes();
/// @brief Returns a pointer to the process with the given pid.
task_struct *kernel_get_running_process(pid_t pid);
/// @param pid The pid of the process we are looking for.
/// @return Pointer to the process, or NULL if we cannot find it.
task_struct *scheduler_get_running_process(pid_t pid);
task_struct *pick_next_task(runqueue_t *runqueue, time_t delta_exec);
/// @brief Activate the given process.
/// @param process Process that has to be activated.
void scheduler_enqueue_task(task_struct *process);
/// @brief The RR implementation of the scheduler.
/// @brief Removes the given process from the queue.
/// @param process Process that has to be activated.
void scheduler_dequeue_task(task_struct *process);
/// @brief The RR implementation of the scheduler.
/// @param f The context of the process.
void kernel_schedule(pt_regs *f);
void scheduler_run(pt_regs *f);
/// @birief Values from pt_regs to task_struct process.
void update_context(pt_regs *f, task_struct *process);
/// @brief Values from pt_regs to task_struct process.
/// @param f The set of registers we are saving.
/// @param process The process for which we are saving the CPU registers status.
void scheduler_store_context(pt_regs *f, task_struct *process);
/// @brief Values from task_struct process to pt_regs.
void do_switch(task_struct *process, pt_regs *f);
/// @param process The process for which we are restoring the registers in CPU .
/// @param f The set of registers we are restoring.
void scheduler_restore_context(task_struct *process, pt_regs *f);
/// @brief Switch CPU to user mode and start running that given process.
/// @param process The process that has to be executed
void enter_user_jmp(uintptr_t location, uintptr_t stack);
/// @brief Switch CPU to user mode and start running that given process.
/// @param location The instruction pointer of the process we are starting.
/// @param stack Address of the stack of that process.
void scheduler_enter_user_jmp(uintptr_t location, uintptr_t stack);
/// @brief Sets the priority value of the given task.
int set_user_nice(task_struct *p, long nice);
/// @brief Picks the next task (in scheduler_algorithm.c).
/// @param runqueue Pointer to the runqueue.
/// @return The next task to execute.
task_struct *scheduler_pick_next_task(runqueue_t *runqueue);
/// @brief Set new scheduling settings for the given process.
/// @param pid ID of the process we are manipulating.
/// @param param New parameters.
/// @return 1 on success, -1 on error.
int sys_sched_setparam(pid_t pid, const sched_param_t *param);
/// @brief Gets the scheduling settings for the given process.
/// @param pid ID of the process we are manipulating.
/// @param param Where we store the parameters.
/// @return 1 on success, -1 on error.
int sys_sched_getparam(pid_t pid, sched_param_t *param);
/// @brief Puts the process on wait until its next period starts.
/// @return 0 on success, a negative value on failure.
int sys_waitperiod();
/// @brief Returns 1 if the given group is orphaned, the session leader of the group
/// is no longer alive.
/// @param gid ID of the group
/// @return 1 if the group is orphan, 0 otherwise.
int is_orphaned_pgrp(pid_t gid);
+111
View File
@@ -0,0 +1,111 @@
/// MentOS, The Mentoring Operating system project
/// @file wait.h
/// @brief
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "list_head.h"
#include "spinlock.h"
/// @brief Return immediately if no child is there to be waited for.
#define WNOHANG 0x00000001
/// @brief Return for children that are stopped, and whose status has not
/// been reported.
#define WUNTRACED 0x00000002
/// @brief returns true if the child process exited because of a signal that
/// was not caught.
#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
/// @brief returns true if the child process that caused the return is
/// currently stopped; this is only possible if the call was done using
/// WUNTRACED().
#define WIFSTOPPED(status) (((status)&0xff) == 0x7f)
/// @brief evaluates to the least significant eight bits of the return code
/// of the child that terminated, which may have been set as the argument
/// to a call to exit() or as the argument for a return statement in the
/// main program. This macro can only be evaluated if WIFEXITED()
/// returned nonzero.
#define WEXITSTATUS(status) (((status)&0xff00) >> 8)
/// @brief returns the number of the signal that caused the child process to
/// terminate. This macro can only be evaluated if WIFSIGNALED() returned
/// nonzero.
#define WTERMSIG(status) ((status)&0x7f)
/// @brief Is nonzero if the child exited normally.
#define WIFEXITED(status) (WTERMSIG(status) == 0)
/// @brief returns the number of the signal that caused the child to stop.
/// This macro can only be evaluated if WIFSTOPPED() returned nonzero.
#define WSTOPSIG(status) (WEXITSTATUS(status))
//==== Task States ============================================================
#define TASK_RUNNING 0x00 ///< The process is either: 1) running on CPU or 2) waiting in a run queue.
#define TASK_INTERRUPTIBLE (1 << 0) ///< The process is sleeping, waiting for some event to occur.
#define TASK_UNINTERRUPTIBLE (1 << 1) ///< Similar to TASK_INTERRUPTIBLE, but it doesn't process signals.
#define TASK_STOPPED (1 << 2) ///< Stopped, it's not running, and not able to run.
#define TASK_TRACED (1 << 3) ///< Is being monitored by other processes such as debuggers.
#define EXIT_ZOMBIE (1 << 4) ///< The process has terminated.
#define EXIT_DEAD (1 << 5) ///< The final state.
//==============================================================================
/// @defgroup WaitQueueFlags Wait Queue Flags
/// @{
/// @brief When an entry has this flag is added to the end of the wait queue.
/// Entries without that flag are, instead, added to the beginning.
#define WQ_FLAG_EXCLUSIVE 0x01
//#define WQ_FLAG_WOKEN 0x02
//#define WQ_FLAG_BOOKMARK 0x04
//#define WQ_FLAG_CUSTOM 0x08
//#define WQ_FLAG_DONE 0x10
/// @}
/// @brief Head of the waiting queue.
typedef struct wait_queue_head_t {
/// Locking element for the waiting queque.
spinlock_t lock;
/// Head of the waiting queue, it contains wait_queue_entry_t elements.
struct list_head task_list;
} wait_queue_head_t;
/// @brief Entry of the waiting queue.
typedef struct wait_queue_entry_t {
/// Flags of the type WaitQueueFlags.
unsigned int flags;
/// Task associated with the wait queue entry.
struct task_struct *task;
/// Function associated with the wait queue entry.
int (*func)(struct wait_queue_entry_t *wait, unsigned mode, int sync);
/// Handler for placing the entry inside a waiting queue double linked-list.
struct list_head task_list;
} wait_queue_entry_t;
/// @brief Initialize the waiting queue entry.
/// @param wq The entry we initialize.
/// @param task The task associated with the entry.
void init_waitqueue_entry(wait_queue_entry_t *wq, struct task_struct *task);
/// @brief Adds the element to the waiting queue.
/// @param head The head of the waiting queue.
/// @param wq The entry we insert inside the waiting queue.
void add_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq);
/// @brief Removes the element from the waiting queue.
/// @param head The head of the waiting queue.
/// @param wq The entry we remove from the waiting queue.
void remove_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq);
/// @brief The default wake function, a wrapper for try_to_wake_up.
/// @param wait The pointer to the wait queue.
/// @param mode The type of wait (TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE).
/// @param sync Specifies if the wakeup should be synchronous.
/// @return 1 on success, 0 on failure.
int default_wake_function(wait_queue_entry_t *wait, unsigned mode, int sync);
/// @brief Sets the state of the current process to TASK_UNINTERRUPTIBLE
/// and inserts it into the specified wait queue.
///
/// @param wq Waitqueue where to sleep.
/// @return Pointer to the entry inside the wq representing the
/// sleeping process.
wait_queue_entry_t *sleep_on(wait_queue_head_t *wq);