feature (proc): implemented basic process structure
This commit is contained in:
parent
bb4323ef79
commit
b732145fef
|
@ -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
|
|
@ -25,27 +25,48 @@
|
||||||
#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"
|
||||||
|
|
||||||
typedef struct {
|
#define SCHEDULER_PROCESS_CHUNK_SIZE 64
|
||||||
uint32_t num_threads;
|
|
||||||
thread_T* running_thread;
|
|
||||||
|
|
||||||
bool blocked;
|
typedef struct scheduler_processes_chunk_T scheduler_processes_chunk_T;
|
||||||
bool initialized;
|
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 {
|
||||||
|
uint32_t num_threads;
|
||||||
|
uint32_t num_processes;
|
||||||
|
thread_T* running_thread;
|
||||||
|
scheduler_processes_chunk_T* processes;
|
||||||
|
|
||||||
|
bool blocked;
|
||||||
|
bool initialized;
|
||||||
} scheduler_T;
|
} scheduler_T;
|
||||||
|
|
||||||
void scheduler_init ();
|
void scheduler_init ();
|
||||||
cpu_state_T* scheduler_start (cpu_state_T* state);
|
cpu_state_T* scheduler_start (cpu_state_T* state);
|
||||||
bool scheduler_is_initialized ();
|
bool scheduler_is_initialized ();
|
||||||
|
|
||||||
thread_T* scheduler_register_thread (thread_T* thread);
|
thread_T* scheduler_register_thread (thread_T* thread);
|
||||||
void scheduler_pause_thread (thread_T* thread);
|
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);
|
||||||
|
|
||||||
thread_T* scheduler_get_current_thread ();
|
pid_t scheduler_register_process (process_T* process);
|
||||||
|
void scheduler_kill_process (process_T* process);
|
||||||
|
process_T* scheduler_get_process (pid_t pid);
|
||||||
|
|
||||||
cpu_state_T* scheduler_switch_context (cpu_state_T* state);
|
thread_T* scheduler_get_current_thread ();
|
||||||
|
process_T* scheduler_get_current_process ();
|
||||||
|
|
||||||
|
cpu_state_T* scheduler_switch_context (cpu_state_T* state);
|
||||||
|
|
||||||
#endif //NOX_SCHEDULER_H
|
#endif //NOX_SCHEDULER_H
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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.running_thread = NULL;
|
g_scheduler.num_processes = 0;
|
||||||
g_scheduler.blocked = false;
|
g_scheduler.running_thread = NULL;
|
||||||
|
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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue