Xyris  0.5
tasks.cpp File Reference
#include <Arch/Arch.hpp>
#include <Arch/Memory.hpp>
#include <Scheduler/tasks.hpp>
#include <Panic.hpp>
#include <Memory/heap.hpp>
#include <Library/stdio.hpp>
#include <Devices/Serial/rs232.hpp>
#include <stdint.h>
#include <x86gprintrin.h>
#include <Arch/i686/timer.hpp>
#include <Logger.hpp>
+ Include dependency graph for tasks.cpp:

Go to the source code of this file.

Macros

#define NAMED_TASKLIST(name)
 
#define TASK_ACTION(action, task)
 

Functions

void _tasks_enqueue_ready (struct task *task)
 
void tasks_update_time ()
 
void _wakeup (struct task *task)
 
 NAMED_TASKLIST (sleeping)
 
 NAMED_TASKLIST (stopped)
 
void tasks_init ()
 
struct tasktasks_new (void(*entry)(void), struct task *storage, task_state state, const char *name)
 
void tasks_schedule ()
 
uint64_t tasks_get_self_time ()
 
void tasks_block_current (task_state reason)
 
void tasks_unblock (struct task *task)
 
void tasks_nano_sleep_until (uint64_t time)
 
void tasks_nano_sleep (uint64_t time)
 
void tasks_exit ()
 
void tasks_sync_block (struct task_sync *ts)
 
void tasks_sync_unblock (struct task_sync *ts)
 

Variables

struct taskcurrent_task = NULL
 
struct tasklist tasks_ready = { }
 

Detailed Description

Author
Micah Switzer (mswit.nosp@m.zer@.nosp@m.cedar.nosp@m.vill.nosp@m.e.edu)
Version
0.3
Date
2020-08-29

Definition in file tasks.cpp.

Macro Definition Documentation

◆ NAMED_TASKLIST

#define NAMED_TASKLIST (   name)
Value:
struct tasklist tasks_##name = { /* Zero */ }; \
static inline void _enqueue_##name(struct task *task) { \
_enqueue_task(&tasks_##name, task); } \
static inline struct task *_dequeue_##name() { \
return _dequeue_task(&tasks_##name); }

Definition at line 33 of file tasks.cpp.

◆ TASK_ACTION

#define TASK_ACTION (   action,
  task 
)

Definition at line 124 of file tasks.cpp.

Function Documentation

◆ _tasks_enqueue_ready()

void _tasks_enqueue_ready ( struct task task)

Definition at line 279 of file tasks.cpp.

280 {
281  _enqueue_task(&tasks_ready, task);
282 }
+ Here is the caller graph for this function:

◆ _wakeup()

void _wakeup ( struct task task)

Definition at line 440 of file tasks.cpp.

441 {
442  task->state = TASK_READY;
443  task->wakeup_time = (0ULL - 1);
445  TASK_ACTION(__func__, task);
446 }
+ Here is the call graph for this function:

◆ NAMED_TASKLIST() [1/2]

NAMED_TASKLIST ( sleeping  )

◆ NAMED_TASKLIST() [2/2]

NAMED_TASKLIST ( stopped  )

◆ tasks_block_current()

void tasks_block_current ( task_state  reason)

Blocks the current task.

Parameters
reason

Definition at line 422 of file tasks.cpp.

423 {
424  _aquire_scheduler_lock();
425  current_task->state = reason;
426  TASK_ACTION(__func__, current_task);
427  _schedule();
428  _release_scheduler_lock();
429 }

◆ tasks_exit()

void tasks_exit ( void  )

Exits the current task.

Definition at line 511 of file tasks.cpp.

512 {
513  // userspace cleanup can happen here
514  Logger::Debug(__func__, "task \"%s\" (0x%08lx) exiting", current_task->name, (uint32_t)current_task);
515 
516  _aquire_scheduler_lock();
517  // all scheduling-specific operations must happen here
518  _enqueue_stopped(current_task);
519 
520  // the ordering of these two should really be reversed
521  // but the scheduler currently isn't very smart
523 
524  tasks_unblock(&_cleaner_task);
525 
526  _release_scheduler_lock();
527 }
+ Here is the call graph for this function:

◆ tasks_get_self_time()

uint64_t tasks_get_self_time ( )

Returns the lifetime of the current task (in nanoseconds).

Returns
uint64_t Task lifetime (in nanoseconds)

Definition at line 416 of file tasks.cpp.

417 {
419  return current_task->time_used;
420 }
+ Here is the call graph for this function:

◆ tasks_init()

void tasks_init ( )

Initializes the kernel task manager.

Definition at line 151 of file tasks.cpp.

152 {
153  // get a pointer to the first task's tcb
154  struct task *this_task = &_first_task;
155  // discover the CPU speed for accurate scheduling
156  _discover_cpu_speed();
157  *this_task = {
158  // this will be filled in when we switch to another task for the first time
159  .stack_top = 0,
160  // this will be the same for kernel tasks
161  .page_dir = Memory::getPageDirPhysAddr(),
162  // this is a linked list with only this task
163  .next = NULL,
164  // this task is currently running
165  .state = TASK_RUNNING,
166  // just say that this task hasn't spent any time running yet
167  .time_used = 0,
168  // Set wakeup time to 0 to make compiler happy
169  .wakeup_time = 0,
170  // name
171  .name = "[main]",
172  // this is not backed by dynamic memory
173  .alloc = ALLOC_STATIC,
174  };
175  TASK_ACTION(__func__, this_task);
176  // create a task for the cleaner and set it's state to "paused"
177  (void) tasks_new(_cleaner_task_impl, &_cleaner_task, TASK_PAUSED, "[cleaner]");
178  _cleaner_task.state = TASK_PAUSED;
179  // update the timer variables
180  _last_time = _get_cpu_time_ns();
181  _last_timer_time = _last_time;
182  // enable time slices
183  _time_slice_remaining = TIME_SLICE_SIZE;
184  // this is the current task
185  current_task = this_task;
186  timer_register_callback(_on_timer);
187 }

◆ tasks_nano_sleep()

void tasks_nano_sleep ( uint64_t  time)

Sleep for a given period of time (in nanoseconds).

Parameters
timeNanoseconds to sleep

Definition at line 506 of file tasks.cpp.

507 {
508  tasks_nano_sleep_until(_get_cpu_time_ns() + time);
509 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tasks_nano_sleep_until()

void tasks_nano_sleep_until ( uint64_t  time)

Sleeps until the provided absolute time (in nanoseconds).

Parameters
timeAbsolute time to sleep until (in nanoseconds since boot)

Definition at line 494 of file tasks.cpp.

495 {
496  // TODO: maybe validate that this time is in the future?
497  _aquire_scheduler_lock();
499  current_task->wakeup_time = time;
500  _enqueue_sleeping(current_task);
501  TASK_ACTION(__func__, current_task);
502  _schedule();
503  _release_scheduler_lock();
504 }
+ Here is the caller graph for this function:

◆ tasks_new()

struct task* tasks_new ( void(*)(void)  entry,
struct task storage,
task_state  state,
const char *  name 
)

Creates a new kernel task with a provided entry point, register storage struct, and task state struct. If the storage parameter is provided, the struct task struct provided will be written to. If NULL is passed as the storage parameter, a pointer to a allocated task will be returned.

Parameters
entryTask function entry point
storageTask stack structure (if NULL, a pointer to the task is returned)
stateTask state structure
nameTask name (for debugging / printing)
Returns
struct task* Pointer to the created kernel task

Definition at line 289 of file tasks.cpp.

290 {
291  struct task *new_task = storage;
292  if (storage == NULL) {
293  // allocate memory for our task structure
294  new_task = (struct task*)malloc(sizeof(struct task));
295  // panic if the alloc fails (we have no fallback)
296  if (new_task == NULL) {
297  panic("Unable to allocate memory for new task struct.");
298  }
299  }
300  // allocate a page for this stack (we might change this later)
301  // TODO: Should more than one page be allocated / freed?
302  uint8_t *stack = (uint8_t *)Memory::newPage(1);
303  if (stack == NULL) {
304  panic("Unable to allocate memory for new task stack.");
305  }
306  // remember, the stack grows up
307  void *stack_pointer = stack + ARCH_PAGE_SIZE;
308  // a null stack frame to make the panic screen happy
309  _stack_push_word(&stack_pointer, 0);
310  // the last thing to happen is the task stopping function
311  _stack_push_word(&stack_pointer, (size_t)_task_stopping);
312  // next entry is the main function to call (the start of the task)
313  _stack_push_word(&stack_pointer, (size_t)entry);
314  // when this task is started, the CPU will pop off this value which will become the new EIP
315  // we push this function to allow some setup code to be run from within the context of the new task
316  _stack_push_word(&stack_pointer, (size_t)_task_starting);
317  // our task switching code is going to pop four values off of the stack before returning
318  _stack_push_word(&stack_pointer, 0);
319  _stack_push_word(&stack_pointer, 0);
320  _stack_push_word(&stack_pointer, 0);
321  _stack_push_word(&stack_pointer, 0);
322  new_task->stack_top = (uintptr_t)stack_pointer;
323  new_task->page_dir = Memory::getPageDirPhysAddr();
324  new_task->next = NULL;
325  new_task->state = state;
326  new_task->time_used = 0;
327  new_task->name = name;
328  new_task->alloc = storage == NULL ? ALLOC_DYNAMIC : ALLOC_STATIC;
329  if (state == TASK_READY) {
330  _tasks_enqueue_ready(new_task);
331  }
332  TASK_ACTION(__func__, new_task);
333  return new_task;
334 }
+ Here is the call graph for this function:

◆ tasks_schedule()

void tasks_schedule ( )

Tell the kernel task scheduler to schedule all of the added tasks.

Definition at line 406 of file tasks.cpp.

407 {
408  // we must lock on all scheduling operations
409  _aquire_scheduler_lock();
410  // run the scheduler
411  _schedule();
412  // this will run when we switch back to the calling task
413  _release_scheduler_lock();
414 }

◆ tasks_sync_block()

void tasks_sync_block ( struct task_sync ts)

Definition at line 560 of file tasks.cpp.

561 {
562  _aquire_scheduler_lock();
563 #ifdef DEBUG
564  if (ts->dbg_name != NULL) {
565  Logger::Debug(__func__, "blocking %s", ts->dbg_name);
566  }
567 #endif
568  // push the current task to the waiting queue
569  _enqueue_task(&ts->waiting, current_task);
570  // now block until the mutex is freed
572  _release_scheduler_lock();
573 }
+ Here is the caller graph for this function:

◆ tasks_sync_unblock()

void tasks_sync_unblock ( struct task_sync ts)

Definition at line 575 of file tasks.cpp.

576 {
577  _aquire_scheduler_lock();
578 #ifdef DEBUG
579  if (ts->dbg_name != NULL) {
580  Logger::Debug(__func__, "unblocking %s", ts->dbg_name);
581  }
582 #endif
583  // iterate all tasks that were blocked and unblock them
584  struct task *task = ts->waiting.head;
585  struct task *next = NULL;
586  if (task == NULL) {
587  // no other tasks were blocked
588  goto exit;
589  }
590  do {
591  next = task->next;
592  _wakeup(task);
593  task->next = NULL;
594  task = next;
595  } while (task != NULL);
596  ts->waiting.head = NULL;
597  ts->waiting.tail = NULL;
598  // we woke up some tasks
599  _schedule();
600 exit:
601  _release_scheduler_lock();
602 }
+ Here is the caller graph for this function:

◆ tasks_unblock()

void tasks_unblock ( struct task task)

Unblocks the current task.

Parameters
task

Definition at line 431 of file tasks.cpp.

432 {
433  _aquire_scheduler_lock();
434  task->state = TASK_READY;
435  TASK_ACTION(__func__, task);
437  _release_scheduler_lock();
438 }

◆ tasks_update_time()

void tasks_update_time ( )

Definition at line 336 of file tasks.cpp.

337 {
338  uint64_t current_time = _get_cpu_time_ns();
339  uint64_t delta = current_time - _last_time;
340  if (current_task == NULL) {
341  _idle_time += delta;
342  } else {
343  current_task->time_used += delta;
344  }
345  _last_time = current_time;
346 }
+ Here is the caller graph for this function:

Variable Documentation

◆ current_task

struct task* current_task = NULL

Definition at line 40 of file tasks.cpp.

◆ tasks_ready

struct tasklist tasks_ready = { }

Definition at line 44 of file tasks.cpp.

ALLOC_STATIC
@ ALLOC_STATIC
Definition: tasks.hpp:30
tasks_update_time
void tasks_update_time()
Definition: tasks.cpp:336
task
Definition: tasks.hpp:32
tasklist
Definition: tasks.hpp:48
TASK_READY
@ TASK_READY
Definition: tasks.hpp:22
TASK_SLEEPING
@ TASK_SLEEPING
Definition: tasks.hpp:23
tasks_unblock
void tasks_unblock(struct task *task)
Unblocks the current task.
Definition: tasks.cpp:431
task::time_used
uint64_t time_used
Definition: tasks.hpp:38
timer_register_callback
void timer_register_callback(void(*func)())
Definition: timer.cpp:61
task::alloc
task_alloc alloc
Definition: tasks.hpp:41
ALLOC_DYNAMIC
@ ALLOC_DYNAMIC
Definition: tasks.hpp:30
TASK_ACTION
#define TASK_ACTION(action, task)
Definition: tasks.cpp:124
_tasks_enqueue_ready
void _tasks_enqueue_ready(struct task *task)
Definition: tasks.cpp:279
TIME_SLICE_SIZE
#define TIME_SLICE_SIZE
Definition: tasks.hpp:17
task_sync::dbg_name
const char * dbg_name
Definition: tasks.hpp:58
tasks_new
struct task * tasks_new(void(*entry)(void), struct task *storage, task_state state, const char *name)
Creates a new kernel task with a provided entry point, register storage struct, and task state struct...
Definition: tasks.cpp:289
TASK_RUNNING
@ TASK_RUNNING
Definition: tasks.hpp:21
Memory::getPageDirPhysAddr
uintptr_t getPageDirPhysAddr()
Gets the physical address of the current page directory.
Definition: paging.cpp:272
tasks_ready
struct tasklist tasks_ready
Definition: tasks.cpp:44
TASK_STOPPED
@ TASK_STOPPED
Definition: tasks.hpp:25
task::stack_top
uintptr_t stack_top
Definition: tasks.hpp:34
task_sync::waiting
struct tasklist waiting
Definition: tasks.hpp:59
Memory::newPage
void * newPage(size_t size)
Returns a new page in memory for use. If less than one page is requested, exactly one page will be al...
Definition: paging.cpp:228
TASK_PAUSED
@ TASK_PAUSED
Definition: tasks.hpp:26
tasklist::head
struct task * head
Definition: tasks.hpp:50
task::state
task_state state
Definition: tasks.hpp:37
task::wakeup_time
uint64_t wakeup_time
Definition: tasks.hpp:39
Logger::Debug
static void Debug(const char *tag, const char *fmt,...)
Definition: Logger.cpp:71
task::name
const char * name
Definition: tasks.hpp:40
task::page_dir
uintptr_t page_dir
Definition: tasks.hpp:35
malloc
void * malloc(size_t)
panic
void panic(const char *msg)
Halt the system and print the provided message on the panic screen.
Definition: Panic.cpp:82
tasks_nano_sleep_until
void tasks_nano_sleep_until(uint64_t time)
Sleeps until the provided absolute time (in nanoseconds).
Definition: tasks.cpp:494
_wakeup
void _wakeup(struct task *task)
Definition: tasks.cpp:440
ARCH_PAGE_SIZE
#define ARCH_PAGE_SIZE
Definition: Memory.i686.hpp:21
current_task
struct task * current_task
Definition: tasks.cpp:40
task::next
struct task * next
Definition: tasks.hpp:36
TASK_BLOCKED
@ TASK_BLOCKED
Definition: tasks.hpp:24
tasks_block_current
void tasks_block_current(task_state reason)
Blocks the current task.
Definition: tasks.cpp:422
tasklist::tail
struct task * tail
Definition: tasks.hpp:51