mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-18 09:04:49 -04:00
Prepare block with timeout
This commit is contained in:
parent
77ee414974
commit
f6bc4b0ad8
@ -33,7 +33,8 @@ enum class process_state : char {
|
||||
BLOCKED = 4,
|
||||
SLEEPING= 5,
|
||||
WAITING = 6,
|
||||
KILLED = 7
|
||||
KILLED = 7,
|
||||
BLOCKED_TIMEOUT = 7
|
||||
};
|
||||
|
||||
struct segment_t {
|
||||
|
@ -19,6 +19,8 @@ namespace scheduler {
|
||||
|
||||
constexpr const size_t MAX_PROCESS = 128;
|
||||
|
||||
constexpr const pid_t INVALID_PID = 1024 * 1024 * 1024; //I'm pretty sure we won't violate this limit
|
||||
|
||||
pid_t get_pid();
|
||||
scheduler::process_t& get_process(pid_t pid);
|
||||
scheduler::process_state get_process_state(pid_t pid);
|
||||
@ -56,7 +58,7 @@ const path& get_working_directory();
|
||||
void set_working_directory(const path& directory);
|
||||
|
||||
void block_process_light(pid_t pid);
|
||||
//TODO Maybe do that for unblock as well!
|
||||
void block_process_timeout_light(pid_t pid, size_t ms);
|
||||
|
||||
process_t& create_kernel_task(const char* name, char* user_stack, char* kernel_stack, void (*fun)());
|
||||
process_t& create_kernel_task_args(const char* name, char* user_stack, char* kernel_stack, void (*fun)(void*), void* data);
|
||||
|
@ -15,24 +15,40 @@
|
||||
#include "scheduler.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
/*!
|
||||
* \brief A simple sleep queue
|
||||
*/
|
||||
struct sleep_queue {
|
||||
private:
|
||||
mutable spinlock lock;
|
||||
circular_buffer<scheduler::pid_t, 16> queue;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Test if the sleep queue is empty
|
||||
*/
|
||||
bool empty() const {
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
|
||||
return queue.empty();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the top process in the queue.
|
||||
*
|
||||
* If the queue is empty, the behaviour is undefined.
|
||||
*/
|
||||
scheduler::pid_t top_process() const {
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
|
||||
return queue.top();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Wake up the first process from the queue.
|
||||
*
|
||||
* If the queue is empty, the behaviour is undefined.
|
||||
*/
|
||||
scheduler::pid_t wake_up(){
|
||||
std::lock_guard<spinlock> l(lock);
|
||||
|
||||
@ -50,6 +66,9 @@ public:
|
||||
return pid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Wait inside the queue until woken up.
|
||||
*/
|
||||
void sleep(){
|
||||
lock.acquire();
|
||||
|
||||
@ -68,6 +87,52 @@ public:
|
||||
|
||||
scheduler::reschedule();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Wait inside the queue until woken up or until the
|
||||
* timeout is passed.
|
||||
*
|
||||
* \return true if the thread was woken up, false if the timeout is passed
|
||||
*/
|
||||
bool sleep(size_t ms){
|
||||
if(!ms){
|
||||
return false;
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
|
||||
//Get the current process information
|
||||
auto pid = scheduler::get_pid();
|
||||
|
||||
logging::logf(logging::log_level::TRACE, "sleep_queue: %u wait with timeout %u\n", pid, ms);
|
||||
|
||||
//Enqueue the process in the sleep queue
|
||||
queue.push(pid);
|
||||
|
||||
//This process will sleep
|
||||
scheduler::block_process_timeout_light(pid, ms);
|
||||
|
||||
lock.release();
|
||||
|
||||
scheduler::reschedule();
|
||||
|
||||
// At this point we need the lock again to check the queue
|
||||
lock.acquire();
|
||||
|
||||
bool obtained = true;
|
||||
|
||||
// If the queue still contains our pid, it means a wake up
|
||||
// from timeout
|
||||
if(queue.contains(pid)){
|
||||
obtained = false;
|
||||
queue.replace(pid, scheduler::INVALID_PID);
|
||||
}
|
||||
|
||||
// Final release of the lock
|
||||
lock.release();
|
||||
|
||||
return obtained;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -762,7 +762,7 @@ void scheduler::tick(){
|
||||
|
||||
// Update sleep timeouts
|
||||
for(auto& process : pcb){
|
||||
if(process.state == process_state::SLEEPING){
|
||||
if(process.state == process_state::SLEEPING || process.state == process_state::BLOCKED_TIMEOUT){
|
||||
--process.sleep_timeout;
|
||||
|
||||
if(process.sleep_timeout == 0){
|
||||
@ -836,6 +836,21 @@ void scheduler::block_process_light(pid_t pid){
|
||||
pcb[pid].state = process_state::BLOCKED;
|
||||
}
|
||||
|
||||
void scheduler::block_process_timeout_light(pid_t pid, size_t ms){
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
|
||||
logging::logf(logging::log_level::DEBUG, "scheduler: Block process (light) %u with timeout %u\n", pid, ms);
|
||||
|
||||
pcb[pid].state = process_state::BLOCKED_TIMEOUT;
|
||||
|
||||
// Compute the amount of ticks to sleep
|
||||
auto sleep_ticks = ms * (timer::timer_frequency() / 1000);
|
||||
sleep_ticks = !sleep_ticks ? 1 : sleep_ticks;
|
||||
|
||||
// Put the process to sleep
|
||||
pcb[pid].sleep_timeout = sleep_ticks;
|
||||
}
|
||||
|
||||
void scheduler::block_process(pid_t pid){
|
||||
thor_assert(is_started(), "The scheduler is not started");
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
@ -854,7 +869,7 @@ void scheduler::unblock_process(pid_t pid){
|
||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||
thor_assert(pid != idle_pid, "No reason to unblock the idle task");
|
||||
thor_assert(is_started(), "The scheduler is not started");
|
||||
thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::WAITING, "Can only unblock BLOCKED/WAITING processes");
|
||||
thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::BLOCKED_TIMEOUT || pcb[pid].state == process_state::WAITING, "Can only unblock BLOCKED/WAITING processes");
|
||||
|
||||
pcb[pid].state = process_state::READY;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user