xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / multitasking.cpp (fc290e9d36f8920073f38c641c28c043a59f3107) (2,128B) (mode 100644) [raw]
#include "multitasking.hpp"

#include <new>

extern "C" void taskEntryThunk();
extern "C" void taskEntry(Task *task);
void taskEntryCxx(Task *task);

void
Task::init(GlobalDescriptorTable &gdt)
{
    cpuState = new(stack + sizeof(stack) - sizeof(CPUState)) CPUState;

    cpuState->eax() = reinterpret_cast<std::uint32_t>(this);
    cpuState->ebx() = 0;
    cpuState->ecx() = 0;
    cpuState->edx() = 0;

    cpuState->esi() = 0;
    cpuState->edi() = 0;
    cpuState->ebp() = 0;

    cpuState->gs() = gdt.getDS();
    cpuState->fs() = gdt.getDS();
    cpuState->es() = gdt.getDS();
    cpuState->ds() = gdt.getDS();

    // cpuState->esp() = ;
    cpuState->eip() = reinterpret_cast<std::uint32_t>(&taskEntryThunk);
    cpuState->cs() = gdt.getCS();
    // cpuState->ss() = ;
    cpuState->eflags() = 0x202;
}

void
taskEntry(Task *task)
{
    taskEntryCxx(task);
}

void
taskEntryCxx(Task *task)
{
    task->entry();
}

void
Task::entry()
{
    (*task)();
    done = true;
    asm ("int $0x20");
}

TaskManager::TaskManager(GlobalDescriptorTable &gdt)
    : InterruptHandler(0x20), gdt(gdt), numTasks(0), currentTask(-1)
{
}

bool
TaskManager::addTask(std::unique_ptr<Task> task)
{
    if (numTasks == 256) {
        return false;
    }

    task->init(gdt);
    tasks[numTasks++] = std::move(task);
    return true;
}

std::uint32_t
TaskManager::handleInterrupt(std::uint32_t esp)
{
    auto cpuState = new(reinterpret_cast<void *>(esp)) CPUState;
    return reinterpret_cast<std::uint32_t>(schedule(cpuState));
}

CPUState *
TaskManager::schedule(CPUState *cpuState)
{
    if (numTasks == 0) {
        return cpuState;
    }

    if (currentTask >= 0) {
        tasks[currentTask]->cpuState = cpuState;
        if (tasks[currentTask]->done) {
            tasks[currentTask] = std::move(tasks[numTasks - 1]);
            --numTasks;
            currentTask %= numTasks;
            // XXX: this could be the last task, need to handle this.
            return tasks[currentTask]->cpuState;
        }
    }

    if (++currentTask >= numTasks) {
        currentTask %= numTasks;
    }
    return tasks[currentTask]->cpuState;
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master