Xyris  0.5
tasks.hpp File Reference
#include <stdint.h>
#include <Arch/Arch.hpp>
#include <Memory/paging.hpp>
+ Include dependency graph for tasks.hpp:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  task
 
struct  tasklist
 
struct  task_sync
 

Macros

#define TIME_SLICE_SIZE   (1 * 1000 * 1000ULL)
 
#define TASK_ONLY   if (current_task != NULL)
 
#define MAX_TASKS_QUEUED   8
 

Enumerations

enum  task_state {
  TASK_RUNNING = 0, TASK_READY = 1, TASK_SLEEPING, TASK_BLOCKED,
  TASK_STOPPED, TASK_PAUSED, TASK_STATE_COUNT
}
 
enum  task_alloc { ALLOC_STATIC, ALLOC_DYNAMIC }
 

Functions

void tasks_init ()
 
void tasks_switch_to (struct task *task)
 
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)
 
void tasks_sync_block (struct task_sync *tsc)
 
void tasks_sync_unblock (struct task_sync *tsc)
 

Variables

struct taskcurrent_task
 

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.hpp.

Macro Definition Documentation

◆ MAX_TASKS_QUEUED

#define MAX_TASKS_QUEUED   8

Definition at line 54 of file tasks.hpp.

◆ TASK_ONLY

#define TASK_ONLY   if (current_task != NULL)

Definition at line 46 of file tasks.hpp.

◆ TIME_SLICE_SIZE

#define TIME_SLICE_SIZE   (1 * 1000 * 1000ULL)

Definition at line 17 of file tasks.hpp.

Enumeration Type Documentation

◆ task_alloc

enum task_alloc
Enumerator
ALLOC_STATIC 
ALLOC_DYNAMIC 

Definition at line 30 of file tasks.hpp.

◆ task_state

enum task_state
Enumerator
TASK_RUNNING 
TASK_READY 
TASK_SLEEPING 
TASK_BLOCKED 
TASK_STOPPED 
TASK_PAUSED 
TASK_STATE_COUNT 

Definition at line 19 of file tasks.hpp.

20 {
21  TASK_RUNNING = 0,
22  TASK_READY = 1,
28 };

Function Documentation

◆ 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_switch_to()

void tasks_switch_to ( struct task task)

Switches to a provided task.

Parameters
taskPointer to the task struct

◆ tasks_sync_block()

void tasks_sync_block ( struct task_sync tsc)

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 tsc)

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 }

Variable Documentation

◆ current_task

struct task* current_task

Definition at line 40 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
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_STATE_COUNT
@ TASK_STATE_COUNT
Definition: tasks.hpp:27
_tasks_enqueue_ready
void _tasks_enqueue_ready(struct task *task)
Definition: tasks.cpp:279
TASK_ACTION
#define TASK_ACTION(action, task)
Definition: tasks.cpp:124
TIME_SLICE_SIZE
#define TIME_SLICE_SIZE
Definition: tasks.hpp:17
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
TASK_STOPPED
@ TASK_STOPPED
Definition: tasks.hpp:25
task::stack_top
uintptr_t stack_top
Definition: tasks.hpp:34
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
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