From 83aeec25147861bef2645037fdfcc93dfe3c3975 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Wed, 18 Jan 2012 17:10:44 +0100 Subject: [PATCH] Multiple threads can now wait on the same pipe. --- sortix/Makefile | 1 + sortix/event.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++ sortix/event.h | 49 ++++++++++++++++++++++++++++++++++ sortix/pipe.cpp | 31 +++++----------------- sortix/thread.cpp | 4 +++ sortix/thread.h | 7 +++++ 6 files changed, 135 insertions(+), 24 deletions(-) create mode 100644 sortix/event.cpp create mode 100644 sortix/event.h diff --git a/sortix/Makefile b/sortix/Makefile index 39f59523..ee084ec4 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -82,6 +82,7 @@ elf.o \ process.o \ initrd.o \ thread.o \ +event.o \ io.o \ pipe.o \ filesystem.o \ diff --git a/sortix/event.cpp b/sortix/event.cpp new file mode 100644 index 00000000..a6c01dfd --- /dev/null +++ b/sortix/event.cpp @@ -0,0 +1,67 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix 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. + + Sortix 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 Sortix. If not, see . + + event.cpp + Each thread can wait for an event to happen and be signaled when it does. + +******************************************************************************/ + +#include "platform.h" +#include "thread.h" +#include "syscall.h" +#include "event.h" + +namespace Sortix +{ + Event::Event() + { + waiting = NULL; + } + + Event::~Event() + { + if ( waiting ) + { + Panic("Thread was waiting on event, but it went out of scope"); + } + } + + void Event::Register() + { + Thread* thread = CurrentThread(); + if ( thread->event ) + { + Panic("Thread tried to wait on an event, but was already waiting"); + } + thread->event = this; + thread->eventnextwaiting = waiting; + waiting = thread; + } + + void Event::Signal() + { + while ( waiting ) + { + waiting->event = NULL; + Syscall::ScheduleResumption(waiting); + waiting = waiting->eventnextwaiting; + } + } +} + diff --git a/sortix/event.h b/sortix/event.h new file mode 100644 index 00000000..612fa01a --- /dev/null +++ b/sortix/event.h @@ -0,0 +1,49 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix 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. + + Sortix 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 Sortix. If not, see . + + event.h + Each thread can wait for an event to happen and be signaled when it does. + +******************************************************************************/ + +#ifndef SORTIX_EVENT_H +#define SORTIX_EVENT_H + +namespace Sortix +{ + class Thread; + + class Event + { + public: + Event(); + ~Event(); + + public: + void Register(); + void Signal(); + + private: + Thread* waiting; + + }; +} + +#endif + diff --git a/sortix/pipe.cpp b/sortix/pipe.cpp index 1b2996e5..1f48efc0 100644 --- a/sortix/pipe.cpp +++ b/sortix/pipe.cpp @@ -25,6 +25,7 @@ #include "platform.h" #include #include +#include "event.h" #include "thread.h" #include "process.h" #include "syscall.h" @@ -48,8 +49,8 @@ namespace Sortix size_t buffersize; size_t bufferoffset; size_t bufferused; - Thread* readwaiting; - Thread* writewaiting; + Event readevent; + Event writeevent; public: virtual ssize_t Read(byte* dest, size_t count); @@ -65,14 +66,10 @@ namespace Sortix this->buffersize = buffersize; this->bufferoffset = 0; this->bufferused = 0; - this->readwaiting = NULL; - this->writewaiting = NULL; } DevPipeStorage::~DevPipeStorage() { - if ( readwaiting ) { Syscall::ScheduleResumption(readwaiting); } - if ( writewaiting ) { Syscall::ScheduleResumption(writewaiting); } delete[] buffer; } @@ -91,20 +88,13 @@ namespace Sortix Memory::Copy(dest, buffer + bufferoffset, amount); bufferoffset = (bufferoffset + amount) % buffersize; bufferused -= amount; - if ( writewaiting ) - { - Syscall::ScheduleResumption(writewaiting); - writewaiting = NULL; - } + writeevent.Signal(); if ( bufferused == 0 || amount == count ) { return amount; } return amount + Read(dest + amount, count - amount); } Error::Set(EWOULDBLOCK); - - // TODO: Only one thread can wait on a pipe at the same time. - ASSERT(readwaiting == NULL); - readwaiting = CurrentThread(); + readevent.Register(); return -1; } @@ -120,20 +110,13 @@ namespace Sortix if ( linear < amount ) { amount = linear; } Memory::Copy(buffer + writeoffset, src, amount); bufferused += amount; - if ( readwaiting ) - { - Syscall::ScheduleResumption(readwaiting); - readwaiting = NULL; - } + readevent.Signal(); if ( buffersize == bufferused || amount == count ) { return amount; } return amount + Write(src + amount, count - amount); } Error::Set(EWOULDBLOCK); - - // TODO: Only one thread can wait on a pipe at the same time. - ASSERT(writewaiting == NULL); - writewaiting = CurrentThread(); + writeevent.Register(); return -1; } diff --git a/sortix/thread.cpp b/sortix/thread.cpp index fed4172f..4e8dff82 100644 --- a/sortix/thread.cpp +++ b/sortix/thread.cpp @@ -42,6 +42,8 @@ namespace Sortix process = NULL; prevsibling = NULL; nextsibling = NULL; + event = NULL; + eventnextwaiting = NULL; sleepuntil = 0; nextsleepingthread = NULL; schedulerlistprev = NULL; @@ -62,6 +64,8 @@ namespace Sortix prevsibling = NULL; nextsibling = NULL; state = forkfrom->state; + event = NULL; + eventnextwaiting = NULL; sleepuntil = forkfrom->sleepuntil; Maxsi::Memory::Copy(®isters, &forkfrom->registers, sizeof(registers)); ready = false; diff --git a/sortix/thread.h b/sortix/thread.h index f2126d7a..2746e149 100644 --- a/sortix/thread.h +++ b/sortix/thread.h @@ -29,6 +29,7 @@ namespace Sortix { + class Event; class Process; class Thread; @@ -62,6 +63,12 @@ namespace Sortix Thread* prevsibling; Thread* nextsibling; + // These are used internally when a thread is waiting for an Event to + // happen. Consider them private. + public: + Event* event; + Thread* eventnextwaiting; + // These are some things used internally by the scheduler and should not be // touched by anything but it. Consider it private. public: