Kernel: Sleep now actually sleeps and allows idling
This commit is contained in:
		
							parent
							
								
									66a4b69a29
								
							
						
					
					
						commit
						1bd8b0fe5c
					
				|  | @ -129,6 +129,8 @@ found: | ||||||
| 		else | 		else | ||||||
| 			dprintln("no handler for irq 0x{2H}\n", irq); | 			dprintln("no handler for irq 0x{2H}\n", irq); | ||||||
| 
 | 
 | ||||||
|  | 		// NOTE: Scheduler sends PIT eoi's
 | ||||||
|  | 		if (irq != PIT_IRQ) | ||||||
| 			InterruptController::get().eoi(irq); | 			InterruptController::get().eoi(irq); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,12 +11,11 @@ exit_thread_trampoline: | ||||||
| 	pushl %eax | 	pushl %eax | ||||||
| 	ret | 	ret | ||||||
| 
 | 
 | ||||||
| # void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rbp, uint32_t rip) | # void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rip) | ||||||
| .global start_thread
 | .global start_thread
 | ||||||
| start_thread: | start_thread: | ||||||
| 	movl %esp, %eax | 	movl %esp, %eax | ||||||
| 	movl 28(%eax), %ecx | 	movl 24(%eax), %ecx | ||||||
| 	movl 24(%eax), %ebp |  | ||||||
| 	movl 20(%eax), %esp | 	movl 20(%eax), %esp | ||||||
| 
 | 
 | ||||||
| 	pushl 16(%eax) | 	pushl 16(%eax) | ||||||
|  | @ -25,14 +24,15 @@ start_thread: | ||||||
| 	pushl 4(%eax) | 	pushl 4(%eax) | ||||||
| 	pushl $exit_thread_trampoline | 	pushl $exit_thread_trampoline | ||||||
| 
 | 
 | ||||||
|  | 	movl $0, %ebp | ||||||
|  | 
 | ||||||
| 	sti | 	sti | ||||||
| 	jmp *%ecx | 	jmp *%ecx | ||||||
| 
 | 
 | ||||||
| # void continue_thread(uint32_t rsp, uint32_t rbp, uint32_t rip) | # void continue_thread(uint32_t rsp, uint32_t rip) | ||||||
| .global continue_thread
 | .global continue_thread
 | ||||||
| continue_thread: | continue_thread: | ||||||
| 	movl 12(%esp), %ecx | 	movl 8(%esp), %ecx | ||||||
| 	movl 8(%esp), %ebp |  | ||||||
| 	movl 4(%esp), %esp | 	movl 4(%esp), %esp | ||||||
| 	movl $0, %eax | 	movl $0, %eax | ||||||
| 	jmp *%ecx | 	jmp *%ecx | ||||||
|  | @ -126,6 +126,8 @@ namespace IDT | ||||||
| 			dprintln("no handler for irq 0x{2H}\n", irq); | 			dprintln("no handler for irq 0x{2H}\n", irq); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		// NOTE: Scheduler sends PIT eoi's
 | ||||||
|  | 		if (irq != PIT_IRQ) | ||||||
| 			InterruptController::get().eoi(irq); | 			InterruptController::get().eoi(irq); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,20 +8,18 @@ exit_thread_trampoline: | ||||||
| 	movq 8(%rsp), %rdi | 	movq 8(%rsp), %rdi | ||||||
| 	ret | 	ret | ||||||
| 
 | 
 | ||||||
| # void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rbp, uint64_t rip) | # void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rip) | ||||||
| .global start_thread
 | .global start_thread
 | ||||||
| start_thread: | start_thread: | ||||||
| 	movq 8(%rsp), %rcx |  | ||||||
| 	movq %r8, %rsp | 	movq %r8, %rsp | ||||||
| 	movq %r9, %rbp | 	movq $0, %rbp | ||||||
| 	pushq $exit_thread_trampoline | 	pushq $exit_thread_trampoline | ||||||
| 	sti | 	sti | ||||||
| 	jmp *%rcx | 	jmp *%r9 | ||||||
| 
 | 
 | ||||||
| # void continue_thread(uint64_t rsp, uint64_t rbp, uint64_t rip) | # void continue_thread(uint64_t rsp, uint64_t rip) | ||||||
| .global continue_thread
 | .global continue_thread
 | ||||||
| continue_thread: | continue_thread: | ||||||
| 	movq %rdi, %rsp | 	movq %rdi, %rsp | ||||||
| 	movq %rsi, %rbp |  | ||||||
| 	movq $0, %rax | 	movq $0, %rax | ||||||
| 	jmp *%rdx | 	jmp *%rsi | ||||||
|  | @ -19,27 +19,33 @@ namespace Kernel | ||||||
| 		const Thread& current_thread() const; | 		const Thread& current_thread() const; | ||||||
| 
 | 
 | ||||||
| 		template<typename... Args> | 		template<typename... Args> | ||||||
| 		void add_thread(const BAN::Function<void(Args...)>& func, Args... args) | 		[[nodiscard]] BAN::ErrorOr<void> add_thread(const BAN::Function<void(Args...)>& func, Args... args) | ||||||
| 		{ | 		{ | ||||||
| 			uintptr_t flags; | 			uintptr_t flags; | ||||||
| 			asm volatile("pushf; pop %0" : "=r"(flags)); | 			asm volatile("pushf; pop %0" : "=r"(flags)); | ||||||
| 			asm volatile("cli"); | 			asm volatile("cli"); | ||||||
| 			MUST(m_threads.emplace_back(func, BAN::forward<Args>(args)...)); | 			TRY(m_threads.emplace_back(func, BAN::forward<Args>(args)...)); | ||||||
| 			if (flags & (1 << 9)) | 			if (flags & (1 << 9)) | ||||||
| 				asm volatile("sti"); | 				asm volatile("sti"); | ||||||
|  | 			return {}; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		void switch_thread(); | 		void reschedule(); | ||||||
|  | 		void set_current_thread_sleeping(); | ||||||
| 		void start(); | 		void start(); | ||||||
| 
 | 
 | ||||||
| 		static constexpr size_t ms_between_switch = 1; | 		static constexpr size_t ms_between_switch = 4; | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		Scheduler() {} | 		Scheduler() {} | ||||||
|  | 		void switch_thread(); | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		BAN::LinkedList<Thread>				m_threads; | 		BAN::LinkedList<Thread>				m_threads; | ||||||
| 		BAN::LinkedList<Thread>::iterator	m_current_iterator; | 		BAN::LinkedList<Thread>::iterator	m_current_iterator; | ||||||
|  | 		uint64_t							m_last_reschedule = 0; | ||||||
|  | 
 | ||||||
|  | 		friend class Thread; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -17,6 +17,7 @@ namespace Kernel | ||||||
| 			NotStarted, | 			NotStarted, | ||||||
| 			Running, | 			Running, | ||||||
| 			Paused, | 			Paused, | ||||||
|  | 			Sleeping, | ||||||
| 			Done, | 			Done, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
|  | @ -36,11 +37,9 @@ namespace Kernel | ||||||
| 		uint32_t id() const { return m_id; } | 		uint32_t id() const { return m_id; } | ||||||
| 
 | 
 | ||||||
| 		void set_rsp(uintptr_t rsp) { m_rsp = rsp; } | 		void set_rsp(uintptr_t rsp) { m_rsp = rsp; } | ||||||
| 		void set_rbp(uintptr_t rbp) { m_rbp = rbp; } |  | ||||||
| 		void set_rip(uintptr_t rip) { m_rip = rip; } | 		void set_rip(uintptr_t rip) { m_rip = rip; } | ||||||
| 		void set_state(State state) { m_state = state; } | 		void set_state(State state) { m_state = state; } | ||||||
| 		uintptr_t rsp() const { return m_rsp; } | 		uintptr_t rsp() const { return m_rsp; } | ||||||
| 		uintptr_t rbp() const { return m_rbp; } |  | ||||||
| 		uintptr_t rip() const { return m_rip; } | 		uintptr_t rip() const { return m_rip; } | ||||||
| 		State state() const { return m_state; } | 		State state() const { return m_state; } | ||||||
| 
 | 
 | ||||||
|  | @ -55,7 +54,6 @@ namespace Kernel | ||||||
| 		State			m_state			= State::NotStarted; | 		State			m_state			= State::NotStarted; | ||||||
| 		uintptr_t		m_args[4]		= {}; | 		uintptr_t		m_args[4]		= {}; | ||||||
| 		uintptr_t		m_rip			= 0; | 		uintptr_t		m_rip			= 0; | ||||||
| 		uintptr_t		m_rbp			= 0; |  | ||||||
| 		uintptr_t		m_rsp			= 0; | 		uintptr_t		m_rsp			= 0; | ||||||
| 		const uint32_t	m_id			= 0; | 		const uint32_t	m_id			= 0; | ||||||
| 		 | 		 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ namespace PIT | ||||||
| 	void irq_handler() | 	void irq_handler() | ||||||
| 	{ | 	{ | ||||||
| 		s_system_time++; | 		s_system_time++; | ||||||
| 		Kernel::Scheduler::get().switch_thread(); | 		Kernel::Scheduler::get().reschedule(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	uint64_t ms_since_boot() | 	uint64_t ms_since_boot() | ||||||
|  | @ -54,7 +54,7 @@ namespace PIT | ||||||
| 	{ | 	{ | ||||||
| 		uint64_t end = s_system_time + ms; | 		uint64_t end = s_system_time + ms; | ||||||
| 		while (s_system_time < end) | 		while (s_system_time < end) | ||||||
| 			asm volatile("hlt"); | 			Kernel::Scheduler::get().set_current_thread_sleeping(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,14 +7,16 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	static Scheduler* s_instance = nullptr; | 	static Scheduler* s_instance = nullptr; | ||||||
| 
 | 
 | ||||||
| 	extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rbp, uintptr_t rip); | 	extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rip); | ||||||
| 	extern "C" void continue_thread(uintptr_t rsp, uintptr_t rbp, uintptr_t rip); | 	extern "C" void continue_thread(uintptr_t rsp, uintptr_t rip); | ||||||
| 	extern "C" uintptr_t read_rip(); | 	extern "C" uintptr_t read_rip(); | ||||||
| 
 | 
 | ||||||
| 	void Scheduler::initialize() | 	void Scheduler::initialize() | ||||||
| 	{ | 	{ | ||||||
| 		ASSERT(!s_instance); | 		ASSERT(!s_instance); | ||||||
| 		s_instance = new Scheduler(); | 		s_instance = new Scheduler(); | ||||||
|  | 		ASSERT(s_instance); | ||||||
|  | 		MUST(s_instance->add_thread(BAN::Function<void()>([] { for(;;) asm volatile("hlt"); }))); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Scheduler& Scheduler::get() | 	Scheduler& Scheduler::get() | ||||||
|  | @ -28,72 +30,92 @@ namespace Kernel | ||||||
| 		return *m_current_iterator; | 		return *m_current_iterator; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void Scheduler::reschedule() | ||||||
|  | 	{ | ||||||
|  | 		ASSERT(InterruptController::get().is_in_service(PIT_IRQ)); | ||||||
|  | 		InterruptController::get().eoi(PIT_IRQ); | ||||||
|  | 
 | ||||||
|  | 		uint64_t current_time = PIT::ms_since_boot(); | ||||||
|  | 		if (m_last_reschedule + ms_between_switch > current_time) | ||||||
|  | 			return; | ||||||
|  | 		m_last_reschedule = current_time; | ||||||
|  | 
 | ||||||
|  | 		for (Thread& thread : m_threads) | ||||||
|  | 			if (thread.state() == Thread::State::Sleeping) | ||||||
|  | 				thread.set_state(Thread::State::Paused); | ||||||
|  | 
 | ||||||
|  | 		switch_thread(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void Scheduler::switch_thread() | 	void Scheduler::switch_thread() | ||||||
| 	{ | 	{ | ||||||
| 		uintptr_t rsp, rbp, rip; | 		uintptr_t rsp, rip; | ||||||
|  | 		push_callee_saved(); | ||||||
| 		if (!(rip = read_rip())) | 		if (!(rip = read_rip())) | ||||||
|  | 		{ | ||||||
|  | 			pop_callee_saved(); | ||||||
| 			return; | 			return; | ||||||
|  | 		} | ||||||
| 		read_rsp(rsp); | 		read_rsp(rsp); | ||||||
| 		read_rbp(rbp); |  | ||||||
| 
 | 
 | ||||||
| 		static uint8_t cnt = 0; | 		ASSERT(m_threads.size() > 1); | ||||||
| 		if (cnt++ % ms_between_switch) |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		ASSERT(InterruptController::get().is_in_service(PIT_IRQ)); |  | ||||||
| 
 |  | ||||||
| 		ASSERT(m_threads.size() > 0); |  | ||||||
| 		if (m_threads.size() == 1) |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		ASSERT(m_current_iterator); |  | ||||||
| 
 |  | ||||||
| 		auto next_iterator = m_current_iterator; |  | ||||||
| 		if (++next_iterator == m_threads.end()) |  | ||||||
| 			next_iterator = m_threads.begin(); |  | ||||||
| 		 | 		 | ||||||
| 		Thread& current = *m_current_iterator; | 		Thread& current = *m_current_iterator; | ||||||
| 		Thread& next 	= *next_iterator; |  | ||||||
| 
 | 
 | ||||||
| 		ASSERT(next.state() == Thread::State::Paused || next.state() == Thread::State::NotStarted); | 		//if (m_threads.size() == 2 && current.id() != 0 && current.state() == Thread::State::Running)
 | ||||||
|  | 		//	return;
 | ||||||
| 
 | 
 | ||||||
| 		if (current.state() == Thread::State::Done) | 		if (current.state() == Thread::State::Done) | ||||||
| 		{ | 		{ | ||||||
| 			// NOTE: this does not invalidate the next/next_iterator
 |  | ||||||
| 			//       since we are working with linked list
 |  | ||||||
| 			m_threads.remove(m_current_iterator); | 			m_threads.remove(m_current_iterator); | ||||||
| 			m_current_iterator = decltype(m_threads)::iterator(); | 			m_current_iterator = m_threads.begin(); | ||||||
| 		} | 		} | ||||||
| 
 | 		else | ||||||
| 		if (m_current_iterator) |  | ||||||
| 		{ | 		{ | ||||||
| 			current.set_rsp(rsp); | 			current.set_rsp(rsp); | ||||||
| 			current.set_rbp(rbp); |  | ||||||
| 			current.set_rip(rip); | 			current.set_rip(rip); | ||||||
|  | 			if (current.state() != Thread::State::Sleeping) | ||||||
| 				current.set_state(Thread::State::Paused); | 				current.set_state(Thread::State::Paused); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		auto next_iterator = m_current_iterator; | ||||||
|  | 		if (++next_iterator == m_threads.end()) | ||||||
|  | 			next_iterator = ++m_threads.begin(); | ||||||
|  | 		if (next_iterator->state() == Thread::State::Sleeping) | ||||||
|  | 			next_iterator = m_threads.begin(); | ||||||
|  | 		Thread& next = *next_iterator; | ||||||
|  | 
 | ||||||
| 		m_current_iterator = next_iterator; | 		m_current_iterator = next_iterator; | ||||||
| 
 | 
 | ||||||
| 		if (next.state() == Thread::State::NotStarted) | 		switch (next.state()) | ||||||
| 		{ | 		{ | ||||||
| 			InterruptController::get().eoi(PIT_IRQ); | 			case Thread::State::NotStarted: | ||||||
| 				next.set_state(Thread::State::Running); | 				next.set_state(Thread::State::Running); | ||||||
| 			const uintptr_t* args = next.args(); | 				start_thread(next.args()[0], next.args()[1], next.args()[2], next.args()[3], next.rsp(), next.rip()); | ||||||
| 			start_thread(args[0], args[1], args[2], args[3], next.rsp(), next.rbp(), next.rip()); | 				break; | ||||||
| 		} | 			case Thread::State::Paused: | ||||||
| 		else if (next.state() == Thread::State::Paused) |  | ||||||
| 		{ |  | ||||||
| 				next.set_state(Thread::State::Running); | 				next.set_state(Thread::State::Running); | ||||||
| 			continue_thread(next.rsp(), next.rbp(), next.rip()); | 				continue_thread(next.rsp(), next.rip()); | ||||||
|  | 				break; | ||||||
|  | 			case Thread::State::Sleeping:	ASSERT(false); | ||||||
|  | 			case Thread::State::Running:	ASSERT(false); | ||||||
|  | 			case Thread::State::Done:		ASSERT(false); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		ASSERT(false); | 		ASSERT(false); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | 	void Scheduler::set_current_thread_sleeping() | ||||||
|  | 	{ | ||||||
|  | 		asm volatile("cli"); | ||||||
|  | 		m_current_iterator->set_state(Thread::State::Sleeping); | ||||||
|  | 		switch_thread(); | ||||||
|  | 		asm volatile("sti"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void Scheduler::start() | 	void Scheduler::start() | ||||||
| 	{ | 	{ | ||||||
| 		ASSERT(m_threads.size() > 0); | 		ASSERT(m_threads.size() > 1); | ||||||
| 
 | 
 | ||||||
| 		m_current_iterator = m_threads.begin(); | 		m_current_iterator = m_threads.begin(); | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +124,7 @@ namespace Kernel | ||||||
| 		current.set_state(Thread::State::Running); | 		current.set_state(Thread::State::Running); | ||||||
| 
 | 
 | ||||||
| 		const uintptr_t* args = current.args(); | 		const uintptr_t* args = current.args(); | ||||||
| 		start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rbp(), current.rip()); | 		start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rip()); | ||||||
| 
 | 
 | ||||||
| 		ASSERT(false); | 		ASSERT(false); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -10,9 +10,9 @@ | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	static uint32_t s_next_id = 1; | 	static uint32_t s_next_id = 0; | ||||||
| 
 | 
 | ||||||
| 	static constexpr size_t thread_stack_size = PAGE_SIZE; | 	static constexpr size_t thread_stack_size = 16384; | ||||||
| 
 | 
 | ||||||
| 	template<size_t size, typename T> | 	template<size_t size, typename T> | ||||||
| 	static void write_to_stack(uintptr_t& rsp, const T& value) | 	static void write_to_stack(uintptr_t& rsp, const T& value) | ||||||
|  | @ -27,8 +27,7 @@ namespace Kernel | ||||||
| 		m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE); | 		m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE); | ||||||
| 		ASSERT(m_stack_base); | 		ASSERT(m_stack_base); | ||||||
| 	 | 	 | ||||||
| 		m_rbp = (uintptr_t)m_stack_base + thread_stack_size; | 		m_rsp = (uintptr_t)m_stack_base + thread_stack_size; | ||||||
| 		m_rsp = m_rbp; |  | ||||||
| 		m_rip = rip; | 		m_rip = rip; | ||||||
| 		m_args[1] = arg1; | 		m_args[1] = arg1; | ||||||
| 		m_args[2] = arg2; | 		m_args[2] = arg2; | ||||||
|  | @ -54,8 +53,10 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	void Thread::on_exit() | 	void Thread::on_exit() | ||||||
| 	{ | 	{ | ||||||
|  | 		asm volatile("cli"); | ||||||
| 		m_state = State::Done; | 		m_state = State::Done; | ||||||
| 		for (;;) asm volatile("hlt"); | 		Scheduler::get().switch_thread(); | ||||||
|  | 		ASSERT(false); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -97,8 +97,8 @@ extern "C" void kernel_main() | ||||||
| 
 | 
 | ||||||
| 	Scheduler::initialize(); | 	Scheduler::initialize(); | ||||||
| 	Scheduler& scheduler = Scheduler::get(); | 	Scheduler& scheduler = Scheduler::get(); | ||||||
| 	scheduler.add_thread(BAN::Function<void()>([] { DiskIO::initialize(); })); | 	MUST(scheduler.add_thread(BAN::Function<void()>([] { DiskIO::initialize(); }))); | ||||||
| 	scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); })); | 	MUST(scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); }))); | ||||||
| 	scheduler.start(); | 	scheduler.start(); | ||||||
| 	ASSERT(false); | 	ASSERT(false); | ||||||
| } | } | ||||||
		Loading…
	
		Reference in New Issue