Added some support for blocking system calls in the kernel.

This commit is contained in:
Jonas 'Sortie' Termansen 2011-11-06 23:06:32 +01:00
parent cfd7648ca9
commit 851ee78903
6 changed files with 86 additions and 4 deletions

View File

@ -130,6 +130,8 @@ namespace Sortix
currentthread = nextthread;
LogEndContextSwitch(currentthread, regs);
if ( currentthread->scfunc ) { Syscall::Resume(regs); }
}
void ProcessTerminated(CPU::InterruptRegisters* regs)

View File

@ -38,7 +38,7 @@ namespace Sortix
extern "C"
{
CPU::SyscallRegisters* syscall_state_ptr;
int system_was_incomplete;
unsigned system_was_incomplete;
size_t SYSCALL_MAX = SYSCALL_MAX_NUM;
void* syscall_list[SYSCALL_MAX_NUM];
}
@ -70,11 +70,13 @@ namespace Sortix
void Incomplete()
{
Thread* thread = CurrentThread();
system_was_incomplete = 1;
CPU::InterruptRegisters* regs = InterruptRegs();
CurrentThread()->SaveRegisters(regs);
// TODO: Make the thread blocking if not already.
thread->SaveRegisters(regs);
Scheduler::SetThreadState(thread, Thread::State::BLOCKING);
Scheduler::Switch(regs);
}
@ -83,6 +85,42 @@ namespace Sortix
system_was_incomplete = 1;
}
void ScheduleResumption(Thread* thread)
{
Scheduler::SetThreadState(thread, Thread::State::RUNNABLE);
}
extern "C" size_t resume_syscall(void* scfunc, size_t scsize, size_t* scstate);
void Resume(CPU::InterruptRegisters* regs)
{
Thread* thread = CurrentThread();
syscall_state_ptr = (CPU::SyscallRegisters*) regs;
ASSERT(thread->scfunc);
size_t* scstate = thread->scstate;
size_t scsize = thread->scsize;
void* scfunc = thread->scfunc;
system_was_incomplete = 0;
size_t result = resume_syscall(scfunc, scsize, scstate);
bool incomplete = (system_was_incomplete);
system_was_incomplete = 1;
if ( !incomplete )
{
syscall_state_ptr->result = result;
return;
}
Incomplete();
}
CPU::InterruptRegisters* InterruptRegs()
{
return (CPU::InterruptRegisters*) syscall_state_ptr;

View File

@ -29,6 +29,8 @@
namespace Sortix
{
class Thread;
namespace Syscall
{
void Init();
@ -45,6 +47,14 @@ namespace Sortix
// For when you want the syscall exit code not to modify registers.
void AsIs();
// Retries a system call by making the thread runnable and then calling
// the system call code whenever the thread is scheduled to run.
void ScheduleResumption(Thread* thread);
// Retries a system call based on the Thread::sc* values of the current
// thread and if it succeeds, sets the proper registers.
void Resume(CPU::InterruptRegisters* regs);
CPU::InterruptRegisters* InterruptRegs();
CPU::SyscallRegisters* SyscallRegs();
}

View File

@ -44,7 +44,8 @@ namespace Sortix
schedulerlistnext = NULL;
state = NONE;
Maxsi::Memory::Set(&registers, 0, sizeof(registers));
ready = false;
ready = false;
scfunc = NULL;
}
Thread::Thread(const Thread* forkfrom)
@ -62,6 +63,7 @@ namespace Sortix
nextsleepingthread = NULL;
schedulerlistprev = NULL;
schedulerlistnext = NULL;
scfunc = NULL;
}
Thread::~Thread()

View File

@ -83,6 +83,11 @@ namespace Sortix
Thread* Fork();
void SaveRegisters(const CPU::InterruptRegisters* src);
void LoadRegisters(CPU::InterruptRegisters* dest);
public:
void* scfunc;
size_t scsize;
size_t scstate[8];
};
}

View File

@ -23,6 +23,7 @@
******************************************************************************/
.global syscall_handler
.global resume_syscall
.section .text
.type syscall_handler, @function
@ -109,3 +110,27 @@ return_to_userspace:
# Return to user-space.
iretl
.type resume_syscall, @function
resume_syscall:
pushl %ebp
movl %esp, %ebp
movl 8(%esp), %eax
movl 16(%esp), %ecx
pushl 28(%ecx)
pushl 24(%ecx)
pushl 20(%ecx)
pushl 16(%ecx)
pushl 12(%ecx)
pushl 8(%ecx)
pushl 4(%ecx)
pushl 0(%ecx)
call *%eax
addl $32, %esp
leavel
retl