feature (proc): implemented basic process structure

This commit is contained in:
antifallobst 2023-03-03 20:23:19 +01:00
parent bb4323ef79
commit b732145fef
7 changed files with 359 additions and 44 deletions

51
kernel/inc/proc/process.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright 2023 Antifallobst <antifallobst@systemausfall.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the Software), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NOX_PROCESS_H
#define NOX_PROCESS_H
#include "utils/stdtypes.h"
#include "utils/string.h"
typedef uint32_t pid_t;
typedef enum {
PROCESS_NONE,
PROCESS_KERNEL
} processes_standard_E;
typedef struct process_T process_T;
struct process_T{
char name[128];
pid_t id;
void* chunk;
uint32_t chunk_id;
process_T* parent;
void* threads;
};
pid_t process_spawn (pid_t parent, string_t name);
void process_kill (pid_t process);
#endif //NOX_PROCESS_H

View File

@ -25,11 +25,27 @@
#define NOX_SCHEDULER_H #define NOX_SCHEDULER_H
#include "proc/thread.h" #include "proc/thread.h"
#include "proc/process.h"
#include "utils/bitmap.h" #include "utils/bitmap.h"
#define SCHEDULER_PROCESS_CHUNK_SIZE 64
typedef struct scheduler_processes_chunk_T scheduler_processes_chunk_T;
struct scheduler_processes_chunk_T {
process_T** processes;
bitmap_T processes_bitmap;
uint32_t num_free_pids;
scheduler_processes_chunk_T* prev;
scheduler_processes_chunk_T* next;
};
typedef struct { typedef struct {
uint32_t num_threads; uint32_t num_threads;
uint32_t num_processes;
thread_T* running_thread; thread_T* running_thread;
scheduler_processes_chunk_T* processes;
bool blocked; bool blocked;
bool initialized; bool initialized;
@ -44,7 +60,12 @@ void scheduler_pause_thread (thread_T* thread);
void scheduler_start_thread (thread_T* thread); void scheduler_start_thread (thread_T* thread);
void scheduler_kill_thread (thread_T* thread); void scheduler_kill_thread (thread_T* thread);
pid_t scheduler_register_process (process_T* process);
void scheduler_kill_process (process_T* process);
process_T* scheduler_get_process (pid_t pid);
thread_T* scheduler_get_current_thread (); thread_T* scheduler_get_current_thread ();
process_T* scheduler_get_current_process ();
cpu_state_T* scheduler_switch_context (cpu_state_T* state); cpu_state_T* scheduler_switch_context (cpu_state_T* state);

View File

@ -26,6 +26,7 @@
#include "utils/stdtypes.h" #include "utils/stdtypes.h"
#include "platform/cpu.h" #include "platform/cpu.h"
#include "proc/process.h"
typedef struct thread_T thread_T; typedef struct thread_T thread_T;
struct thread_T{ struct thread_T{
@ -33,15 +34,19 @@ struct thread_T{
uint64_t cpu_time; uint64_t cpu_time;
void* stack; void* stack;
uint32_t stack_size; uint32_t stack_size;
process_T* process;
// Scheduling data // Scheduling data
thread_T* prev; thread_T* global_prev;
thread_T* next; thread_T* global_next;
thread_T* local_prev;
thread_T* local_next;
}; };
thread_T* thread_spawn (void* function); thread_T* thread_spawn (pid_t process, void* function);
thread_T* thread_spawn_from_state (cpu_state_T* state); thread_T* thread_spawn_from_state (pid_t process, cpu_state_T* state);
void thread_start (thread_T* thread); void thread_start (thread_T* thread);
void thread_pause (thread_T* thread); void thread_pause (thread_T* thread);
void thread_kill (thread_T* thread); void thread_kill (thread_T* thread);

View File

@ -78,6 +78,26 @@ void kernel_init(boot_info_T* boot_info) {
limine_terminal_print(boot_info, " ok\n"); limine_terminal_print(boot_info, " ok\n");
} }
#include "utils/io.h"
void test1() {
while (true) {
io_out_byte(LOG_PORT, 'A');
}
}
void test2() {
while (true) {
io_out_byte(LOG_PORT, 'B');
}
}
void test3() {
while (true) {
io_out_byte(LOG_PORT, 'C');
}
}
void kmain(boot_info_T boot_info) { void kmain(boot_info_T boot_info) {
limine_terminal_print(&boot_info, "Booting NoxOS...\n"); limine_terminal_print(&boot_info, "Booting NoxOS...\n");
@ -90,16 +110,29 @@ void kmain(boot_info_T boot_info) {
elf_init_kernel_exec(&boot_info); elf_init_kernel_exec(&boot_info);
vfs_node_T* node = vfs_resolve_path(&g_root_fs, "/initrd/test.elf"); pid_t proc1 = process_spawn(PROCESS_NONE, "test process 1");
thread_T* proc1_thread1 = thread_spawn(proc1, test1);
thread_T* proc1_thread2 = thread_spawn(proc1, test2);
thread_T* proc1_thread3 = thread_spawn(proc1, test3);
elf_executable_T* exec = elf_executable_create(node->cache->buffer); thread_start(proc1_thread1);
thread_start(proc1_thread2);
thread_start(proc1_thread3);
page_map_T* page_map = pframe_request(); process_kill(proc1);
elf_mappings_apply(exec->mappings, exec->num_mappings, node->cache->buffer, 0xFFFFFFFFFF000000, page_map);
int (*entry)() = (0xFFFFFFFFFF000000 + symbol_resolve_from_name(exec->symbols, exec->num_symbols, "_start")->address); // vfs_node_T* node = vfs_resolve_path(&g_root_fs, "/initrd/test.elf");
//
// elf_executable_T* exec = elf_executable_create(node->cache->buffer);
//
// page_map_T* page_map = pframe_request();
// elf_mappings_apply(exec->mappings, exec->num_mappings, node->cache->buffer, 0xFFFFFFFFFF000000, page_map);
//
// int (*entry)() = (0xFFFFFFFFFF000000 + symbol_resolve_from_name(exec->symbols, exec->num_symbols, "_start")->address);
//
// thread_spawn(PROCESS_KERNEL, entry);
log(LOG_DEBUG, "ELF returned: %d", entry()); // log(LOG_DEBUG, "ELF returned: %d", entry());
CORE_HALT_FOREVER CORE_HALT_FOREVER
} }

47
kernel/src/proc/process.c Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright 2023 Antifallobst <antifallobst@systemausfall.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the Software), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "proc/process.h"
#include "proc/scheduler.h"
#include "utils/memory.h"
#include "utils/math.h"
pid_t process_spawn(pid_t parent, string_t name) {
process_T* process = memory_allocate(sizeof(process_T));
process->threads = NULL;
process->parent = scheduler_get_process(parent);
memory_copy(name, process->name, MIN(string_length(name), 127));
// the processes' id, chunk_id and chunk fields will be set by the scheduler
return scheduler_register_process(process);
}
void process_kill(pid_t process) {
process_T* proc = scheduler_get_process(process);
scheduler_kill_process(proc);
memory_free(proc);
}

View File

@ -25,22 +25,52 @@
#include "utils/memory.h" #include "utils/memory.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/core.h" #include "utils/core.h"
#include "drivers/graphics/renderer.h"
#include "platform/syscall.h" #include "platform/syscall.h"
scheduler_T g_scheduler; scheduler_T g_scheduler;
graphics_buffer_T* g_scheduler_info_buffer;
void scheduler_update_info() {
uint64_t size = format_size("Processes[%d]\n Threads[%d]", g_scheduler.num_processes, g_scheduler.num_threads);
char buffer[size];
format(buffer, "Processes[%d]\n Threads[%d]", g_scheduler.num_processes, g_scheduler.num_threads);
graphics_buffer_draw_string(g_scheduler_info_buffer, 0, 0, g_color_palette[COLOR_PAL_GREEN], buffer);
}
scheduler_processes_chunk_T* scheduler_processes_chunk_create(scheduler_processes_chunk_T* prev) {
scheduler_processes_chunk_T* chunk = memory_allocate(sizeof(scheduler_processes_chunk_T));
chunk->processes = memory_allocate(SCHEDULER_PROCESS_CHUNK_SIZE * sizeof(process_T*));
chunk->prev = prev;
chunk->next = NULL;
chunk->processes_bitmap = bitmap_init(SCHEDULER_PROCESS_CHUNK_SIZE);
chunk->num_free_pids = SCHEDULER_PROCESS_CHUNK_SIZE;
return chunk;
}
void scheduler_init() { void scheduler_init() {
g_scheduler.num_threads = 0; g_scheduler.num_threads = 0;
g_scheduler.num_processes = 0;
g_scheduler.running_thread = NULL; g_scheduler.running_thread = NULL;
g_scheduler.blocked = false; g_scheduler.blocked = false;
g_scheduler.processes = scheduler_processes_chunk_create(NULL);
g_scheduler_info_buffer = graphics_buffer_request(graphics_renderer_get_width()-100, 0, 100, 200, GRAPHICS_BUFFER_STANDARD);
syscall_perform(SYSCALL_KERNEL_SCHEDULER_START); syscall_perform(SYSCALL_KERNEL_SCHEDULER_START);
} }
cpu_state_T* scheduler_start(cpu_state_T* state) { cpu_state_T* scheduler_start(cpu_state_T* state) {
thread_T* thread = thread_spawn_from_state(state);
thread->prev = thread; process_spawn(PROCESS_NONE, "kernel");
thread->next = thread;
thread_T* thread = thread_spawn_from_state(PROCESS_KERNEL, state);
thread->global_prev = thread;
thread->global_next = thread;
g_scheduler.running_thread = thread; g_scheduler.running_thread = thread;
@ -58,25 +88,36 @@ bool scheduler_is_initialized() {
void scheduler_queue_add_thread(thread_T* thread) { void scheduler_queue_add_thread(thread_T* thread) {
if (g_scheduler.running_thread == NULL) { return; } if (g_scheduler.running_thread == NULL) { return; }
thread->prev = g_scheduler.running_thread; thread->global_prev = g_scheduler.running_thread;
thread->next = g_scheduler.running_thread->next; thread->global_next = g_scheduler.running_thread->global_next;
g_scheduler.running_thread->next->prev = thread; g_scheduler.running_thread->global_next->global_prev = thread;
g_scheduler.running_thread->next = thread; g_scheduler.running_thread->global_next = thread;
} }
void scheduler_queue_remove_thread(thread_T* thread) { void scheduler_queue_remove_thread(thread_T* thread) {
if (thread->prev == NULL || thread->next == NULL) { return; } if (thread->global_prev == NULL || thread->global_next == NULL) { return; }
thread->prev->next = thread->next; thread->global_prev->global_next = thread->global_next;
thread->next->prev = thread->prev; thread->global_next->global_prev = thread->global_prev;
thread->prev = NULL; thread->global_prev = NULL;
thread->next = NULL; thread->global_next = NULL;
} }
thread_T* scheduler_register_thread(thread_T* thread) { thread_T* scheduler_register_thread(thread_T* thread) {
thread->local_prev = NULL;
thread->local_next = NULL;
if (thread->process->threads != NULL) {
thread->local_next = thread->process->threads;
thread->local_next->local_prev = thread;
}
thread->process->threads = thread;
g_scheduler.num_threads++; g_scheduler.num_threads++;
log(LOG_INFO, "<Scheduler> Registered thread"); log(LOG_INFO, "<Scheduler> Registered thread");
scheduler_update_info();
return thread; return thread;
} }
@ -84,25 +125,129 @@ thread_T* scheduler_register_thread(thread_T* thread) {
void scheduler_pause_thread(thread_T* thread) { void scheduler_pause_thread(thread_T* thread) {
scheduler_queue_remove_thread(thread); scheduler_queue_remove_thread(thread);
log(LOG_INFO, "<Scheduler> Paused thread"); log(LOG_INFO, "<Scheduler> Paused thread");
scheduler_update_info();
} }
void scheduler_start_thread(thread_T* thread) { void scheduler_start_thread(thread_T* thread) {
scheduler_queue_add_thread(thread); scheduler_queue_add_thread(thread);
log(LOG_INFO, "<Scheduler> Started thread"); log(LOG_INFO, "<Scheduler> Started thread");
scheduler_update_info();
} }
void scheduler_kill_thread(thread_T* thread) { void scheduler_kill_thread(thread_T* thread) {
scheduler_queue_remove_thread(thread); scheduler_queue_remove_thread(thread);
if (thread->process->threads == thread) {
thread->process->threads = thread->local_next;
}
if (thread->local_next != NULL) {
thread->local_next->local_prev = thread->local_prev;
}
if (thread->local_prev != NULL) {
thread->local_prev->local_next = thread->local_next;
}
g_scheduler.num_threads--; g_scheduler.num_threads--;
log(LOG_INFO, "<Scheduler> Killed thread"); log(LOG_INFO, "<Scheduler> Killed thread");
scheduler_update_info();
}
pid_t scheduler_register_process(process_T* process) {
pid_t pid = 1; // offset pit by one, so this won't return a pid that is PROCESS_NONE
// find a process chunk, that has free slots
scheduler_processes_chunk_T* chunk = g_scheduler.processes;
while (chunk->num_free_pids == 0) {
if (chunk->next == NULL) {
chunk->next = scheduler_processes_chunk_create(chunk);
}
chunk = chunk->next;
pid += SCHEDULER_PROCESS_CHUNK_SIZE;
}
for (uint32_t i = 0; i < SCHEDULER_PROCESS_CHUNK_SIZE; i++) {
if (bitmap_get(&chunk->processes_bitmap, i)) {
continue;
}
bitmap_set(&chunk->processes_bitmap, i, true);
chunk->processes[i] = process;
process->chunk = chunk;
process->chunk_id = i;
process->id = pid + i;
chunk->num_free_pids--;
g_scheduler.num_processes++;
log(LOG_INFO, "<Scheduler> Registered Process %d", pid + i);
scheduler_update_info();
return pid + i;
}
// if this happens, something went really wrong
log(LOG_ERROR, "<Scheduler> failed to register process (no free slots in chunk)");
return PROCESS_NONE;
}
void scheduler_kill_process(process_T* process) {
scheduler_processes_chunk_T* chunk = process->chunk;
bitmap_set(&chunk->processes_bitmap, process->chunk_id, false);
chunk->processes[process->chunk_id] = NULL;
thread_T* thread = process->threads;
while (thread != NULL) {
thread_T* next = thread->local_next;
thread_kill(thread);
thread = next;
}
chunk->num_free_pids++;
g_scheduler.num_processes--;
log(LOG_INFO, "<Scheduler> Killed Process %d", process->id);
scheduler_update_info();
}
process_T* scheduler_get_process(pid_t pid) {
if (pid == PROCESS_NONE) {
return NULL;
}
pid--; // apply pid offset to make PROCESS_NONE work
uint32_t num_chunks = pid / SCHEDULER_PROCESS_CHUNK_SIZE;
uint32_t index_in_chunk = pid % SCHEDULER_PROCESS_CHUNK_SIZE;
scheduler_processes_chunk_T* chunk = g_scheduler.processes;
for (uint32_t i = 0; i < num_chunks; i++) {
chunk = chunk->next;
if (chunk == NULL) {
return NULL;
}
}
if (!bitmap_get(&chunk->processes_bitmap, index_in_chunk)) {
return NULL;
}
return chunk->processes[index_in_chunk];
} }
thread_T* scheduler_get_current_thread() { thread_T* scheduler_get_current_thread() {
return g_scheduler.running_thread; return g_scheduler.running_thread;
} }
process_T* scheduler_get_current_process() {
return g_scheduler.running_thread->process;
}
cpu_state_T* scheduler_switch_context(cpu_state_T* state) { cpu_state_T* scheduler_switch_context(cpu_state_T* state) {
if (!g_scheduler.initialized) { if (!g_scheduler.initialized) {
return state; return state;
@ -112,14 +257,14 @@ cpu_state_T* scheduler_switch_context(cpu_state_T* state) {
g_scheduler.blocked = true; g_scheduler.blocked = true;
thread_T* old_thread = g_scheduler.running_thread; thread_T* old_thread = g_scheduler.running_thread;
thread_T* new_thread = g_scheduler.running_thread->next; thread_T* new_thread = g_scheduler.running_thread->global_next;
if (old_thread->cpu_time > 0) { if (old_thread->cpu_time > 0) {
memory_copy(state, &old_thread->state, sizeof(cpu_state_T)); memory_copy(state, &old_thread->state, sizeof(cpu_state_T));
} }
old_thread->cpu_time += 1; old_thread->cpu_time += 1;
g_scheduler.running_thread = g_scheduler.running_thread->next; g_scheduler.running_thread = g_scheduler.running_thread->global_next;
g_scheduler.blocked = false; g_scheduler.blocked = false;
return &new_thread->state; return &new_thread->state;

View File

@ -27,10 +27,17 @@
#include "mm/page_frame.h" #include "mm/page_frame.h"
#include "platform/gdt.h" #include "platform/gdt.h"
#include "utils/memory.h" #include "utils/memory.h"
#include "utils/logger.h"
thread_T* thread_spawn(void* function) { thread_T* thread_spawn(pid_t process, void* function) {
thread_T* thread = memory_allocate(sizeof(thread_T)); thread_T* thread = memory_allocate(sizeof(thread_T));
thread->process = scheduler_get_process(process);
if (thread->process == NULL) {
log(LOG_WARNING, "<Thread> failed to spawn thread for process %d (invalid pid)", process);
return NULL;
}
thread->stack_size = PFRAME_SIZE * 4; thread->stack_size = PFRAME_SIZE * 4;
thread->stack = memory_allocate(thread->stack_size); thread->stack = memory_allocate(thread->stack_size);
thread->cpu_time = 0; thread->cpu_time = 0;
@ -56,9 +63,15 @@ thread_T* thread_spawn(void* function) {
return scheduler_register_thread(thread); return scheduler_register_thread(thread);
} }
thread_T* thread_spawn_from_state(cpu_state_T* state) { thread_T* thread_spawn_from_state(pid_t process, cpu_state_T* state) {
thread_T* thread = memory_allocate(sizeof(thread_T)); thread_T* thread = memory_allocate(sizeof(thread_T));
thread->process = scheduler_get_process(process);
if (thread->process == NULL) {
log(LOG_WARNING, "<Thread> failed to spawn thread for process %d (invalid pid)", process);
return NULL;
}
thread->stack_size = 0; thread->stack_size = 0;
thread->stack = NULL; thread->stack = NULL;
thread->cpu_time = 0; thread->cpu_time = 0;