Quantcast
Viewing all articles
Browse latest Browse all 10

OS Class lab5-6: Implementing multitasking

Goal

  • have a simple multitasking implemented
  • your OS multitasking should have the following functions available:
    • void sched_add_task(void* func_ptr) – add a task to scheduler by giving a function pointer
    • void yield(void) – give control to scheduler in a task
    • void sched_run(void) – start the scheduler

To demonstrate that your multitakisking implementation works, you have to have the following code in your kmain.c

char* vidmem = (char *) 0xb8000;

void task0 (void) {
  while (1) {
    yield();
    vidmem[0] = vidmem[0] == 'B' ? 'A' : 'B';
    wait();
  }
}

void task1 (void) {
  while (1) {
    yield();
    vidmem[2] = vidmem[2] == 'B' ? 'A' : 'B';
    wait();
  }
}

int main( void )
{
  vidmem[1] = 0x7;
  vidmem[3] = 0x7;
  sched_add_task(task0);
  sched_add_task(task1);
  sched_run();
}

Things you need

  • have the lab4 done, and to understand what is setjmp, longjmp, what they do, and how they do it. (google is your friend)

Progress

Task

Since our simple OS must do multitasking, this means it can mange multiple tasks. Therefore, our OS must operate with the concept of a task. This concept, like any other concept in our OS, must have a actual representation. This means only one thing – a task is a data structure. But how does it look?

In laboratory work number 4, you added a special structure to your project – jmp_buf, which stores the cpu registers. Since a task has it’s own context of execution, obviously, the task data structure must have a jmp_buf inside. Also, to have an isolated context, each task should have it’s own stack.

typedef struct {
  jmp_buf state;
  unsigned char stack[TASK_STACK_SIZE];
} task_t;

But that is not enough, each task must have a state, this for our scheduler to manage them more smartly. For example: No need to switch the context to a task which is a zombie, since this will be a waste of CPU time. Therefore, our task type (task_t) must store the state:

typedef enum {
  TS_RUNNABLE = 1, TS_BLOCKED = 2, TS_ZOMBIE = 3
} task_status_t;

Lastly, include a structure of this type in our task structure:

typedef struct {
  jmp_buf state;
  unsigned char stack[TASK_STACK_SIZE];
  task_status_t status;
} task_t;

The task data structure definition is also available in this gist.

Scheduling – general overview

Scheduling – is the process of managing multiple tasks at the same time and switching the context between them. We will implement a simple, cooperative scheduler – this means that each task must explicitly give control to OS to schedule other tasks. Therefore, a task will usually look like this:

void task0 (void) {
  // this is a long computation
  while (1) {
    yield(); // give control to os to schedule
    // do a fraction of the long computation
  }
}

So from our example task, we understand that we need to know how the yield function will look. It’s psudocode looks like this:

void yield (void) {
  // switch context from current task to next
  sched_switch_context(current_task(), next_task())
}

Scheduling – Managing tasks

So, your OS scheduler should:

  • have a fixed array to store up to 4 tasks. (to make it easy)
  • should initialize a task with it’s function pointer when a task is added.
  • when yield is called, should switch the context to the next runnable task, after saving the current task state.

Scheduling – QA

Q: how to know which is the current task?

A: a global variable will do.

Q: how to store tasks?

A: an array is fine.

Q: ZOMG! How do I implement sched_add_task?

A: Here’s a skeleton for you:

void
sched_add_task (void* func_ptr) {
  task_t *task = & _sched_tasks[++_sched_num_tasks];
  unsigned* initial_stack_ptr;

  //The task comes with the current context as default
  sched_save_state(task);
  initial_stack_ptr = (unsigned) task->stack + TASK_STACK_SIZE;

  // set stack pointer of the task context to initial_stack_ptr
  // set instruction pointer of the task context to func_ptr
  // set status of the task as runnable

  task->state[0].eflags = 0x200; //some magic for longjmp
}

Viewing all articles
Browse latest Browse all 10

Trending Articles