pub fn scheduler(&mut self) {
		// Someone wants to give up the CPU
		// => we have time to cleanup the system
		self.cleanup_tasks();

		// Get information about the current task.
		let (id, last_stack_pointer, kernel_stack_pointer, user_stack_pointer, prio, status) = {
			let mut borrowed = self.current_task.borrow_mut();
			(
				borrowed.id,
				&mut borrowed.last_stack_pointer as *mut usize,
				&mut borrowed.kernel_stack_pointer as *mut usize,
				&mut borrowed.user_stack_pointer as *mut usize,
				borrowed.prio,
				borrowed.status,
			)
		};

		// Lock the scheduler state while we change it.
		let mut state_locked = self.state.lock();
		state_locked.is_halted = false;

		let mut new_task = None;

		if status == TaskStatus::TaskRunning {
			// A task is currently running.
			// Check if a task with a higher priority is available.
			let higher_prio = Priority::from(prio.into() + 1);
			if let Some(task) = state_locked.ready_queue.pop_with_prio(higher_prio) {
				// This higher priority task becomes the new task.
				debug!("Task with a higher priority is available.");
				new_task = Some(task);
			} else {
				// No task with a higher priority is available, but a task with the same priority as ours may be available.
				// We implement Round-Robin Scheduling for this case.
				// Check if our current task has been running for at least the task time slice.
				if arch::processor::get_timer_ticks() > self.last_task_switch_tick + TASK_TIME_SLICE
				{
					// Check if a task with our own priority is available.
					if let Some(task) = state_locked.ready_queue.pop_with_prio(prio) {
						// This task becomes the new task.
						debug!("Time slice expired for current task.");
						new_task = Some(task);
					}
				}
			}
		} else {
			// No task is currently running.
			// Check if there is any available task and get the one with the highest priority.
			if let Some(task) = state_locked.ready_queue.pop() {
				// This available task becomes the new task.
				debug!("Task is available.");
				new_task = Some(task);
			} else if status != TaskStatus::TaskIdle {
				// The Idle task becomes the new task.
				debug!("Only Idle Task is available.");
				new_task = Some(self.idle_task.clone());
			}
		}

		if let Some(task) = new_task {
			// There is a new task we want to switch to.

			// Handle the current task.
			if status == TaskStatus::TaskRunning {
				// Mark the running task as ready again and add it back to the queue.
				self.current_task.borrow_mut().status = TaskStatus::TaskReady;
				state_locked.ready_queue.push(self.current_task.clone());
			} else if status == TaskStatus::TaskFinished {
				// Mark the finished task as invalid and add it to the finished tasks for a later cleanup.
				self.current_task.borrow_mut().status = TaskStatus::TaskInvalid;
				self.finished_tasks.push_back(id);
			}

			// Handle the new task and get information about it.
			let (new_id, new_stack_pointer, new_kernel_stack_pointer, new_user_stack_pointer) = 
			{
				let mut borrowed = task.borrow_mut();
				if borrowed.status != TaskStatus::TaskIdle {
					// Mark the new task as running.
					borrowed.status = TaskStatus::TaskRunning;
				}

				(borrowed.id, borrowed.last_stack_pointer, borrowed.kernel_stack_pointer, borrowed.user_stack_pointer)
			};

			if id != new_id {
				// Tell the scheduler about the new task.
				debug!(
					"Switching task from {} to {} (kernel stack {:#x} => {:#x}) (kernel sp {:#x} => {:#x}) (user sp {:#x} => {:#x})",
					id,
					new_id,
					unsafe { *last_stack_pointer},
					new_stack_pointer,
					unsafe { *kernel_stack_pointer },
					new_kernel_stack_pointer,
					unsafe { *user_stack_pointer },
					new_user_stack_pointer
				);
				self.current_task = task;
				self.last_task_switch_tick = arch::processor::get_timer_ticks();

				// Unlock the state and reenable interrupts.
				drop(state_locked);

				// Finally save our current context and restore the context of the new task.
				switch(last_stack_pointer, new_stack_pointer);
			}
		} else {
			// There is no new task to switch to.

			if status == TaskStatus::TaskIdle {
				// We are now running the Idle task and will halt the CPU.
				// Indicate that and unlock the state.
				state_locked.is_halted = true;
			}
		}
	}
/// Triggers the scheduler to reschedule the tasks
Triggers the scheduler to reschedule the tasks
Triggers the scheduler to reschedule the tasks
pub fn scheduler(&mut self) {
		// Someone wants to give up the CPU
		// => we have time to cleanup the system
		self.cleanup_tasks();
		// Get information about the current task.
		let (id, last_stack_pointer, kernel_stack_pointer, user_stack_pointer, prio, status) = {
			let mut borrowed = self.current_task.borrow_mut();
			(
				borrowed.id,
				&mut borrowed.last_stack_pointer as *mut usize,
				&mut borrowed.kernel_stack_pointer as *mut usize,
				&mut borrowed.user_stack_pointer as *mut usize,
				borrowed.prio,
				borrowed.status,
			)
		};
		// Lock the scheduler state while we change it.
		let mut state_locked = self.state.lock();
		state_locked.is_halted = false;
		let mut new_task = None;
		if status == TaskStatus::TaskRunning {
			// A task is currently running.
			// Check if a task with a higher priority is available.
			let higher_prio = Priority::from(prio.into() + 1);
			if let Some(task) = state_locked.ready_queue.pop_with_prio(higher_prio) {
				// This higher priority task becomes the new task.
				debug!("Task with a higher priority is available.");
				new_task = Some(task);
			} else {
				// No task with a higher priority is available, but a task with the same priority as ours may be available.
				// We implement Round-Robin Scheduling for this case.
				// Check if our current task has been running for at least the task time slice.
				if arch::processor::get_timer_ticks() > self.last_task_switch_tick + TASK_TIME_SLICE
				{
					// Check if a task with our own priority is available.
					if let Some(task) = state_locked.ready_queue.pop_with_prio(prio) {
						// This task becomes the new task.
						debug!("Time slice expired for current task.");
						new_task = Some(task);
					}
				}
			}
		} else {
			// No task is currently running.
			// Check if there is any available task and get the one with the highest priority.
			if let Some(task) = state_locked.ready_queue.pop() {
				// This available task becomes the new task.
				debug!("Task is available.");
				new_task = Some(task);
			} else if status != TaskStatus::TaskIdle {
				// The Idle task becomes the new task.
				debug!("Only Idle Task is available.");
				new_task = Some(self.idle_task.clone());
			}
		}
		if let Some(task) = new_task {
			// There is a new task we want to switch to.
			// Handle the current task.
			if status == TaskStatus::TaskRunning {
				// Mark the running task as ready again and add it back to the queue.
				self.current_task.borrow_mut().status = TaskStatus::TaskReady;
				state_locked.ready_queue.push(self.current_task.clone());
			} else if status == TaskStatus::TaskFinished {
				// Mark the finished task as invalid and add it to the finished tasks for a later cleanup.
				self.current_task.borrow_mut().status = TaskStatus::TaskInvalid;
				self.finished_tasks.push_back(id);
			}
			// Handle the new task and get information about it.
			let (new_id, new_stack_pointer, new_kernel_stack_pointer, new_user_stack_pointer) = 
			{
				let mut borrowed = task.borrow_mut();
				if borrowed.status != TaskStatus::TaskIdle {
					// Mark the new task as running.
					borrowed.status = TaskStatus::TaskRunning;
				}
				(borrowed.id, borrowed.last_stack_pointer, borrowed.kernel_stack_pointer, borrowed.user_stack_pointer)
			};
			if id != new_id {
				// Tell the scheduler about the new task.
				debug!(
					"Switching task from {} to {} (kernel stack {:#x} => {:#x}) (kernel sp {:#x} => {:#x}) (user sp {:#x} => {:#x})",
					id,
					new_id,
					unsafe { *last_stack_pointer},
					new_stack_pointer,
					unsafe { *kernel_stack_pointer },
					new_kernel_stack_pointer,
					unsafe { *user_stack_pointer },
					new_user_stack_pointer
				);
				self.current_task = task;
				self.last_task_switch_tick = arch::processor::get_timer_ticks();
				// Unlock the state and reenable interrupts.
				drop(state_locked);
				// Finally save our current context and restore the context of the new task.
				switch(last_stack_pointer, new_stack_pointer);
			}
		} else {
			// There is no new task to switch to.
			if status == TaskStatus::TaskIdle {
				// We are now running the Idle task and will halt the CPU.
				// Indicate that and unlock the state.
				state_locked.is_halted = true;
			}
		}
	}
pub fn scheduler ( & mut self ) { // Someone wants to give up the CPU // => we have time to cleanup the system self . cleanup_tasks ( ) ; // Get information about the current task. let ( id , last_stack_pointer , kernel_stack_pointer , user_stack_pointer , prio , status ) = { let mut borrowed = self . current_task . borrow_mut ( ) ; ( borrowed . id , & mut borrowed . last_stack_pointer as * mut usize , & mut borrowed . kernel_stack_pointer as * mut usize , & mut borrowed . user_stack_pointer as * mut usize , borrowed . prio , borrowed . status , ) } ; // Lock the scheduler state while we change it. let mut state_locked = self . state . lock ( ) ; state_locked . is_halted = false ; let mut new_task = None ; if status == TaskStatus :: TaskRunning { // A task is currently running. // Check if a task with a higher priority is available. let higher_prio = Priority :: from ( prio . into ( ) + 1 ) ; if let Some ( task ) = state_locked . ready_queue . pop_with_prio ( higher_prio ) { // This higher priority task becomes the new task. debug ! ( " " ) ; new_task = Some ( task ) ; } else { // No task with a higher priority is available, but a task with the same priority as ours may be available. // We implement Round-Robin Scheduling for this case. // Check if our current task has been running for at least the task time slice. if arch :: processor :: get_timer_ticks ( ) > self . last_task_switch_tick + TASK_TIME_SLICE { // Check if a task with our own priority is available. if let Some ( task ) = state_locked . ready_queue . pop_with_prio ( prio ) { // This task becomes the new task. debug ! ( " " ) ; new_task = Some ( task ) ; } } } } else { // No task is currently running. // Check if there is any available task and get the one with the highest priority. if let Some ( task ) = state_locked . ready_queue . pop ( ) { // This available task becomes the new task. debug ! ( " " ) ; new_task = Some ( task ) ; } else if status != TaskStatus :: TaskIdle { // The Idle task becomes the new task. debug ! ( " " ) ; new_task = Some ( self . idle_task . clone ( ) ) ; } } if let Some ( task ) = new_task { // There is a new task we want to switch to. // Handle the current task. if status == TaskStatus :: TaskRunning { // Mark the running task as ready again and add it back to the queue. self . current_task . borrow_mut ( ) . status = TaskStatus :: TaskReady ; state_locked . ready_queue . push ( self . current_task . clone ( ) ) ; } else if status == TaskStatus :: TaskFinished { // Mark the finished task as invalid and add it to the finished tasks for a later cleanup. self . current_task . borrow_mut ( ) . status = TaskStatus :: TaskInvalid ; self . finished_tasks . push_back ( id ) ; } // Handle the new task and get information about it. let ( new_id , new_stack_pointer , new_kernel_stack_pointer , new_user_stack_pointer ) = { let mut borrowed = task . borrow_mut ( ) ; if borrowed . status != TaskStatus :: TaskIdle { // Mark the new task as running. borrowed . status = TaskStatus :: TaskRunning ; } ( borrowed . id , borrowed . last_stack_pointer , borrowed . kernel_stack_pointer , borrowed . user_stack_pointer ) } ; if id != new_id { // Tell the scheduler about the new task. debug ! ( " " id new_id unsafe { last_stack_pointer } new_stack_pointer unsafe { kernel_stack_pointer } new_kernel_stack_pointer unsafe { user_stack_pointer } new_user_stack_pointer ) ; self . current_task = task ; self . last_task_switch_tick = arch :: processor :: get_timer_ticks ( ) ; // Unlock the state and reenable interrupts. drop ( state_locked ) ; // Finally save our current context and restore the context of the new task. switch ( last_stack_pointer , new_stack_pointer ) ; } } else { // There is no new task to switch to. if status == TaskStatus :: TaskIdle { // We are now running the Idle task and will halt the CPU. // Indicate that and unlock the state. state_locked . is_halted = true ; } } }
Triggers the scheduler to reschedule the tasks
Triggers the scheduler to reschedule the tasks
&mut self
&mut self