Prepare block with timeout

This commit is contained in:
Baptiste Wicht 2016-08-18 18:24:25 +02:00
parent 77ee414974
commit f6bc4b0ad8
4 changed files with 87 additions and 4 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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

View File

@ -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;
}