Kernel: Add Semaphore to block threads
This commit is contained in:
		
							parent
							
								
									7b7f4eb141
								
							
						
					
					
						commit
						c2e3b422cc
					
				|  | @ -57,6 +57,7 @@ kernel/PIT.o					\ | ||||||
| kernel/Process.o				\ | kernel/Process.o				\ | ||||||
| kernel/RTC.o					\ | kernel/RTC.o					\ | ||||||
| kernel/Scheduler.o				\ | kernel/Scheduler.o				\ | ||||||
|  | kernel/Semaphore.o				\ | ||||||
| kernel/Serial.o					\ | kernel/Serial.o					\ | ||||||
| kernel/Shell.o					\ | kernel/Shell.o					\ | ||||||
| kernel/SpinLock.o				\ | kernel/SpinLock.o				\ | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| #include <kernel/Input/KeyEvent.h> | #include <kernel/Input/KeyEvent.h> | ||||||
| #include <kernel/Input/PS2Controller.h> | #include <kernel/Input/PS2Controller.h> | ||||||
| #include <kernel/Input/PS2Keymap.h> | #include <kernel/Input/PS2Keymap.h> | ||||||
|  | #include <kernel/Semaphore.h> | ||||||
| 
 | 
 | ||||||
| namespace Kernel::Input | namespace Kernel::Input | ||||||
| { | { | ||||||
|  | @ -60,6 +61,8 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 		State m_state { State::Normal }; | 		State m_state { State::Normal }; | ||||||
| 
 | 
 | ||||||
|  | 		Semaphore m_semaphore; | ||||||
|  | 
 | ||||||
| 		BAN::String m_name; | 		BAN::String m_name; | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <BAN/LinkedList.h> | #include <BAN/LinkedList.h> | ||||||
| #include <BAN/Memory.h> | #include <BAN/Memory.h> | ||||||
|  | #include <kernel/Semaphore.h> | ||||||
| #include <kernel/Thread.h> | #include <kernel/Thread.h> | ||||||
| 
 | 
 | ||||||
| namespace Kernel | namespace Kernel | ||||||
|  | @ -21,6 +22,9 @@ namespace Kernel | ||||||
| 		void set_current_thread_sleeping(uint64_t); | 		void set_current_thread_sleeping(uint64_t); | ||||||
| 		[[noreturn]] void set_current_thread_done(); | 		[[noreturn]] void set_current_thread_done(); | ||||||
| 
 | 
 | ||||||
|  | 		void block_current_thread(Semaphore*); | ||||||
|  | 		void unblock_threads(Semaphore*); | ||||||
|  | 
 | ||||||
| 		BAN::RefPtr<Thread> current_thread(); | 		BAN::RefPtr<Thread> current_thread(); | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
|  | @ -47,9 +51,18 @@ namespace Kernel | ||||||
| 			uint64_t wake_time; | 			uint64_t wake_time; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
|  | 		struct BlockingThread | ||||||
|  | 		{ | ||||||
|  | 			BlockingThread(const BAN::RefPtr<Thread>& thread, Semaphore* semaphore) : thread(thread), semaphore(semaphore) {} | ||||||
|  | 			BAN::RefPtr<Thread> thread; | ||||||
|  | 			Semaphore* semaphore; | ||||||
|  | 			uint8_t padding[sizeof(uint64_t) - sizeof(Semaphore*)]; | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
| 		BAN::RefPtr<Thread> m_idle_thread; | 		BAN::RefPtr<Thread> m_idle_thread; | ||||||
| 		BAN::LinkedList<ActiveThread> m_active_threads; | 		BAN::LinkedList<ActiveThread> m_active_threads; | ||||||
| 		BAN::LinkedList<SleepingThread> m_sleeping_threads; | 		BAN::LinkedList<SleepingThread> m_sleeping_threads; | ||||||
|  | 		BAN::LinkedList<BlockingThread> m_blocking_threads; | ||||||
| 
 | 
 | ||||||
| 		BAN::LinkedList<ActiveThread>::iterator m_current_thread; | 		BAN::LinkedList<ActiveThread>::iterator m_current_thread; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <kernel/SpinLock.h> | ||||||
|  | 
 | ||||||
|  | namespace Kernel | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	class Semaphore | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		void block(); | ||||||
|  | 		void unblock(); | ||||||
|  | 		bool is_blocked() const { return m_blocked; } | ||||||
|  | 
 | ||||||
|  | 	private: | ||||||
|  | 		void set_blocked(bool blocked) { m_blocked = blocked; } | ||||||
|  | 
 | ||||||
|  | 	private: | ||||||
|  | 		bool m_blocked { false }; | ||||||
|  | 
 | ||||||
|  | 		friend class Scheduler; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -211,8 +211,9 @@ namespace Kernel::Input | ||||||
| 			m_event_queue.pop(); | 			m_event_queue.pop(); | ||||||
| 		} | 		} | ||||||
| 		m_event_queue.push(event); | 		m_event_queue.push(event); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
|  | 		m_semaphore.unblock(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	void PS2Keyboard::update_leds() | 	void PS2Keyboard::update_leds() | ||||||
| 	{ | 	{ | ||||||
|  | @ -231,14 +232,20 @@ namespace Kernel::Input | ||||||
| 		if (size < sizeof(KeyEvent)) | 		if (size < sizeof(KeyEvent)) | ||||||
| 			return BAN::Error::from_errno(ENOBUFS); | 			return BAN::Error::from_errno(ENOBUFS); | ||||||
| 
 | 
 | ||||||
| 		while (m_event_queue.empty()) | 		while (true) | ||||||
| 			PIT::sleep(1); | 		{ | ||||||
|  | 			if (m_event_queue.empty()) | ||||||
|  | 				m_semaphore.block(); | ||||||
| 
 | 
 | ||||||
| 			CriticalScope _; | 			CriticalScope _; | ||||||
|  | 			if (m_event_queue.empty()) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
| 			*(KeyEvent*)buffer = m_event_queue.front(); | 			*(KeyEvent*)buffer = m_event_queue.front(); | ||||||
| 			m_event_queue.pop(); | 			m_event_queue.pop(); | ||||||
| 
 | 
 | ||||||
| 			return sizeof(KeyEvent); | 			return sizeof(KeyEvent); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -211,4 +211,58 @@ namespace Kernel | ||||||
| 		ASSERT_NOT_REACHED(); | 		ASSERT_NOT_REACHED(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | #pragma GCC push_options | ||||||
|  | #pragma GCC optimize("O0") | ||||||
|  | 	void Scheduler::block_current_thread(Semaphore* semaphore) | ||||||
|  | 	{ | ||||||
|  | 		VERIFY_STI(); | ||||||
|  | 		DISABLE_INTERRUPTS(); | ||||||
|  | 
 | ||||||
|  | 		ASSERT(m_current_thread); | ||||||
|  | 
 | ||||||
|  | 		auto blocking = m_current_thread->thread; | ||||||
|  | 
 | ||||||
|  | 		if (save_current_thread()) | ||||||
|  | 		{ | ||||||
|  | 			ENABLE_INTERRUPTS(); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		remove_and_advance_current_thread(); | ||||||
|  | 
 | ||||||
|  | 		// This should work as we released enough memory from active thread
 | ||||||
|  | 		static_assert(sizeof(ActiveThread) == sizeof(BlockingThread)); | ||||||
|  | 		MUST(m_blocking_threads.emplace_back(blocking, semaphore)); | ||||||
|  | 		blocking.clear(); | ||||||
|  | 
 | ||||||
|  | 		semaphore->m_blocked = true; | ||||||
|  | 
 | ||||||
|  | 		execute_current_thread(); | ||||||
|  | 		ASSERT_NOT_REACHED(); | ||||||
|  | 	} | ||||||
|  | #pragma GCC pop_options | ||||||
|  | 	 | ||||||
|  | 	void Scheduler::unblock_threads(Semaphore* semaphore) | ||||||
|  | 	{ | ||||||
|  | 		Kernel::CriticalScope critical; | ||||||
|  | 
 | ||||||
|  | 		for (auto it = m_blocking_threads.begin(); it != m_blocking_threads.end();) | ||||||
|  | 		{ | ||||||
|  | 			if (it->semaphore == semaphore) | ||||||
|  | 			{ | ||||||
|  | 				auto thread = it->thread; | ||||||
|  | 				it = m_blocking_threads.remove(it); | ||||||
|  | 
 | ||||||
|  | 				// This should work as we released enough memory from active thread
 | ||||||
|  | 				static_assert(sizeof(ActiveThread) == sizeof(BlockingThread)); | ||||||
|  | 				MUST(m_active_threads.emplace_back(thread)); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				it++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		semaphore->m_blocked = false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | #include <kernel/LockGuard.h> | ||||||
|  | #include <kernel/Scheduler.h> | ||||||
|  | #include <kernel/Semaphore.h> | ||||||
|  | 
 | ||||||
|  | namespace Kernel | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	void Semaphore::block() | ||||||
|  | 	{ | ||||||
|  | 		Scheduler::get().block_current_thread(this); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Semaphore::unblock() | ||||||
|  | 	{ | ||||||
|  | 		if (!m_blocked) | ||||||
|  | 			return; | ||||||
|  | 		Scheduler::get().unblock_threads(this); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue