Merge branch 'develop' into feature/Feature-Semaphores
This commit is contained in:
+20
-12
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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...");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user