2018-10-16 09:01:38 +00:00
|
|
|
#include "types.h"
|
|
|
|
#include "Task.h"
|
|
|
|
#include "kmalloc.h"
|
|
|
|
#include "VGA.h"
|
|
|
|
#include "StdLib.h"
|
|
|
|
#include "i386.h"
|
|
|
|
#include "system.h"
|
2018-10-18 08:28:09 +00:00
|
|
|
#include <VirtualFileSystem/FileHandle.h>
|
|
|
|
#include <VirtualFileSystem/VirtualFileSystem.h>
|
2018-10-17 21:13:55 +00:00
|
|
|
#include "MemoryManager.h"
|
2018-10-16 09:01:38 +00:00
|
|
|
|
|
|
|
Task* current;
|
2018-10-16 09:06:35 +00:00
|
|
|
Task* s_kernelTask;
|
2018-10-16 09:01:38 +00:00
|
|
|
|
|
|
|
static pid_t next_pid;
|
2018-10-17 08:55:43 +00:00
|
|
|
static InlineLinkedList<Task>* s_tasks;
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
static bool contextSwitch(Task*);
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
static void redoKernelTaskTSS()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-16 09:06:35 +00:00
|
|
|
if (!s_kernelTask->selector())
|
|
|
|
s_kernelTask->setSelector(allocateGDTEntry());
|
|
|
|
|
|
|
|
auto& tssDescriptor = getGDTEntry(s_kernelTask->selector());
|
|
|
|
|
|
|
|
tssDescriptor.setBase(&s_kernelTask->tss());
|
|
|
|
tssDescriptor.setLimit(0xffff);
|
|
|
|
tssDescriptor.dpl = 0;
|
|
|
|
tssDescriptor.segment_present = 1;
|
|
|
|
tssDescriptor.granularity = 1;
|
|
|
|
tssDescriptor.zero = 0;
|
|
|
|
tssDescriptor.operation_size = 1;
|
|
|
|
tssDescriptor.descriptor_type = 0;
|
|
|
|
tssDescriptor.type = 9;
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
flushGDT();
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
void Task::prepForIRETToNewTask()
|
|
|
|
{
|
|
|
|
redoKernelTaskTSS();
|
|
|
|
s_kernelTask->tss().backlink = current->selector();
|
|
|
|
loadTaskRegister(s_kernelTask->selector());
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
void Task::initialize()
|
|
|
|
{
|
|
|
|
current = nullptr;
|
|
|
|
next_pid = 0;
|
2018-10-17 08:55:43 +00:00
|
|
|
s_tasks = new InlineLinkedList<Task>;
|
2018-10-16 09:06:35 +00:00
|
|
|
s_kernelTask = new Task(0, "idle", IPC::Handle::Any, Task::Ring0);
|
|
|
|
redoKernelTaskTSS();
|
|
|
|
loadTaskRegister(s_kernelTask->selector());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TASK_SANITY_CHECKS
|
|
|
|
void Task::checkSanity(const char* msg)
|
|
|
|
{
|
|
|
|
char ch = current->name()[0];
|
|
|
|
kprintf("<%p> %s{%u}%b [%d] :%b: sanity check <%s>\n",
|
|
|
|
current->name().characters(),
|
|
|
|
current->name().characters(),
|
|
|
|
current->name().length(),
|
|
|
|
current->name()[current->name().length() - 1],
|
|
|
|
current->pid(), ch, msg ? msg : "");
|
|
|
|
ASSERT((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void Task::allocateLDT()
|
|
|
|
{
|
|
|
|
ASSERT(!m_tss.ldt);
|
|
|
|
static const WORD numLDTEntries = 4;
|
|
|
|
WORD newLDTSelector = allocateGDTEntry();
|
|
|
|
m_ldtEntries = new Descriptor[numLDTEntries];
|
|
|
|
#if 1
|
|
|
|
kprintf("new ldt selector = %x\n", newLDTSelector);
|
|
|
|
kprintf("new ldt table at = %p\n", m_ldtEntries);
|
|
|
|
kprintf("new ldt table size = %u\n", (numLDTEntries * 8) - 1);
|
|
|
|
#endif
|
|
|
|
Descriptor& ldt = getGDTEntry(newLDTSelector);
|
|
|
|
ldt.setBase(m_ldtEntries);
|
|
|
|
ldt.setLimit(numLDTEntries * 8 - 1);
|
|
|
|
ldt.dpl = 0;
|
|
|
|
ldt.segment_present = 1;
|
|
|
|
ldt.granularity = 0;
|
|
|
|
ldt.zero = 0;
|
|
|
|
ldt.operation_size = 1;
|
|
|
|
ldt.descriptor_type = 0;
|
|
|
|
ldt.type = Descriptor::LDT;
|
|
|
|
m_tss.ldt = newLDTSelector;
|
|
|
|
}
|
|
|
|
|
|
|
|
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
|
|
|
: m_name(n)
|
|
|
|
, m_entry(e)
|
|
|
|
, m_pid(next_pid++)
|
|
|
|
, m_handle(h)
|
|
|
|
, m_state(Runnable)
|
|
|
|
, m_ring(ring)
|
|
|
|
{
|
|
|
|
memset(&m_tss, 0, sizeof(m_tss));
|
|
|
|
memset(&m_ldtEntries, 0, sizeof(m_ldtEntries));
|
|
|
|
|
|
|
|
if (ring == Ring3) {
|
|
|
|
allocateLDT();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only IF is set when a task boots.
|
|
|
|
m_tss.eflags = 0x0202;
|
|
|
|
|
|
|
|
WORD dataSegment;
|
|
|
|
WORD stackSegment;
|
|
|
|
WORD codeSegment;
|
|
|
|
|
|
|
|
if (ring == Ring0) {
|
|
|
|
codeSegment = 0x08;
|
|
|
|
dataSegment = 0x10;
|
|
|
|
stackSegment = dataSegment;
|
|
|
|
} else {
|
|
|
|
codeSegment = 0x1b;
|
|
|
|
dataSegment = 0x23;
|
|
|
|
stackSegment = dataSegment;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tss.ds = dataSegment;
|
|
|
|
m_tss.es = dataSegment;
|
|
|
|
m_tss.fs = dataSegment;
|
|
|
|
m_tss.gs = dataSegment;
|
|
|
|
m_tss.ss = stackSegment;
|
|
|
|
m_tss.cs = codeSegment;
|
|
|
|
|
2018-10-17 21:13:55 +00:00
|
|
|
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
m_tss.eip = (DWORD)m_entry;
|
|
|
|
|
|
|
|
// NOTE: Each task gets 4KB of stack.
|
|
|
|
// This memory is leaked ATM.
|
|
|
|
// But uh, there's also no process termination, so I guess it's not technically leaked...
|
|
|
|
static const DWORD defaultStackSize = 4096;
|
|
|
|
m_stackTop = ((DWORD)kmalloc(defaultStackSize) + defaultStackSize) & 0xffffff8;
|
|
|
|
m_tss.esp = m_stackTop;
|
|
|
|
|
|
|
|
if (ring == Ring3) {
|
|
|
|
// Set up a separate stack for Ring0.
|
|
|
|
// FIXME: Don't leak this stack either.
|
|
|
|
DWORD ring0StackTop = ((DWORD)kmalloc(defaultStackSize) + defaultStackSize) & 0xffffff8;
|
|
|
|
m_tss.ss0 = 0x10;
|
|
|
|
m_tss.esp0 = ring0StackTop;
|
|
|
|
}
|
|
|
|
|
|
|
|
// HACK: Ring2 SS in the TSS is the current PID.
|
|
|
|
m_tss.ss2 = m_pid;
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
m_farPtr.offset = 0x12345678;
|
2018-10-16 09:01:38 +00:00
|
|
|
|
|
|
|
// Don't add task 0 (kernel dummy task) to task list.
|
|
|
|
// FIXME: This doesn't belong in the constructor.
|
|
|
|
if (m_pid == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Add it to head of task list (meaning it's next to run too, ATM.)
|
|
|
|
s_tasks->prepend(this);
|
|
|
|
|
|
|
|
system.nprocess++;
|
|
|
|
|
|
|
|
kprintf("Task %u (%s) spawned @ %p\n", m_pid, m_name.characters(), m_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
Task::~Task()
|
|
|
|
{
|
2018-10-17 22:26:30 +00:00
|
|
|
system.nprocess--;
|
2018-10-16 09:01:38 +00:00
|
|
|
delete [] m_ldtEntries;
|
|
|
|
m_ldtEntries = nullptr;
|
|
|
|
}
|
|
|
|
|
2018-10-17 22:26:30 +00:00
|
|
|
void Task::taskDidCrash(Task* crashedTask)
|
|
|
|
{
|
|
|
|
crashedTask->setState(Crashing);
|
|
|
|
s_tasks->remove(crashedTask);
|
|
|
|
|
|
|
|
if (!scheduleNewTask()) {
|
|
|
|
kprintf("Task::taskDidCrash: Failed to schedule a new task :(\n");
|
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete crashedTask;
|
|
|
|
|
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
void yield()
|
|
|
|
{
|
|
|
|
if (!current) {
|
|
|
|
kprintf( "PANIC: yield() with !current" );
|
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
//kprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
|
|
|
|
|
|
|
if (!scheduleNewTask())
|
|
|
|
return;
|
|
|
|
|
2018-10-17 21:49:32 +00:00
|
|
|
//kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
|
|
|
void switchNow()
|
|
|
|
{
|
2018-10-16 09:06:35 +00:00
|
|
|
Descriptor& descriptor = getGDTEntry(current->selector());
|
|
|
|
descriptor.type = 9;
|
|
|
|
flushGDT();
|
|
|
|
asm(
|
|
|
|
"ljmp *(%%eax)\n"
|
|
|
|
::"a"(¤t->farPtr())
|
|
|
|
);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
bool scheduleNewTask()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
if (!current) {
|
|
|
|
// XXX: The first ever context_switch() goes to the idle task.
|
|
|
|
// This to setup a reliable place we can return to.
|
2018-10-16 09:06:35 +00:00
|
|
|
return contextSwitch(Task::kernelTask());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check and unblock tasks whose wait conditions have been met.
|
|
|
|
for (auto* task = s_tasks->head(); task; task = task->next()) {
|
|
|
|
if (task->state() == Task::BlockedReceive && (task->ipc.msg.isValid() || task->ipc.notifies)) {
|
|
|
|
task->unblock();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (task->state() == Task::BlockedSend) {
|
|
|
|
Task* peer = Task::fromIPCHandle(task->ipc.dst);
|
|
|
|
if (peer && peer->state() == Task::BlockedReceive && peer->acceptsMessageFrom(*task)) {
|
|
|
|
task->unblock();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (task->state() == Task::BlockedSleep) {
|
|
|
|
if (task->wakeupTime() <= system.uptime) {
|
|
|
|
task->unblock();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* prevHead = s_tasks->head();
|
|
|
|
for (;;) {
|
|
|
|
// Move head to tail.
|
|
|
|
s_tasks->append(s_tasks->removeHead());
|
|
|
|
auto* task = s_tasks->head();
|
|
|
|
|
|
|
|
if (task->state() == Task::Runnable || task->state() == Task::Running) {
|
|
|
|
//kprintf("switch to %s\n", task->name().characters());
|
2018-10-16 09:06:35 +00:00
|
|
|
return contextSwitch(task);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (task == prevHead) {
|
|
|
|
// Back at task_head, nothing wants to run.
|
2018-10-16 09:06:35 +00:00
|
|
|
return contextSwitch(Task::kernelTask());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawSchedulerBanner(Task& task)
|
|
|
|
{
|
2018-10-16 09:06:35 +00:00
|
|
|
// FIXME: We need a kernel lock to do stuff like this :(
|
|
|
|
//return;
|
2018-10-16 09:01:38 +00:00
|
|
|
auto c = vga_get_cursor();
|
|
|
|
auto a = vga_get_attr();
|
|
|
|
vga_set_cursor(0, 50);
|
|
|
|
vga_set_attr(0x20);
|
|
|
|
kprintf(" ");
|
|
|
|
kprintf(" ");
|
|
|
|
kprintf(" ");
|
|
|
|
vga_set_cursor(0, 50);
|
|
|
|
kprintf("pid: %u ", task.pid());
|
|
|
|
vga_set_cursor(0, 58);
|
|
|
|
kprintf("%s", task.name().characters());
|
|
|
|
vga_set_cursor(0, 65);
|
|
|
|
kprintf("eip: %p", task.tss().eip);
|
|
|
|
vga_set_attr(a);
|
|
|
|
vga_set_cursor(c);
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
static bool contextSwitch(Task* t)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-16 09:06:35 +00:00
|
|
|
//kprintf("c_s to %s (same:%u)\n", t->name().characters(), current == t);
|
2018-10-16 09:01:38 +00:00
|
|
|
t->setTicksLeft(5);
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
if (current == t)
|
|
|
|
return false;
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
// If the last task hasn't blocked (still marked as running),
|
|
|
|
// mark it as runnable for the next round.
|
|
|
|
if (current->state() == Task::Running)
|
|
|
|
current->setState(Task::Runnable);
|
|
|
|
|
|
|
|
current = t;
|
|
|
|
t->setState(Task::Running);
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
if (!t->selector())
|
2018-10-16 09:01:38 +00:00
|
|
|
t->setSelector(allocateGDTEntry());
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
auto& tssDescriptor = getGDTEntry(t->selector());
|
|
|
|
|
|
|
|
tssDescriptor.limit_hi = 0;
|
|
|
|
tssDescriptor.limit_lo = 0xFFFF;
|
|
|
|
tssDescriptor.base_lo = (DWORD)(&t->tss()) & 0xFFFF;
|
|
|
|
tssDescriptor.base_hi = ((DWORD)(&t->tss()) >> 16) & 0xFF;
|
|
|
|
tssDescriptor.base_hi2 = ((DWORD)(&t->tss()) >> 24) & 0xFF;
|
|
|
|
tssDescriptor.dpl = 0;
|
|
|
|
tssDescriptor.segment_present = 1;
|
|
|
|
tssDescriptor.granularity = 1;
|
|
|
|
tssDescriptor.zero = 0;
|
|
|
|
tssDescriptor.operation_size = 1;
|
|
|
|
tssDescriptor.descriptor_type = 0;
|
|
|
|
tssDescriptor.type = 11; // Busy TSS
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
flushGDT();
|
|
|
|
drawSchedulerBanner(*t);
|
|
|
|
return true;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Task* Task::fromPID(pid_t pid)
|
|
|
|
{
|
|
|
|
for (auto* task = s_tasks->head(); task; task = task->next()) {
|
|
|
|
if (task->pid() == pid)
|
|
|
|
return task;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Task* Task::fromIPCHandle(IPC::Handle handle)
|
|
|
|
{
|
|
|
|
for (auto* task = s_tasks->head(); task; task = task->next()) {
|
|
|
|
if (task->handle() == handle)
|
|
|
|
return task;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileHandle* Task::fileHandleIfExists(int fd)
|
|
|
|
{
|
|
|
|
if (fd < 0)
|
|
|
|
return nullptr;
|
|
|
|
if ((unsigned)fd < m_fileHandles.size())
|
2018-10-18 08:28:09 +00:00
|
|
|
return m_fileHandles[fd].ptr();
|
2018-10-16 09:01:38 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Task::sys$seek(int fd, int offset)
|
|
|
|
{
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-16 09:01:38 +00:00
|
|
|
if (!handle)
|
|
|
|
return -1;
|
2018-10-18 08:28:09 +00:00
|
|
|
return handle->seek(offset, SEEK_SET);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-10-18 08:28:09 +00:00
|
|
|
ssize_t Task::sys$read(int fd, void* outbuf, size_t nread)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
Task::checkSanity("Task::sys$read");
|
|
|
|
kprintf("Task::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread);
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-16 09:01:38 +00:00
|
|
|
kprintf("Task::sys$read: handle=%p\n", handle);
|
|
|
|
if (!handle) {
|
|
|
|
kprintf("Task::sys$read: handle not found :(\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
kprintf("call read on handle=%p\n", handle);
|
2018-10-18 08:28:09 +00:00
|
|
|
nread = handle->read((byte*)outbuf, nread);
|
2018-10-16 09:01:38 +00:00
|
|
|
kprintf("called read\n");
|
|
|
|
kprintf("Task::sys$read: nread=%u\n", nread);
|
|
|
|
return nread;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Task::sys$close(int fd)
|
|
|
|
{
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-16 09:01:38 +00:00
|
|
|
if (!handle)
|
|
|
|
return -1;
|
2018-10-18 08:28:09 +00:00
|
|
|
// FIXME: Implement.
|
2018-10-16 09:01:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Task::sys$open(const char* path, size_t pathLength)
|
|
|
|
{
|
|
|
|
Task::checkSanity("sys$open");
|
|
|
|
kprintf("Task::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength);
|
|
|
|
auto* handle = current->openFile(String(path, pathLength));
|
|
|
|
if (handle)
|
|
|
|
return handle->fd();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileHandle* Task::openFile(String&& path)
|
|
|
|
{
|
2018-10-18 08:28:09 +00:00
|
|
|
kprintf("calling vfs::open with vfs=%p, path='%s'\n", &VirtualFileSystem::the(), path.characters());
|
|
|
|
auto handle = VirtualFileSystem::the().open(move(path));
|
|
|
|
if (!handle) {
|
|
|
|
kprintf("vfs::open() failed\n");
|
2018-10-16 09:01:38 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2018-10-18 08:28:09 +00:00
|
|
|
handle->setFD(m_fileHandles.size());
|
|
|
|
kprintf("vfs::open() worked! handle=%p, fd=%d\n", handle.ptr(), handle->fd());
|
|
|
|
m_fileHandles.append(move(handle)); // FIXME: allow non-move Vector::append
|
|
|
|
kprintf("Task::openFile(): FileHandle{%p} fd=%d\n", handle.ptr(), handle->fd());
|
|
|
|
return m_fileHandles.last().ptr();
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Task::sys$kill(pid_t pid, int sig)
|
|
|
|
{
|
|
|
|
(void) sig;
|
|
|
|
if (pid == 0) {
|
|
|
|
// FIXME: Send to same-group processes.
|
|
|
|
ASSERT(pid != 0);
|
|
|
|
}
|
|
|
|
if (pid == -1) {
|
|
|
|
// FIXME: Send to all processes.
|
|
|
|
ASSERT(pid != -1);
|
|
|
|
}
|
|
|
|
ASSERT_NOT_REACHED();
|
|
|
|
Task* peer = Task::fromPID(pid);
|
|
|
|
if (!peer) {
|
|
|
|
// errno = ESRCH;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
send(peer->handle(), IPC::Message(SYS_KILL, DataBuffer::copy((BYTE*)&sig, sizeof(sig))));
|
|
|
|
IPC::Message response = receive(peer->handle());
|
|
|
|
return *(int*)response.data();
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uid_t Task::sys$getuid()
|
|
|
|
{
|
|
|
|
return m_uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Task::acceptsMessageFrom(Task& peer)
|
|
|
|
{
|
|
|
|
return !ipc.msg.isValid() && (ipc.src == IPC::Handle::Any || ipc.src == peer.handle());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Task::unblock()
|
|
|
|
{
|
|
|
|
ASSERT(m_state != Task::Runnable && m_state != Task::Running);
|
|
|
|
system.nblocked--;
|
|
|
|
m_state = Task::Runnable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Task::block(Task::State state)
|
|
|
|
{
|
|
|
|
ASSERT(current->state() == Task::Running);
|
|
|
|
system.nblocked++;
|
|
|
|
current->setState(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void block(Task::State state)
|
|
|
|
{
|
|
|
|
current->block(state);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
void sleep(DWORD ticks)
|
|
|
|
{
|
|
|
|
ASSERT(current->state() == Task::Running);
|
|
|
|
current->setWakeupTime(system.uptime + ticks);
|
|
|
|
current->block(Task::BlockedSleep);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Task::sys$sleep(DWORD ticks)
|
|
|
|
{
|
|
|
|
ASSERT(this == current);
|
|
|
|
sleep(ticks);
|
|
|
|
}
|
|
|
|
|
|
|
|
Task* Task::kernelTask()
|
|
|
|
{
|
|
|
|
ASSERT(s_kernelTask);
|
|
|
|
return s_kernelTask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Task::setError(int error)
|
|
|
|
{
|
|
|
|
m_error = error;
|
|
|
|
}
|