mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-19 01:25:05 -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,
|
BLOCKED = 4,
|
||||||
SLEEPING= 5,
|
SLEEPING= 5,
|
||||||
WAITING = 6,
|
WAITING = 6,
|
||||||
KILLED = 7
|
KILLED = 7,
|
||||||
|
BLOCKED_TIMEOUT = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
struct segment_t {
|
struct segment_t {
|
||||||
|
@ -19,6 +19,8 @@ namespace scheduler {
|
|||||||
|
|
||||||
constexpr const size_t MAX_PROCESS = 128;
|
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();
|
pid_t get_pid();
|
||||||
scheduler::process_t& get_process(pid_t pid);
|
scheduler::process_t& get_process(pid_t pid);
|
||||||
scheduler::process_state get_process_state(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 set_working_directory(const path& directory);
|
||||||
|
|
||||||
void block_process_light(pid_t pid);
|
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(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);
|
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 "scheduler.hpp"
|
||||||
#include "logging.hpp"
|
#include "logging.hpp"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief A simple sleep queue
|
||||||
|
*/
|
||||||
struct sleep_queue {
|
struct sleep_queue {
|
||||||
private:
|
private:
|
||||||
mutable spinlock lock;
|
mutable spinlock lock;
|
||||||
circular_buffer<scheduler::pid_t, 16> queue;
|
circular_buffer<scheduler::pid_t, 16> queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/*!
|
||||||
|
* \brief Test if the sleep queue is empty
|
||||||
|
*/
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
std::lock_guard<spinlock> l(lock);
|
std::lock_guard<spinlock> l(lock);
|
||||||
|
|
||||||
return queue.empty();
|
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 {
|
scheduler::pid_t top_process() const {
|
||||||
std::lock_guard<spinlock> l(lock);
|
std::lock_guard<spinlock> l(lock);
|
||||||
|
|
||||||
return queue.top();
|
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(){
|
scheduler::pid_t wake_up(){
|
||||||
std::lock_guard<spinlock> l(lock);
|
std::lock_guard<spinlock> l(lock);
|
||||||
|
|
||||||
@ -50,6 +66,9 @@ public:
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Wait inside the queue until woken up.
|
||||||
|
*/
|
||||||
void sleep(){
|
void sleep(){
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
|
||||||
@ -68,6 +87,52 @@ public:
|
|||||||
|
|
||||||
scheduler::reschedule();
|
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
|
#endif
|
||||||
|
@ -762,7 +762,7 @@ void scheduler::tick(){
|
|||||||
|
|
||||||
// Update sleep timeouts
|
// Update sleep timeouts
|
||||||
for(auto& process : pcb){
|
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;
|
--process.sleep_timeout;
|
||||||
|
|
||||||
if(process.sleep_timeout == 0){
|
if(process.sleep_timeout == 0){
|
||||||
@ -836,6 +836,21 @@ void scheduler::block_process_light(pid_t pid){
|
|||||||
pcb[pid].state = process_state::BLOCKED;
|
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){
|
void scheduler::block_process(pid_t pid){
|
||||||
thor_assert(is_started(), "The scheduler is not started");
|
thor_assert(is_started(), "The scheduler is not started");
|
||||||
thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds");
|
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 < scheduler::MAX_PROCESS, "pid out of bounds");
|
||||||
thor_assert(pid != idle_pid, "No reason to unblock the idle task");
|
thor_assert(pid != idle_pid, "No reason to unblock the idle task");
|
||||||
thor_assert(is_started(), "The scheduler is not started");
|
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;
|
pcb[pid].state = process_state::READY;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user