/*
* Copyright (C) 2009 Niek Linnenbank
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "ProcessCtl.h"
void interruptNotify(CPUState *st, Process *p)
{
ProcessEvent event;
event.type = InterruptEvent;
event.number = IRQ_REG(st);
p->raiseEvent(&event);
}
Error ProcessCtlHandler(ProcessID procID,
ProcessOperation action,
Address addr,
Address output)
{
Process *proc = ZERO;
ProcessInfo *info = (ProcessInfo *) addr;
ProcessManager *procs = Kernel::instance->getProcessManager();
Timer *timer;
Arch::MemoryMap map;
DEBUG("#" << procs->current()->getID() << " " << action << " -> " << procID << " (" << addr << ")");
// TODO: Verify memory address
// Does the target process exist?
if(action != GetPID && action != Spawn)
{
if (procID == SELF)
proc = procs->current();
else if (!(proc = procs->get(procID)))
return API::NotFound;
}
// Handle request
switch (action)
{
case Spawn:
proc = procs->create(addr, map);
proc->setParent(procs->current()->getID());
return proc->getID();
case KillPID:
procs->remove(proc, addr); // Addr contains the exit status
procs->schedule();
break;
case GetPID:
return procs->current()->getID();
case GetParent:
return procs->current()->getParent();
case Schedule:
procs->schedule();
break;
case Resume:
// increment wakeup counter and set process ready
proc->wakeup();
break;
case WatchIRQ:
Kernel::instance->hookIntVector(IRQ(addr), (InterruptHandler *)interruptNotify, (ulong)proc);
break;
case EnableIRQ:
Kernel::instance->enableIRQ(addr, true);
break;
case DisableIRQ:
Kernel::instance->enableIRQ(addr, false);
break;
case InfoPID:
info->id = proc->getID();
info->state = proc->getState();
info->userStack = proc->getUserStack();
info->kernelStack = proc->getKernelStack();
info->pageDirectory = proc->getPageDirectory();
info->parent = proc->getParent();
break;
case WaitPID:
procs->current()->setWait(proc->getID());
procs->current()->setState(Process::Waiting);
procs->schedule();
return procs->current()->getWait(); // contains the exit status of the other process
case InfoTimer:
if (!(timer = Kernel::instance->getTimer()))
return API::NotFound;
timer->getCurrent((Timer::Info *) addr); // TODO: check access...
break;
/*
case WaitTimer:
procs->current()->setSleepTimer((const Timer::Info *)addr); // TODO: check access...
procs->current()->setState(Process::Sleeping);
procs->schedule();
// TODO: set a Timer::Info field for the process. Then when scheduling, the process
// will only be allowed to run until after the Timer::Info time has arrived (for sleep).
break;
*/
case EnterSleep:
// only sleeps the process if no pending wakeups
if (procs->current()->sleep((Timer::Info *)addr) == Process::Success)
procs->schedule();
if (output && ((timer = Kernel::instance->getTimer())))
timer->getCurrent((Timer::Info *) output); // TODO: check access...
break;
case SetStack:
proc->setUserStack(addr);
break;
}
return API::Success;
}
Log & operator << (Log &log, ProcessOperation op)
{
switch (op)
{
case Spawn: log.append("Spawn"); break;
case KillPID: log.append("KillPID"); break;
case GetPID: log.append("GetPID"); break;
case GetParent: log.append("GetParent"); break;
case WatchIRQ: log.append("WatchIRQ"); break;
case EnableIRQ: log.append("EnableIRQ"); break;
case DisableIRQ:log.append("DisableIRQ"); break;
case InfoPID: log.append("InfoPID"); break;
case WaitPID: log.append("WaitPID"); break;
case InfoTimer: log.append("InfoTimer"); break;
case EnterSleep: log.append("EnterSleep"); break;
case Schedule: log.append("Schedule"); break;
case Resume: log.append("Resume"); break;
case SetStack: log.append("SetStack"); break;
default: log.append("???"); break;
}
return log;
}