Max OS 0.3
Loading...
Searching...
No Matches
scheduler.cpp
Go to the documentation of this file.
1
10#include <common/logger.h>
11
12using namespace MaxOS;
13using namespace MaxOS::processes;
14using namespace MaxOS::memory;
15using namespace MaxOS::hardwarecommunication;
16using namespace MaxOS::system;
17
25: InterruptHandler(0x20),
26 m_shared_memory_registry(resource_type_t::SHARED_MEMORY),
27 m_shared_messages_registry(resource_type_t::MESSAGE_ENDPOINT),
28 m_next_pid(-1),
29 m_next_tid(-1)
30{
31
32 // Set up the global scheduler
33 Logger::INFO() << "Setting up global Scheduler\n";
34 s_instance = this;
35
36 // Set up the per core scheduler
37 for(const auto& core : CPU::cores)
38 core -> scheduler = new Scheduler();
39
40 // Load the elfs
41 load_multiboot_elfs(&multiboot);
42
43}
44
51
52 return s_instance;
53}
54
55
63
64 // Scheduler not active
65 if(!s_instance || !s_instance->m_active)
66 return status;
67
68 auto s = core_scheduler()->schedule(status);
69 ASSERT(s->rip != 0, "Cant run a empty state\n");
70 return s;
71}
72
83
88
89 // No longer the global instance
90 s_instance = nullptr;
91
92 // Free the per core scheduler
93 for(const auto& core : CPU::cores)
94 delete core->scheduler;
95
96}
97
102
103 s_instance -> m_active = true;
104 for(const auto& core : CPU::cores)
105 core->scheduler->activate();
106
107}
108
113
114 s_instance -> m_active = false;
115 for(const auto& core : CPU::cores)
116 core->scheduler->deactivate();
117
118}
119
127
128}
129
130
139
140 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))) {
141
142 // Tag is not an ELF
143 if (tag->type != MULTIBOOT_TAG_TYPE_MODULE)
144 continue;
145
146 // Try to create the elf from the module
147 auto* module = (struct multiboot_tag_module*) tag;
148 ELF64 elf((uintptr_t) PhysicalMemoryManager::to_dm_region(module->mod_start));
149 if (!elf.is_valid())
150 continue;
151
152 Logger::DEBUG() << "Creating process from multiboot module for " << module->cmdline << " (at 0x" << (uint64_t) module->mod_start << ")\n";
153
154 // Create an array of args for the process
155 char* args[1] = {module->cmdline};
156
157 // Create the process
158 auto* process = new Process(module->cmdline, args, 1, &elf);
160
161 Logger::DEBUG() << "ELF loaded to pid " << process->pid() << "\n";
162 }
163}
164
169
170 // No threads or processes to get
171 if(!s_instance || !s_instance->m_active)
172 return;
173
174 auto process = current_process();
175 auto thread = current_thread();
176
177 Logger::Out() << "(" << process->name << ":t" << thread->tid << "c" << CPU::executing_core()->id << ") ";
178}
179
187
188 // No cores?
189 if(CPU::cores.empty())
190 return 0;
191
192 // Find the core with the least processes
193 uint64_t core_id = 0;
194 Scheduler* scheduler = CPU::cores[core_id]->scheduler;
195 for(const auto& core : CPU::cores){
196 auto core_scheduler = core->scheduler;
197 if(core_scheduler->process_amount() < scheduler->process_amount()){
198 core_id = core->id;
199 scheduler = core_scheduler;
200 }
201 }
202
203 // Save the pid
204 auto pid = scheduler->add_process(process);
205 m_core_pids.insert(pid,core_id);
206
207 Logger::DEBUG() << "Adding process " << pid << ": " << process->name << " to core " << core_id <<"\n";
208 return pid;
209}
210
218
219 // No cores?
220 if(CPU::cores.empty())
221 return 0;
222
223 // Find the core with the least threads
224 uint64_t core_id = 0;
225 Scheduler* scheduler = CPU::cores[core_id]->scheduler;
226 for(const auto& core : CPU::cores){
227 auto core_scheduler = core->scheduler;
228 if(core_scheduler->thread_amount() < scheduler->thread_amount()){
229 core_id = core->id;
230 scheduler = core_scheduler;
231 }
232 }
233
234 // Save the tid
235 auto tid = scheduler->add_thread(thread);
236 m_core_tids.insert(tid,core_id);
237
238 Logger::DEBUG() << "Adding thread " << tid << " to core " << core_id <<"\n";
239 return tid;
240}
241
249
250 // Get the core running the process
251 if(!s_instance)
252 return 0;
253
254 auto core = s_instance -> m_core_pids[process->pid()];
255 return CPU::cores[core]->scheduler->remove_process(process);
256}
257
265
266 // Get the core running the process
267 if(!s_instance)
268 return nullptr;
269
270 auto core = s_instance -> m_core_pids[process->pid()];
271 return CPU::cores[core]->scheduler->force_remove_process(process);
272
273}
274
281 if(!s_instance || !s_instance ->m_active)
282 return nullptr;
283
285}
286
294
295 // Get the core running the pid
296 if(!s_instance)
297 return nullptr;
298
299 auto core = s_instance -> m_core_pids[pid];
300 return CPU::cores[core]->scheduler->get_process(pid);
301}
302
308 return s_instance -> m_next_pid++;
309}
310
319
327
328 // Get the core running the tid
329 if(!s_instance)
330 return nullptr;
331
332 auto core = s_instance -> m_core_tids[tid];
333 return CPU::cores[core]->scheduler->get_thread(tid);
334}
335
341 return s_instance->m_next_tid++;
342}
343
352
359 return s_instance->m_active;
360}
361
366: m_next_thread_index(0),
367 m_active(false),
368 m_ticks(0)
369{
370
371 // Create this idle process
372 auto* idle = new Process("Idle", nullptr, nullptr, 0, true);
373 idle->memory_manager = MemoryManager::s_kernel_memory_manager;
374 idle->set_pid(0);
375 add_process(idle);
376}
377
378Scheduler::~Scheduler() = default;
379
380
388
389 // Scheduler cant schedule anything
390 if (m_threads.empty() || !m_active)
391 return cpu_state;
392
393 // Thread that we are dealing with
394 Thread* current_thread = m_threads[m_next_thread_index];
395
396 // Ticked
397 m_ticks++;
399
400 // Thread hasn't used its time slot yet
402 return cpu_state;
403
404 // Schedule the next thread
405 return schedule_next(cpu_state);
406}
407
417
418 // Get the current state
419 Thread* current_thread = m_threads[m_next_thread_index];
420 Process* owner_process = current_process();
421 auto old_tid = m_next_thread_index;
422
423 // Save the executing thread state
424 current_thread->execution_state = *cpu_state;
426 if (current_thread->thread_state == ThreadState::RUNNING)
427 current_thread->thread_state = ThreadState::READY;
428
429 // Find a free thread to run
430 while ((++m_next_thread_index) != old_tid){
431 m_next_thread_index %= m_threads.size();
432
433 // Get the current thread
434 current_thread = m_threads[m_next_thread_index];
435 owner_process = current_process();
436
437 // Handle state changes
438 switch (current_thread->thread_state) {
439
440 case ThreadState::SLEEPING:
441
442 // If the wake-up time hasn't occurred yet, run the next thread
445 continue;
446 }
447
448 break;
449
450 case ThreadState::STOPPED:
451
452 // Find the process that has the thread and remove it
453 for (auto thread: owner_process->threads()) {
454 if (thread == current_thread) {
455 owner_process->remove_thread(thread->tid);
456 break;
457 }
458 }
459
460 // Remove the thread
461 m_threads.erase(m_threads.begin() + m_next_thread_index);
462 if(owner_process->threads().empty())
463 remove_process(owner_process);
464 continue;
465
466 case ThreadState::WAITING:
467 continue;
468
469 default:
470 break;
471 }
472 break;
473 }
474
475 // Load the thread's state
476 return load_process(owner_process, current_thread);
477}
478
486cpu_status_t* Scheduler::load_process(Process* process, Thread* thread) {
487
488 // Prepare the next thread to run
489 thread->thread_state = ThreadState::RUNNING;
490 thread->restore_sse_state();
491
492 // Load the thread's memory manager and task state
494 CPU::executing_core() -> tss.rsp0 = thread->tss_pointer();
495
496 return &thread->execution_state;
497}
498
505uint64_t Scheduler::add_process(Process* process) {
506
507 // Get the next process ID
508 auto pid = GlobalScheduler::next_pid();
509 process->set_pid(pid);
510
511 // Add the process to the list
512 m_processes.push_back(process);
513
514 // Add the threads to the list
515 for(const auto& thread : process->threads())
516 thread->tid = add_thread(thread);
517
518 return pid;
519}
520
527uint64_t Scheduler::add_thread(Thread* thread) {
528
529 // Get the next thread ID
530 auto tid = GlobalScheduler::next_tid();
531 thread->tid = tid;
532
533 // Add the thread to the list
534 m_threads.push_back(thread);
535
536 // Return the thread ID
537 return tid;
538}
539
545uint64_t Scheduler::ticks() const {
546
547 return m_ticks;
548}
549
556
557 // If this is the only thread, can't yield
558 if (m_threads.size() <= 1)
560
561 // Set the current thread to waiting if running
562 auto thread = current_thread();
563 if (thread->thread_state == ThreadState::RUNNING)
564 thread->thread_state = ThreadState::READY;
565
566 // Schedule the next thread
567 return schedule_next(&thread->execution_state);
568}
569
574
575 m_active = true;
576}
577
585
586 // Check if the process has no threads
587 if (!process->threads().empty()) {
588
589 // Set the threads to stopped or remove them if forced
590 for (auto thread: process->threads())
591 thread->thread_state = ThreadState::STOPPED;
592
593 // Need to wait until the threads are stopped before removing the process (this will be called again when all threads are stopped)
594 return -1;
595
596 }
597
598 // Remove the process
599 for (uint32_t i = 0; i < m_processes.size(); i++) {
600 if (m_processes[i] == process) {
601 m_processes.erase(m_processes.begin() + i);
602
603 // Delete the process mem
604 delete process;
605 return 0;
606 }
607 }
608
609 // Process not found
610 return -1;
611}
612
620
621 // If there is no process, fail
622 if (!process)
623 return nullptr;
624
625 // Remove all the threads
626 for (auto thread: process->threads()) {
627
628 // Remove the thread from the scheduler
629 size_t index = m_threads.find(thread) - m_threads.begin();
630 m_threads.erase(m_threads.begin() + index);
631
632 // Delete the thread
633 process->remove_thread(thread->tid);
634
635 }
636
637 // Process will be dead now so run the next process (don't care about the execution state being outdated as it is being
638 // removed regardless)
639 return schedule_next(&current_thread()->execution_state);
640}
641
648
649 Process* current_process = nullptr;
650
651 // Find the process that has the thread being executed
652 for (auto process: m_processes)
653 if (process->pid() == current_thread()->parent_pid) {
654 current_process = process;
655 break;
656 }
657
658 return current_process;
659}
660
668
669 // Try to find the process
670 for (auto process: m_processes)
671 if (process->pid() == pid)
672 return process;
673
674 // Not found
675 return nullptr;
676}
677
683 return m_processes.size();
684}
685
692
693 return m_threads[m_next_thread_index];
694}
695
701 return m_threads.size();
702}
703
708
709 m_active = false;
710}
711
719
720 // Try to find the thread
721 for (auto thread: m_threads)
722 if (thread->tid == tid)
723 return thread;
724
725 return nullptr;
726}
static Logger DEBUG()
Gets active logger set to DEBUG level.
Definition logger.cpp:193
static Logger & Out()
Gets the active logger.
Definition logger.cpp:149
static Logger INFO()
Gets active logger set to info level.
Definition logger.cpp:171
void insert(Key, Value)
Updates the value of an element, or adds a new element if it does not exist.
Definition map.h:253
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Handles a certain interrupt number.
Definition interrupts.h:30
virtual void handle_interrupt()
Handles an interrupt.
static MemoryManager * s_kernel_memory_manager
The memory manager for any kernel processes and all kernel allocations.
static void switch_active_memory_manager(MemoryManager *manager)
Switches the active memory manager.
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...
Definition physical.cpp:930
Handles the loading and parsing of 64-bit ELF files.
Definition elf.h:217
bool is_valid() const
Checks if the elf file is valid for MaxOS runtime.
Definition elf.cpp:100
The global scheduler that manages all processes and threads across all cores.
Definition scheduler.h:26
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...
static system::cpu_status_t * yield(system::cpu_status_t *current)
Pass execution to the next thread.
Definition scheduler.cpp:79
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.
~GlobalScheduler()
Destroys the global scheduler and frees the per core schedulers.
Definition scheduler.cpp:87
static GlobalScheduler * system_scheduler()
Gets the system scheduler.
Definition scheduler.cpp:50
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...
Definition scheduler.cpp:24
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.
uint64_t add_process(Process *process)
Adds a process to the least busy core.
uint64_t add_thread(Thread *thread)
Adds a thread to the least busy 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 ...
Definition process.h:85
uint64_t pid() const
Gets the pid of the process.
Definition process.cpp:326
string name
The name of the process.
Definition process.h:109
common::Vector< Thread * > threads()
Gets the threads of the process.
Definition process.cpp:316
void set_pid(uint64_t pid)
Sets the pid of the process once added to the queue.
Definition process.cpp:296
void remove_thread(uint64_t tid)
Remove a thread by its tid (NOTE: this will not remove it from the scheduler)
Definition process.cpp:272
memory::MemoryManager * memory_manager
The manager for memory used by this process.
Definition process.h:112
Schedules processes to run on the core via their threads.
Definition scheduler.h:85
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.
Scheduler()
Constructs a new Scheduler object and creates the idle process.
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 * yield()
Pass execution to the next 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.
Process * current_process()
Gets the current process.
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.
Definition process.h:49
thread_state_t thread_state
The current state of the thread.
Definition process.h:68
uint64_t parent_pid
The parent process ID.
Definition process.h:65
void save_sse_state()
Saves the SSE, x87 FPU, and MMX states from memory to the thread.
Definition process.cpp:92
uint64_t tid
The thread ID.
Definition process.h:64
size_t wakeup_time
The time at which the thread should wake up (if sleeping)
Definition process.h:71
system::cpu_status_t execution_state
The CPU state of the thread.
Definition process.h:67
uintptr_t tss_pointer() const
Gets the stack pointer to use for the TSS when switching to this thread.
Definition process.h:73
void restore_sse_state()
Restores the SSE, x87 FPU, and MMX states from the thread to memory.
Definition process.cpp:105
size_t ticks
The number of ticks the thread has run for.
Definition process.h:70
static common::Vector< Core * > cores
The list of CPU cores in the system (populated during initialization, includes the BSP and cores that...
Definition cpu.h:270
static Core * executing_core()
Gets the core that is currently executing.
Definition cpu.cpp:623
uint8_t id
The ID of this core.
Definition cpu.h:240
processes::Scheduler * scheduler
The scheduler for this core.
Definition cpu.h:246
Parses and provides access to Multiboot 2 information.
Definition multiboot.h:518
multiboot_tag * start_tag() const
struct PACKED MaxOS::system::CPUStatus cpu_status_t
Alias for CPUStatus struct.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
Definition logger.h:100
::syscore::ResourceType resource_type_t
Alias to make the libsyscore ResourceType accessible here.
Definition resource.h:22
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.
Definition scheduler.h:79
Common header for all multiboot info tags.
Definition multiboot.h:234