Merge branch 'develop' into feature/Feature-Semaphores

This commit is contained in:
Enrico Fraccaroli
2023-04-21 16:51:20 +02:00
13 changed files with 385 additions and 30 deletions
+20 -12
View File
@@ -488,6 +488,10 @@ static bool_t ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gi
{
// Check the permissions.
task_struct *task = scheduler_get_current_process();
if (task == NULL) {
pr_warning("Failed to get the current running process, assuming we are booting.\n");
return true;
}
// The current task is the owner.
if (task->uid == uid) {
if (!bitmask_check(mask, S_IRUSR))
@@ -2151,11 +2155,6 @@ static int ext2_create_inode(
pr_err("Received a null EXT2 inode.\n");
return -1;
}
task_struct *task = scheduler_get_current_process();
if (task == NULL) {
pr_err("Failed to get the current running process.\n");
return -1;
}
// Allocate an inode, inside the preferred_group if possible.
int inode_index = ext2_allocate_inode(fs, preferred_group);
if (inode_index == 0) {
@@ -2169,10 +2168,19 @@ static int ext2_create_inode(
pr_err("Failed to read the newly created inode.\n");
return -1;
}
// Get the UID and GID.
uid_t uid = 0, gid = 0;
task_struct *task = scheduler_get_current_process();
if (task != NULL) {
pr_warning("Failed to get the current running process, assuming we are booting.\n");
} else {
uid = task->uid;
gid = task->gid;
}
// Set the inode mode.
inode->mode = mode;
// Set the user identifiers of the owners.
inode->uid = task->uid;
inode->uid = uid;
// Set the size of the file in bytes.
inode->size = 0;
// Set the time that the inode was accessed.
@@ -2184,7 +2192,7 @@ static int ext2_create_inode(
// Set the time that the inode was deleted.
inode->dtime = 0;
// Set the group identifiers of the owners.
inode->gid = task->gid;
inode->gid = gid;
// Set the number of hard links.
inode->links_count = 0;
// Set the blocks count.
@@ -2332,7 +2340,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
search.parent_inode = 0;
// First check, if a file with the given name already exists.
if (!ext2_resolve_path(fs->root, absolute_path, &search)) {
if (bitmask_check(flags, O_CREAT | O_EXCL)) {
if (bitmask_check(flags, O_CREAT) && bitmask_check(flags, O_EXCL)) {
pr_err("A file or directory already exists at `%s` (O_CREAT | O_EXCL).\n", absolute_path);
return NULL;
} else if (bitmask_check(flags, O_DIRECTORY) && (direntry.file_type != ext2_file_type_directory)) {
@@ -2720,15 +2728,15 @@ static int ext2_mkdir(const char *path, mode_t permission)
pr_err("Failed to properly get the parent directory (%s == %s).\n", parent_path, path);
return -ENOENT;
}
// Set the inode mode.
uint32_t mode = EXT2_S_IFDIR;
mode |= 0xFFF & permission;
// Get the parent VFS node.
vfs_file_t *parent = vfs_open(parent_path, O_RDONLY, 0);
vfs_file_t *parent = vfs_open(parent_path, O_RDONLY, mode);
if (parent == NULL) {
pr_err("Failed to open parent directory (%s).\n", parent_path);
return -ENOENT;
}
// Set the inode mode.
uint32_t mode = EXT2_S_IFDIR;
mode |= 0xFFF & permission;
// Get the group index of the parent.
uint32_t group_index = ext2_get_group_index_from_inode(fs, parent->ino);
// Create and initialize the new inode.
+1 -1
View File
@@ -321,7 +321,7 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode)
// Retrieve the file.
vfs_file_t *file = sb_root->sys_operations->creat_f(absolute_path, mode);
if (file == NULL) {
pr_err("vfs_open(%s): Cannot find the given file (%s)!\n", path, strerror(errno));
pr_err("vfs_creat(%s): Cannot find the given file (%s)!\n", path, strerror(errno));
errno = ENOENT;
return NULL;
}
+50
View File
@@ -0,0 +1,50 @@
/// @file proc_feedback.c
/// @brief Contains callbacks for procfs system files.
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "fs/procfs.h"
#include "process/process.h"
#include "sys/errno.h"
#include "io/debug.h"
#include "string.h"
static ssize_t procfb_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
return 0;
}
/// Filesystem general operations.
static vfs_sys_operations_t procfb_sys_operations = {
.mkdir_f = NULL,
.rmdir_f = NULL,
.stat_f = NULL
};
/// Filesystem file operations.
static vfs_file_operations_t procfb_fs_operations = {
.open_f = NULL,
.unlink_f = NULL,
.close_f = NULL,
.read_f = procfb_read,
.write_f = NULL,
.lseek_f = NULL,
.stat_f = NULL,
.ioctl_f = NULL,
.getdents_f = NULL
};
int procfb_module_init()
{
// Create the file.
proc_dir_entry_t *file = proc_create_entry("feedback", NULL);
if (file == NULL) {
pr_err("Cannot create `/proc/feedback`.\n");
return 1;
}
pr_debug("Created `/proc/feedback` (%p)\n", file);
// Set the specific operations.
file->sys_operations = &procfb_sys_operations;
file->fs_operations = &procfb_fs_operations;
return 0;
}
+19
View File
@@ -29,6 +29,7 @@
#include "drivers/keyboard/keymap.h"
#include "drivers/ps2.h"
#include "process/scheduler.h"
#include "process/scheduler_feedback.h"
#include "hardware/timer.h"
#include "fs/vfs.h"
#include "devices/fpu.h"
@@ -342,6 +343,24 @@ int kmain(boot_info_t *boot_informations)
}
print_ok();
//==========================================================================
pr_notice("Initialize scheduler feedback system...\n");
printf("Initialize scheduler feedback system...");
if (!scheduler_feedback_init()) {
print_fail();
return 1;
}
print_ok();
//==========================================================================
pr_notice("Initialize scheduler feedback system (2)...\n");
printf("Initialize scheduler feedback system (2)...");
if (procfb_module_init()) {
print_fail();
return 1;
}
print_ok();
//==========================================================================
pr_notice("Creating init process...\n");
printf("Creating init process...");
+5 -1
View File
@@ -12,9 +12,10 @@
#include "assert.h"
#include "strerror.h"
#include "fs/vfs.h"
#include "process/scheduler.h"
#include "descriptor_tables/tss.h"
#include "devices/fpu.h"
#include "process/scheduler_feedback.h"
#include "process/scheduler.h"
#include "process/prio.h"
#include "process/wait.h"
#include "mem/kheap.h"
@@ -109,10 +110,13 @@ void scheduler_enqueue_task(task_struct *process)
list_head_insert_before(&process->run_list, &runqueue.queue);
// Increment the number of active processes.
++runqueue.num_active;
scheduler_feedback_task_add(process);
}
void scheduler_dequeue_task(task_struct *process)
{
scheduler_feedback_task_remove(process->pid);
// Delete the process from the list of running processes.
list_head_remove(&process->run_list);
// Decrement the number of active processes.
+23 -13
View File
@@ -15,6 +15,7 @@
#include "klib/list_head.h"
#include "process/wait.h"
#include "process/scheduler.h"
#include "process/scheduler_feedback.h"
/// @brief Updates task execution statistics.
/// @param task the task to update.
@@ -29,12 +30,12 @@ static inline bool_t __is_periodic_task(task_struct *task)
return task->se.is_periodic && !task->se.is_under_analysis;
}
/// @brief Employs time-sharing, giving each job a timeslice, and is also
/// @brief Employs time-sharing, giving each job a time-slot, and is also
/// preemptive since the scheduler forces the task out of the CPU once
/// the timeslice expires.
/// the time-slot 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 that periodic processes in the list
/// should be skipped.
/// @return the next task on success, NULL on failure.
static inline task_struct *__scheduler_rr(runqueue_t *runqueue, bool_t skip_periodic)
{
@@ -61,6 +62,7 @@ static inline task_struct *__scheduler_rr(runqueue_t *runqueue, bool_t skip_peri
// We have our next entry.
return entry;
}
return NULL;
}
@@ -95,10 +97,10 @@ static inline task_struct *__scheduler_priority(runqueue_t *runqueue, bool_t ski
#ifdef SCHEDULER_PRIORITY
// Get the first element of the list.
task_struct *next = list_entry(runqueue->queue.next, struct task_struct, run_list);
// Get the static priority of the first element of the list we just extracted.
time_t min = /*...*/;
// This will hold a given entry, while iterating the list of tasks.
task_struct *entry = NULL;
// Get the static priority of the first element of the list we just extracted.
time_t min = /*...*/;
// Search for the task with the smallest static priority.
list_for_each_decl(it, &runqueue->queue)
@@ -140,10 +142,10 @@ static inline task_struct *__scheduler_cfs(runqueue_t *runqueue, bool_t skip_per
#ifdef SCHEDULER_CFS
// Get the first element of the list.
task_struct *next = list_entry(runqueue->queue.next, struct task_struct, run_list);
// Get the virtual runtime of the first element of the list we just extracted.
time_t min = /*...*/;
// This will hold a given entry, while iterating the list of tasks.
task_struct *entry = NULL;
// Get the virtual runtime of the first element of the list we just extracted.
time_t min = /*...*/;
// Search for the task with the smallest vruntime value.
list_for_each_decl(it, &runqueue->queue)
@@ -163,6 +165,7 @@ static inline task_struct *__scheduler_cfs(runqueue_t *runqueue, bool_t skip_per
// Check if the element in the list has a smaller vruntime value.
/* ... */
}
return next;
#else
return __scheduler_rr(runqueue, skip_periodic);
@@ -177,7 +180,7 @@ static inline task_struct *__scheduler_aedf(runqueue_t *runqueue)
{
#ifdef SCHEDULER_AEDF
// This will hold the pointer to the next task to schedule.
task_struct *next = NULL;
task_struct *next = list_entry(runqueue->queue.next, struct task_struct, run_list);
// This will hold a given entry, while iterating the list of tasks.
task_struct *entry = NULL;
// Initialize the nearest "next deadline".
@@ -385,6 +388,11 @@ task_struct *scheduler_pick_next_task(runqueue_t *runqueue)
// Update the last context switch time of the next task.
next->se.exec_start = timer_get_ticks();
// Update the feedback statistics for the new scheduled task.
scheduler_feedback_task_update(next);
// Update the overall feedback system.
scheduler_feedback_update();
return next;
}
@@ -410,16 +418,18 @@ static void __update_task_statistics(task_struct *task)
// If the task is not a periodic task we have to update the virtual runtime.
if (!task->se.is_periodic) {
// Get the weight of the current task.
time_t weight = /* ... */;
time_t weight = GET_WEIGHT((task)->se.prio); /* ... */
;
// If the weight is different from the default load, compute it.
if (weight != NICE_0_LOAD) {
// Get the multiplicative factor for its delta_exec.
double factor = /* ... */;
double factor = ((double)NICE_0_LOAD / (double)weight); /* ... */
;
// Weight the delta_exec with the multiplicative factor.
task->se.exec_runtime = /* ... */;
task->se.exec_runtime = ((int)(((double)task->se.exec_runtime) * factor)); /* ... */
}
// Update vruntime of the current task.
task->se.vruntime += /* ... */;
task->se.vruntime += task->se.exec_runtime;
}
#endif
}
+195
View File
@@ -0,0 +1,195 @@
/// @file scheduler_feedback.c
/// @brief Manage the current PID for the scheduler feedback session
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "process/scheduler_feedback.h"
#include "hardware/timer.h"
#include "strerror.h"
#include "fs/vfs.h"
#include "assert.h"
#include "string.h"
#include "fcntl.h"
#include "stdio.h"
// Include the kernel log levels.
#include "sys/kernel_levels.h"
/// Change the header.
#define __DEBUG_HEADER__ "[SCHFBK]"
/// Set the log level.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE
#include "io/debug.h"
/// @brief How often the feedback is shown.
#define LOG_INTERVAL_SEC 0.5
/// @brief The name of the scheduling policy.
#if defined(SCHEDULER_RR)
#define POLICY_NAME "RR "
#elif defined(SCHEDULER_PRIORITY)
#define POLICY_NAME "PRIO "
#elif defined(SCHEDULER_CFS)
#define POLICY_NAME "CFS "
#elif defined(SCHEDULER_EDF)
#define POLICY_NAME "EDF "
#elif defined(SCHEDULER_RM)
#define POLICY_NAME "RM "
#elif defined(SCHEDULER_AEDF)
#define POLICY_NAME "AEDF "
#else
#error "You should enable a scheduling algorithm!"
#endif
/// @brief If uncommented, it writes the logging on file.
//#define WRITE_ON_FILE
#ifdef WRITE_ON_FILE
/// @brief Name of the file where the feedback statistics are saved.
#define FEEDBACK_FILENAME "/var/schedfb"
/// @brief The header shown
#define FEEDBACK_HEADER "\n[PID[] | NAME | -> (CPU UTILIZATION)\n\0"
/// @brief
ssize_t offset;
#endif
/// @brief When the next log should be displayed/saved, in CPU ticks.
unsigned long next_log;
/// @brief The total number of context-switches since the starting of the log
/// session.
size_t total_occurrences;
/// @brief A structure that keeps track of scheduling statistics.
struct statistic {
task_struct *task;
unsigned long occur;
} arr_stats[PID_MAX_LIMIT];
/// @brief Updates when the logging should happen.
static inline void __scheduler_feedback_deadline_advance()
{
next_log = timer_get_ticks() + (LOG_INTERVAL_SEC * TICKS_PER_SECOND);
}
/// @brief Checks if the deadline is passed.
/// @return 1 if the deadline is passed, 0 otherwise.
static inline int __scheduler_feedback_deadline_check()
{
return (next_log < timer_get_ticks());
}
/// @brief Logs the scheduling statistics either on file or on the terminal.
static inline void __scheduler_feedback_log()
{
pr_info("Scheduling Statistics (%s)\n", POLICY_NAME);
#ifdef WRITE_ON_FILE
// Open the feedback file.
vfs_file_t *feedback = vfs_open(FEEDBACK_FILENAME, O_WRONLY, 0644);
if (feedback == NULL) {
pr_err("Failed to create the feedback file.\n");
pr_err("Error: %s\n", strerror(errno));
return;
}
char buffer[BUFSIZ];
int written = 0;
#endif
for (size_t i = 0; i < PID_MAX_LIMIT; ++i) {
if (arr_stats[i].task) {
float tcpu = ((float)arr_stats[i].occur * 100.0) / total_occurrences;
pr_info("[%3d] | %-24s | -> TCPU: %.2f%% \n",
arr_stats[i].task->pid,
arr_stats[i].task->name,
tcpu);
#ifdef WRITE_ON_FILE
written = sprintf(buffer, "[%3d](%s)[%f], ", arr_stats[i].pid, arr_stats[i].name, tcpu);
vfs_write(feedback, buffer, offset, written);
offset += written;
#endif
}
}
#ifdef WRITE_ON_FILE
vfs_write(feedback, "/n", offset, 1);
offset++;
vfs_close(feedback);
#endif
}
int scheduler_feedback_init()
{
#ifdef WRITE_ON_FILE
// Create the feedback file, if necessary.
int ret = vfs_mkdir("/var", 0644);
if ((ret < 0) && (-ret != EEXIST)) {
pr_err("Failed to create the `/var` directory.\n");
pr_err("Error: %s\n", strerror(errno));
return 0;
}
// Create the feedback file, if necessary.
vfs_file_t *feedback = vfs_open(FEEDBACK_FILENAME, O_WRONLY | O_TRUNC | O_CREAT, 0644);
if (feedback == NULL) {
pr_err("Failed to create the feedback file.\n");
pr_err("Error: %s\n", strerror(errno));
return 0;
}
// Get the length of the headr.
ssize_t header_len = strlen(FEEDBACK_HEADER);
// Reset the offset.
offset = 0;
// Write the header.
vfs_write(feedback, FEEDBACK_HEADER, offset, header_len);
// Move the offset.
offset += header_len;
// Close the file.
vfs_close(feedback);
#endif
// Initialize the stat array.
for (size_t i = 0; i < PID_MAX_LIMIT; ++i) {
arr_stats[i].task = NULL;
arr_stats[i].occur = 0;
}
// Update when in the future, the logging should happen.
__scheduler_feedback_deadline_advance();
// Initialize the number of occurrences.
total_occurrences = 0;
return 1;
}
void scheduler_feedback_task_add(task_struct *task)
{
assert(task && "Received a NULL task.");
arr_stats[task->pid].occur = 1;
arr_stats[task->pid].task = task;
}
void scheduler_feedback_task_remove(pid_t pid)
{
assert(pid < PID_MAX_LIMIT && "We received a wrong pid.");
total_occurrences -= arr_stats[pid].occur;
arr_stats[pid].occur = 0;
arr_stats[pid].task = NULL;
}
void scheduler_feedback_task_update(task_struct *task)
{
assert(task && "Received a NULL task.");
arr_stats[task->pid].occur += 1;
total_occurrences += 1;
}
void scheduler_feedback_update()
{
// If it is not yet time for the next reset, skip.
if (!__scheduler_feedback_deadline_check()) {
return;
}
// Dump on the feedback before reset.
__scheduler_feedback_log();
// Reset the occurences.
for (size_t i = 0; i < PID_MAX_LIMIT; ++i) {
if (arr_stats[i].task)
arr_stats[i].occur = 0;
}
// Update when in the future, the logging should happen.
__scheduler_feedback_deadline_advance();
// Reset the number of occurrences.
total_occurrences = 0;
}