14using namespace MaxOS::common;
15using namespace MaxOS::processes;
16using namespace MaxOS::processes::resources;
17using namespace MaxOS::memory;
18using namespace MaxOS::hardwarecommunication;
19using namespace MaxOS::system;
20using namespace MaxOS::runtime;
21using namespace MaxOS::console;
43 core -> scheduler =
new Scheduler(core->id);
70 if(!s_instance || !s_instance->m_active)
74 ASSERT(s->rip != 0,
"Cant run a empty state\n");
88 delete core->scheduler;
97 s_instance -> m_active =
true;
99 core->scheduler->activate();
108 s_instance -> m_active =
false;
110 core->scheduler->deactivate();
135 if((check_threads && current->scheduler->thread_amount() < core->scheduler->thread_amount())
136 || current->scheduler->process_amount() < core->scheduler->process_amount())
152 for (
multiboot_tag* tag = multiboot->
start_tag(); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (
struct multiboot_tag*) ((multiboot_uint8_t*) tag + ((tag->size + 7) & ~7))) {
155 if (tag->type != MULTIBOOT_TAG_TYPE_MODULE)
159 auto*
module = (struct multiboot_tag_module*) tag;
161 Logger::DEBUG() <<
"Creating process from multiboot module for " <<
module->cmdline << " (at 0x" << (uint64_t) module->mod_start << ")\n";
164 if (strcmp(module->cmdline,
"initrd") == 0)
173 char* args[1] = {
module->cmdline};
176 auto* process =
new Process(module->cmdline, args, 1, &elf);
179 Logger::DEBUG() <<
"ELF loaded to pid " << process->pid() <<
"\n";
194 ASSERT(init_process !=
nullptr,
"Can't find init process\n");
198 uint32_t size =
module->mod_end - module->mod_start;
202 MemoryManager::switch_active_memory_manager(init_process->
memory_manager);
206 memcpy((
void*)0xFFF000, &size,
sizeof(uint32_t));
207 memcpy((
void*)(0xFFF000 +
sizeof(uint32_t)), (
void*)start, size);
217 if(!s_instance || !s_instance->m_active)
243 auto core_id = scheduler->
core_id();
247 m_core_pids.insert(pid,core_id);
254 debugger->attach(process->
threads()[0]);
257 Logger::DEBUG() <<
"Adding process " << pid <<
": " << process->
name <<
" to core " << core_id <<
"\n";
277 auto core_id = scheduler->
core_id();
281 m_core_tids.insert(tid,core_id);
283 Logger::DEBUG() <<
"Adding thread " << tid <<
" to core " << core_id <<
"\n";
299 auto core = s_instance -> m_core_pids[process->
pid()];
300 return CPU::cores[core]->scheduler->remove_process(process);
315 auto core = s_instance -> m_core_pids[process->
pid()];
316 return CPU::cores[core]->scheduler->force_remove_process(process);
326 if(!s_instance || !s_instance ->m_active)
344 auto core = s_instance -> m_core_pids[pid];
345 return CPU::cores[core]->scheduler->get_process(pid);
353 return s_instance -> m_next_pid++;
363 if(!s_instance || !s_instance ->m_active)
381 auto core = s_instance -> m_core_tids[tid];
382 return CPU::cores[core]->scheduler->get_thread(tid);
390 return s_instance->m_next_tid++;
411 return s_instance->m_active;
418: m_next_thread_index(0),
425 string name =
"Idle c";
426 name += string(m_core_id);
429 auto* idle =
new Process(name,
nullptr,
nullptr, 0,
true);
437Scheduler::~Scheduler() =
default;
449 if (m_threads.empty() || !m_active)
461 if (running_process && running_process->
is_kernel)
485 auto old_tid = m_next_thread_index;
494 while ((++m_next_thread_index) != old_tid){
495 m_next_thread_index %= m_threads.size();
504 case ThreadState::SLEEPING:
514 case ThreadState::STOPPED:
517 for (
auto thread: owner_process->
threads()) {
525 m_threads.erase(m_threads.begin() + m_next_thread_index);
526 if(owner_process->
threads().empty())
530 case ThreadState::WAITING:
539 int pid0 = m_processes.size() > 0 ? (int) m_processes[0]->pid() : -1;
540 int pid1 = m_processes.size() > 1 ? (int) m_processes[1]->pid() : -1;
541 int pid2 = m_processes.size() > 2 ? (int) m_processes[2]->pid() : -1;
542 ASSERT(owner_process !=
nullptr,
"No owner process: tid %d parent_pid %d core %d index %d threads %d processes %d pids %d %d %d\n",
544 (
int) m_next_thread_index, (
int) m_threads.size(), (
int) m_processes.size(), pid0, pid1, pid2);
565 MemoryManager::switch_active_memory_manager(process->
memory_manager);
567 if (process->
name ==
"DriverManager.elf")
590 m_processes.push_back(process);
593 for(
const auto& thread : process->
threads())
612 m_threads.push_back(thread);
655 if (!process->
threads().empty()) {
658 for (
auto thread: process->
threads())
667 for (uint32_t i = 0; i < m_processes.size(); i++) {
668 if (m_processes[i] == process) {
669 m_processes.erase(m_processes.begin() + i);
694 for (
auto thread: process->
threads()) {
697 size_t index = m_threads.find(thread) - m_threads.begin();
698 m_threads.erase(m_threads.begin() + index);
720 for (
auto process: m_processes)
738 for (
auto process: m_processes)
739 if (process->
pid() == pid)
751 return m_processes.size();
761 return m_threads[m_next_thread_index];
769 return m_threads.size();
789 for (
auto thread: m_threads)
790 if (thread->
tid == tid)
void printf(const char *format,...)
Prints a formatted string to the logger (thread safe)
static Logger * active_logger()
Gets the active logger (to be used to modify the logger)
static LogRecord DEBUG()
Gets the active logger for debug logs.
static LogRecord INFO()
Gets the active logger for info logs.
A driver for the serial output.
Handles a certain interrupt number.
virtual void handle_interrupt()
Handles an interrupt.
VirtualMemoryManager * vmm()
static MemoryManager * s_kernel_memory_manager
The memory manager for any kernel processes and all kernel allocations.
static void * to_dm_region(uintptr_t physical_address)
Converts a physical address to a direct map region address if it is in the lower region using the hig...
void * allocate(size_t size, size_t flags)
Allocate a new chunk of virtual memory.
Handles the loading and parsing of 64-bit ELF files.
bool is_valid() const
Checks if the elf file is valid for MaxOS runtime.
The global scheduler that manages all processes and threads across all cores.
static uint64_t next_pid()
Gets the next usable global PID.
static Scheduler * core_scheduler()
Gets the scheduler for the currently executing core.
static Process * get_process(uint64_t pid)
Gets a process on the currently executing core by its PID.
static uint64_t remove_process(Process *process)
Removes a process from the scheduler if the process has no threads, if it does then the threads are s...
uint64_t add_process(Process *process, Scheduler *scheduler=nullptr)
Adds a process to the least busy core.
static void print_running_header()
Print the header for the running processes in the form ({name}:t{tid}c{core})
static uint64_t next_tid()
Gets the next usable global TID.
uint64_t add_thread(Thread *thread, Scheduler *scheduler=nullptr)
Adds a thread to the least busy core.
static void prepare_initrd(multiboot_tag_module *module)
Loads the initrd into the init program at 0xFFF000.
~GlobalScheduler()
Destroys the global scheduler and frees the per core schedulers.
system::Core * least_busy_core(bool check_threads=false)
Finds the core with the least amount of threads/processes.
static GlobalScheduler * system_scheduler()
Gets the system scheduler.
static Process * current_process()
Gets the process on the currently executing core.
static Thread * get_thread(uint64_t tid)
Gets a thread on the currently executing core by its TID.
GlobalScheduler(system::Multiboot &multiboot)
Constructs a new Global Scheduler object. Registers as the interrupt handler for interrupt 0x20 and s...
static void activate()
Activates each core's scheduler.
static void deactivate()
Deactivates each core's scheduler.
static bool is_active()
Checks if the global scheduler is active.
void balance()
Moves processes and threads between cores to balance the load so that each core has a similar amount ...
static Thread * current_thread()
Gets the thread on the currently executing core.
static void load_multiboot_elfs(system::Multiboot *multiboot)
Loads any valid ELF files from the multiboot structure.
static system::cpu_status_t * force_remove_process(Process *process)
Removes a process from the scheduler and deletes all threads, begins running the next process.
A process that can be scheduled by the Scheduler, wraps & manages threads as well as its own address ...
uint64_t pid() const
Gets the pid of the process.
string name
The name of the process.
common::Vector< Thread * > threads()
Gets the threads of the process.
bool is_kernel
Whether this process is a kernel process.
void set_pid(uint64_t pid)
Sets the pid of the process once added to the queue.
void remove_thread(uint64_t tid)
Remove a thread by its tid (NOTE: this will not remove it from the scheduler)
memory::MemoryManager * memory_manager
The manager for memory used by this process.
Schedules processes to run on the core via their threads.
uint64_t remove_process(Process *process)
Removes a process from the scheduler if the process has no threads, if it does then the threads are s...
uint64_t ticks() const
Gets how long the system has been running for.
uint64_t thread_amount()
Gets how many threads are running on this scheduler.
Thread * current_thread()
Gets the currently executing thread.
system::cpu_status_t * force_remove_process(Process *process)
Removes a process from the scheduler and deletes all threads, begins running the next process.
Process * get_process(uint64_t pid)
Gets a process by its PID.
uint64_t add_process(Process *process)
Adds a process to the scheduler.
Thread * get_thread(uint64_t tid)
Gets a thread by its TID.
uint64_t add_thread(Thread *thread)
Adds a thread to the scheduler.
system::cpu_status_t * schedule(system::cpu_status_t *cpu_state)
Schedules the next thread to run.
uint64_t process_amount()
Gets how processes are running on this scheduler.
void activate()
Activates the scheduler.
Scheduler(uint64_t core_id)
Constructs a new Scheduler object and creates the idle process.
Process * current_process()
Gets the current process.
uint64_t core_id() const
Gets the core that this scheduler handles processes for.
system::cpu_status_t * schedule_next(system::cpu_status_t *status)
Schedules the next thread to run.
void deactivate()
Deactivates the scheduler.
The execution context of a sub-process thread.
uint64_t parent_pid
The parent process ID.
void save_sse_state()
Saves the SSE, x87 FPU, and MMX states from memory to the thread.
uint64_t tid
The thread ID.
volatile system::cpu_status_t execution_state
The CPU state of the thread.
volatile size_t ticks
The number of ticks the thread has run for.
uintptr_t tss_pointer() const
Gets the stack pointer to use for the TSS when switching to this thread.
volatile thread_state_t thread_state
The current state of the thread.
void restore_sse_state()
Restores the SSE, x87 FPU, and MMX states from the thread to memory.
volatile size_t wakeup_time
The time at which the thread should wake up (if sleeping)
void load_port_bitmap()
Copy this ports.
Handler for running a GDB server over serial.
static common::Vector< Core * > cores
The list of CPU cores in the system (populated during initialization, includes the BSP and cores that...
static Core * executing_core()
Gets the core that is currently executing.
Represents a CPU core in the system.
uint8_t id
The ID of this core.
processes::Scheduler * scheduler
The scheduler for this core.
Parses and provides access to Multiboot 2 information.
multiboot_tag * start_tag() const
struct PACKED MaxOS::system::CPUStatus cpu_status_t
Alias for CPUStatus struct.
GDB Stub definition for remote debugging userspace processes.
constexpr bool DO_DEBUGGING
Whether to use the serial for GDB communcation or for logging.
constexpr char * DEBUG_TARGET
The userspace process to attach to.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
@ PRESENT
The page is present in memory.
@ WRITE
Memory in this page is writable.
KPI::ResourceType resource_type_t
Alias to make the libsyscore ResourceType accessible here.
Defines a GlobalScheduler and Scheduler for managing processes and threads.
constexpr size_t TICKS_PER_EVENT
Number of times the clock has to interrupt before switching to the next process/thread.
A tag containing information about a loaded module.
multiboot_uint32_t mod_start
The starting address of the module.
Common header for all multiboot info tags.