mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Added pipe(2), write(2), and read(2).
This commit is contained in:
parent
c5605b6693
commit
a7de7b4905
18 changed files with 578 additions and 105 deletions
1
Makefile
1
Makefile
|
@ -102,7 +102,6 @@ debsource: all
|
|||
mkdir -p $(DEBSRCDIR)
|
||||
for D in `ls | grep -v builds | grep -v sysroot`; do cp -r $$D $(DEBSRCDIR); done
|
||||
(cd $(DEBSRCDIR) && make distclean)
|
||||
rm $(DEBSRCDIR)/git-daemon-export-ok
|
||||
rm -rf $(DEBSRCDIR)/sysroot
|
||||
(cd builds && tar cfzv $(DEBSRCNAME)-src.tar.gz $(DEBSRCNAME)-src)
|
||||
rm -rf $(DEBSRCDIR)
|
||||
|
|
|
@ -125,10 +125,8 @@ off_t lseek(int, off_t, int);
|
|||
int nice(int);
|
||||
long pathconf(const char*, int);
|
||||
int pause(void);
|
||||
int pipe(int [2]);
|
||||
ssize_t pread(int, void*, size_t, off_t);
|
||||
ssize_t pwrite(int, const void*, size_t, off_t);
|
||||
ssize_t read(int, void*, size_t);
|
||||
ssize_t readlink(const char* restrict, char* restrict, size_t);
|
||||
ssize_t readlinkat(int, const char* restrict, char* restrict, size_t);
|
||||
int rmdir(const char*);
|
||||
|
@ -152,7 +150,6 @@ char* ttyname(int);
|
|||
int ttyname_r(int, char*, size_t);
|
||||
int unlink(const char*);
|
||||
int unlinkat(int, const char*, int);
|
||||
ssize_t write(int, const void*, size_t);
|
||||
|
||||
#if __POSIX_OBSOLETE <= 200801
|
||||
pid_t setpgrp(void);
|
||||
|
@ -166,10 +163,13 @@ void _exit(int);
|
|||
pid_t fork(void);
|
||||
pid_t getpid(void);
|
||||
pid_t getppid(void);
|
||||
int pipe(int [2]);
|
||||
ssize_t read(int, void*, size_t);
|
||||
unsigned sleep(unsigned);
|
||||
#if __POSIX_OBSOLETE <= 200112
|
||||
int usleep(useconds_t useconds);
|
||||
#endif
|
||||
ssize_t write(int, const void*, size_t);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Maxsi
|
|||
|
||||
const int ENOTBLK = 12;
|
||||
const int ENODEV = 13;
|
||||
const int EWOULDBLOCK = 14;
|
||||
const int EBADF = 15;
|
||||
|
||||
extern int _errornumber;
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
namespace Maxsi
|
||||
{
|
||||
DEFN_SYSCALL1(size_t, SysPrint, 4, const char*);
|
||||
DEFN_SYSCALL3(ssize_t, SysRead, 18, int, void*, size_t);
|
||||
DEFN_SYSCALL3(ssize_t, SysWrite, 19, int, const void*, size_t);
|
||||
DEFN_SYSCALL1(int, SysPipe, 20, int*);
|
||||
|
||||
size_t Print(const char* Message)
|
||||
{
|
||||
|
@ -59,6 +62,22 @@ namespace Maxsi
|
|||
va_end(list);
|
||||
return (int) result;
|
||||
}
|
||||
|
||||
extern "C" ssize_t read(int fd, void* buf, size_t count)
|
||||
{
|
||||
return SysRead(fd, buf, count);
|
||||
}
|
||||
|
||||
extern "C" ssize_t write(int fd, const void* buf, size_t count)
|
||||
{
|
||||
return SysWrite(fd, buf, count);
|
||||
}
|
||||
|
||||
extern "C" int pipe(int pipefd[2])
|
||||
{
|
||||
return SysPipe(pipefd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ elf.o \
|
|||
process.o \
|
||||
initrd.o \
|
||||
thread.o \
|
||||
io.o \
|
||||
pipe.o \
|
||||
../libmaxsi/libmaxsi-sortix.a
|
||||
|
||||
JSOBJS:=$(subst .o,-js.o,$(OBJS))
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "platform.h"
|
||||
#include <libmaxsi/memory.h>
|
||||
#include "descriptors.h"
|
||||
#include "device.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
|
@ -91,7 +92,7 @@ namespace Sortix
|
|||
|
||||
if ( devices[index] != reserveddevideptr )
|
||||
{
|
||||
// TODO: Unref device here?
|
||||
devices[index]->Unref();
|
||||
}
|
||||
|
||||
devices[index] = NULL;
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Sortix
|
|||
public:
|
||||
inline Device* Get(int index)
|
||||
{
|
||||
if ( numdevices <= index ) { return NULL; }
|
||||
if ( index < 0 || numdevices <= index ) { return NULL; }
|
||||
return devices[index];
|
||||
}
|
||||
|
||||
|
|
|
@ -28,29 +28,24 @@
|
|||
|
||||
namespace Sortix
|
||||
{
|
||||
bool Device::Close()
|
||||
Device::Device()
|
||||
{
|
||||
_refCount--;
|
||||
if ( _refCount == 0 )
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return true;
|
||||
refcount = 0;
|
||||
}
|
||||
|
||||
void Device::Think()
|
||||
Device::~Device()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Device::RequestThink()
|
||||
void Device::Unref()
|
||||
{
|
||||
Think();
|
||||
if ( --refcount == 0 ) { delete this; }
|
||||
}
|
||||
|
||||
bool Device::Sync()
|
||||
void Device::Refer()
|
||||
{
|
||||
return true;
|
||||
refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,61 +27,26 @@
|
|||
|
||||
namespace Sortix
|
||||
{
|
||||
class User;
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
// Flags
|
||||
static const nat READABLE = (1<<0);
|
||||
static const nat WRITABLE = (1<<1);
|
||||
static const nat SEEKABLE = (1<<2);
|
||||
static const nat SIZEABLE = (1<<3);
|
||||
static const nat BLOCK = (1<<4);
|
||||
static const nat FLAGMASK = ((1<<5)-1);
|
||||
|
||||
// Types
|
||||
static const nat TYPEMASK = ~FLAGMASK;
|
||||
static const nat STREAM = (1<<5);
|
||||
static const nat BUFFER = (2<<5);
|
||||
static const nat DIRECTORY = (3<<5);
|
||||
static const nat FILESYSTEM = (4<<5);
|
||||
static const nat NETWORK = (5<<5);
|
||||
static const nat SOUND = (6<<5);
|
||||
static const nat GRAPHICS = (7<<5);
|
||||
static const nat MOUSE = (8<<5);
|
||||
static const nat KEYBOARD = (9<<5);
|
||||
static const nat PRINTER = (10<<5);
|
||||
static const nat SCANNER = (11<<5);
|
||||
static const nat VGABUFFER = (12<<5);
|
||||
static const nat OTHER = TYPEMASK;
|
||||
static const unsigned STREAM = 0;
|
||||
static const unsigned BUFFER = 1;
|
||||
static const unsigned VGABUFFER = 2;
|
||||
|
||||
public:
|
||||
volatile size_t _refCount;
|
||||
|
||||
public:
|
||||
Device() { _refCount = 1; }
|
||||
virtual ~Device() { }
|
||||
Device();
|
||||
virtual ~Device();
|
||||
|
||||
private:
|
||||
User* _owner;
|
||||
size_t refcount;
|
||||
|
||||
public:
|
||||
bool IsOwner(User* candidate) { return candidate == _owner; }
|
||||
void Refer();
|
||||
void Unref();
|
||||
|
||||
public:
|
||||
bool Close();
|
||||
void RequestThink();
|
||||
|
||||
protected:
|
||||
virtual void Think();
|
||||
|
||||
public:
|
||||
virtual bool Sync();
|
||||
virtual nat Flags() = 0;
|
||||
|
||||
public:
|
||||
bool IsType(nat type) { return (Flags() & TYPEMASK) == type; }
|
||||
virtual bool IsType(unsigned type) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
126
sortix/io.cpp
Normal file
126
sortix/io.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
io.cpp
|
||||
Provides system calls for input and output.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
#include <libmaxsi/error.h>
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include "syscall.h"
|
||||
#include "io.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
struct SysWrite_t
|
||||
{
|
||||
union { size_t align1; int fd; };
|
||||
union { size_t align2; const byte* buffer; };
|
||||
union { size_t align3; size_t count; };
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(SysWrite_t) <= sizeof(Thread::scstate));
|
||||
|
||||
ssize_t SysWrite(int fd, const byte* buffer, size_t count)
|
||||
{
|
||||
// TODO: Check that buffer is a valid user-space buffer.
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { return -1; /* TODO: EBADF */ }
|
||||
if ( !dev->IsType(Device::STREAM) ) { return -1; /* TODO: EBADF */ }
|
||||
DevStream* stream = (DevStream*) dev;
|
||||
if ( !stream->IsWritable() ) { return -1; /* TODO: EBADF */ }
|
||||
ssize_t written = stream->Write(buffer, count);
|
||||
if ( 0 <= written ) { return written; }
|
||||
if ( Error::Last() != Error::EWOULDBLOCK ) { return -1; /* TODO: errno */ }
|
||||
|
||||
// The stream will resume our system call once progress has been
|
||||
// made. Our request is certainly not forgotten.
|
||||
|
||||
// Resume the system call with these parameters.
|
||||
Thread* thread = CurrentThread();
|
||||
thread->scfunc = (void*) SysWrite;
|
||||
SysWrite_t* state = (SysWrite_t*) thread->scstate;
|
||||
state->fd = fd;
|
||||
state->buffer = buffer;
|
||||
state->count = count;
|
||||
thread->scsize = sizeof(SysWrite_t);
|
||||
|
||||
// Now go do something else.
|
||||
Syscall::Incomplete();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct SysRead_t
|
||||
{
|
||||
union { size_t align1; int fd; };
|
||||
union { size_t align2; byte* buffer; };
|
||||
union { size_t align3; size_t count; };
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(SysRead_t) <= sizeof(Thread::scstate));
|
||||
|
||||
ssize_t SysRead(int fd, byte* buffer, size_t count)
|
||||
{
|
||||
// TODO: Check that buffer is a valid user-space buffer.
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { return -1; /* TODO: EBADF */ }
|
||||
if ( !dev->IsType(Device::STREAM) ) { return -1; /* TODO: EBADF */ }
|
||||
DevStream* stream = (DevStream*) dev;
|
||||
if ( !stream->IsReadable() ) { return -1; /* TODO: EBADF */ }
|
||||
ssize_t bytesread = stream->Read(buffer, count);
|
||||
if ( 0 <= bytesread ) { return bytesread; }
|
||||
if ( Error::Last() != Error::EWOULDBLOCK ) { return -1; /* TODO: errno */ }
|
||||
|
||||
// The stream will resume our system call once progress has been
|
||||
// made. Our request is certainly not forgotten.
|
||||
|
||||
// Resume the system call with these parameters.
|
||||
Thread* thread = CurrentThread();
|
||||
thread->scfunc = (void*) SysRead;
|
||||
SysRead_t* state = (SysRead_t*) thread->scstate;
|
||||
state->fd = fd;
|
||||
state->buffer = buffer;
|
||||
state->count = count;
|
||||
thread->scsize = sizeof(SysRead_t);
|
||||
|
||||
// Now go do something else.
|
||||
Syscall::Incomplete();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_WRITE, (void*) SysWrite);
|
||||
Syscall::Register(SYSCALL_READ, (void*) SysRead);
|
||||
}
|
||||
}
|
||||
}
|
37
sortix/io.h
Normal file
37
sortix/io.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
io.h
|
||||
Provides system calls for input and output.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_IO_H
|
||||
#define SORTIX_IO_H
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -45,6 +45,8 @@
|
|||
#include "initrd.h"
|
||||
#include "vga.h"
|
||||
#include "sound.h"
|
||||
#include "io.h"
|
||||
#include "pipe.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
|
@ -236,6 +238,12 @@ namespace Sortix
|
|||
// Initialize the process system.
|
||||
Process::Init();
|
||||
|
||||
// Initialize the IO system.
|
||||
IO::Init();
|
||||
|
||||
// Initialize the pipe system.
|
||||
Pipe::Init();
|
||||
|
||||
// Initialize the scheduler.
|
||||
Scheduler::Init();
|
||||
|
||||
|
|
289
sortix/pipe.cpp
Normal file
289
sortix/pipe.cpp
Normal file
|
@ -0,0 +1,289 @@
|
|||
/******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
pipe.cpp
|
||||
A device with a writing end and a reading end.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
#include <libmaxsi/error.h>
|
||||
#include <libmaxsi/memory.h>
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "syscall.h"
|
||||
#include "pipe.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevPipeStorage : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeStorage(byte* buffer, size_t buffersize);
|
||||
~DevPipeStorage();
|
||||
|
||||
private:
|
||||
byte* buffer;
|
||||
size_t buffersize;
|
||||
size_t bufferoffset;
|
||||
size_t bufferused;
|
||||
Thread* readwaiting;
|
||||
Thread* writewaiting;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(byte* dest, size_t count);
|
||||
virtual ssize_t Write(const byte* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevPipeStorage::DevPipeStorage(byte* buffer, size_t buffersize)
|
||||
{
|
||||
this->buffer = buffer;
|
||||
this->buffersize = buffersize;
|
||||
this->bufferoffset = 0;
|
||||
this->bufferused = 0;
|
||||
this->readwaiting = NULL;
|
||||
this->writewaiting = NULL;
|
||||
}
|
||||
|
||||
DevPipeStorage::~DevPipeStorage()
|
||||
{
|
||||
ASSERT(!readwaiting);
|
||||
ASSERT(!writewaiting);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool DevPipeStorage::IsReadable() { return true; }
|
||||
bool DevPipeStorage::IsWritable() { return true; }
|
||||
|
||||
ssize_t DevPipeStorage::Read(byte* dest, size_t count)
|
||||
{
|
||||
if ( count == 0 ) { return 0; }
|
||||
if ( bufferused )
|
||||
{
|
||||
if ( bufferused < count ) { count = bufferused; }
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - bufferused;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
Memory::Copy(dest, buffer + bufferoffset, amount);
|
||||
bufferoffset = (bufferoffset + amount) % buffersize;
|
||||
bufferused -= amount;
|
||||
if ( writewaiting )
|
||||
{
|
||||
Syscall::ScheduleResumption(writewaiting);
|
||||
writewaiting = NULL;
|
||||
}
|
||||
if ( bufferused == 0 || amount == count ) { return amount; }
|
||||
return amount + Read(dest + amount, count - amount);
|
||||
}
|
||||
|
||||
Error::Set(Error::EWOULDBLOCK);
|
||||
|
||||
// TODO: Only one thread can wait on a pipe at the same time.
|
||||
ASSERT(readwaiting == NULL);
|
||||
readwaiting = CurrentThread();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t DevPipeStorage::Write(const byte* src, size_t count)
|
||||
{
|
||||
if ( count == 0 ) { return 0; }
|
||||
if ( bufferused < buffersize )
|
||||
{
|
||||
if ( buffersize - bufferused < count ) { count = buffersize - bufferused; }
|
||||
size_t writeoffset = (bufferoffset + bufferused) % buffersize;
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - writeoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
Memory::Copy(buffer + writeoffset, src, amount);
|
||||
bufferused += amount;
|
||||
if ( readwaiting )
|
||||
{
|
||||
Syscall::ScheduleResumption(readwaiting);
|
||||
readwaiting = NULL;
|
||||
}
|
||||
if ( buffersize == bufferused || amount == count ) { return amount; }
|
||||
return amount + Write(src + amount, count - amount);
|
||||
}
|
||||
|
||||
Error::Set(Error::EWOULDBLOCK);
|
||||
|
||||
// TODO: Only one thread can wait on a pipe at the same time.
|
||||
ASSERT(writewaiting == NULL);
|
||||
writewaiting = CurrentThread();
|
||||
return -1;
|
||||
}
|
||||
|
||||
class DevPipeReading : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeReading(DevStream* stream);
|
||||
~DevPipeReading();
|
||||
|
||||
private:
|
||||
DevStream* stream;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(byte* dest, size_t count);
|
||||
virtual ssize_t Write(const byte* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevPipeReading::DevPipeReading(DevStream* stream)
|
||||
{
|
||||
stream->Refer();
|
||||
this->stream = stream;
|
||||
}
|
||||
|
||||
DevPipeReading::~DevPipeReading()
|
||||
{
|
||||
stream->Unref();
|
||||
}
|
||||
|
||||
ssize_t DevPipeReading::Read(byte* dest, size_t count)
|
||||
{
|
||||
return stream->Read(dest, count);
|
||||
}
|
||||
|
||||
ssize_t DevPipeReading::Write(const byte* /*src*/, size_t /*count*/)
|
||||
{
|
||||
Error::Set(Error::EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool DevPipeReading::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevPipeReading::IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class DevPipeWriting : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeWriting(DevStream* stream);
|
||||
~DevPipeWriting();
|
||||
|
||||
private:
|
||||
DevStream* stream;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(byte* dest, size_t count);
|
||||
virtual ssize_t Write(const byte* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevPipeWriting::DevPipeWriting(DevStream* stream)
|
||||
{
|
||||
stream->Refer();
|
||||
this->stream = stream;
|
||||
}
|
||||
|
||||
DevPipeWriting::~DevPipeWriting()
|
||||
{
|
||||
stream->Unref();
|
||||
}
|
||||
|
||||
ssize_t DevPipeWriting::Read(byte* /*dest*/, size_t /*count*/)
|
||||
{
|
||||
Error::Set(Error::EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t DevPipeWriting::Write(const byte* src, size_t count)
|
||||
{
|
||||
return stream->Write(src, count);
|
||||
}
|
||||
|
||||
bool DevPipeWriting::IsReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevPipeWriting::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace Pipe
|
||||
{
|
||||
const size_t BUFFER_SIZE = 4096UL;
|
||||
|
||||
int SysPipe(int pipefd[2])
|
||||
{
|
||||
// TODO: Validate that pipefd is a valid user-space array!
|
||||
|
||||
size_t buffersize = BUFFER_SIZE;
|
||||
byte* buffer = new byte[buffersize];
|
||||
if ( !buffer ) { return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
// Transfer ownership of the buffer to the storage device.
|
||||
DevStream* storage = new DevPipeStorage(buffer, buffersize);
|
||||
if ( !storage ) { delete[] buffer; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
DevStream* reading = new DevPipeReading(storage);
|
||||
if ( !reading ) { delete storage; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
DevStream* writing = new DevPipeWriting(storage);
|
||||
if ( !writing ) { delete reading; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
Process* process = CurrentProcess();
|
||||
int readfd = process->descriptors.Allocate(reading);
|
||||
int writefd = process->descriptors.Allocate(writing);
|
||||
|
||||
if ( readfd < 0 || writefd < 0 )
|
||||
{
|
||||
if ( 0 <= readfd ) { process->descriptors.Free(readfd); } else { delete reading; }
|
||||
if ( 0 <= writefd ) { process->descriptors.Free(writefd); } else { delete writing; }
|
||||
|
||||
return -1; /* TODO: ENOMEM/EMFILE/ENFILE */
|
||||
}
|
||||
|
||||
pipefd[0] = readfd;
|
||||
pipefd[1] = writefd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_PIPE, (void*) SysPipe);
|
||||
}
|
||||
}
|
||||
}
|
40
sortix/pipe.h
Normal file
40
sortix/pipe.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
pipe.h
|
||||
A device with a writing end and a reading end.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef SORTIX_PIPE_H
|
||||
#define SORTIX_PIPE_H
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace Pipe
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -25,61 +25,43 @@
|
|||
#ifndef SORTIX_STREAM_H
|
||||
#define SORTIX_STREAM_H
|
||||
|
||||
#include "device.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
Device() { };
|
||||
virtual ~Device() { }
|
||||
|
||||
public:
|
||||
virtual void close() = 0;
|
||||
|
||||
};
|
||||
|
||||
class DevStream : public Device
|
||||
{
|
||||
public:
|
||||
DevStream() { };
|
||||
virtual ~DevStream() { }
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
virtual size_t write(const void* buffer, size_t bufferSize) = 0;
|
||||
virtual size_t readSome(const void* buffer, size_t bufferSize) = 0;
|
||||
virtual bool IsType(unsigned type) { return type == Device::STREAM; }
|
||||
|
||||
public:
|
||||
inline size_t read(const void* buffer, size_t bufferSize)
|
||||
{
|
||||
const uint8_t* bytes = (uint8_t*) buffer;
|
||||
size_t total = bufferSize;
|
||||
while ( BufferSize > 0 )
|
||||
{
|
||||
size_t got = readSome(bytes, bufferSize);
|
||||
if ( got == SIZE_MAX ) { return SIZE_MAX; }
|
||||
bytes += got;
|
||||
bufferSize -= got;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
virtual ssize_t Read(byte* dest, size_t count) = 0;
|
||||
virtual ssize_t Write(const byte* src, size_t count) = 0;
|
||||
virtual bool IsReadable() = 0;
|
||||
virtual bool IsWritable() = 0;
|
||||
|
||||
};
|
||||
|
||||
class DevBuffer : public DevStream
|
||||
{
|
||||
public:
|
||||
DevBuffer() { };
|
||||
virtual ~DevBuffer() { }
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
virtual size_t write(const void* buffer, size_t bufferSize) = 0;
|
||||
virtual size_t readSome(const void* buffer, size_t bufferSize) = 0;
|
||||
virtual bool IsType(unsigned type)
|
||||
{
|
||||
return type == Device::BUFFER || BaseClass::IsType(type);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual size_t blockSize() = 0;
|
||||
virtual intmax_t size() = 0;
|
||||
virtual intmax_t position() = 0;
|
||||
virtual bool seek(intmax_t position) = 0;
|
||||
virtual bool resize(intmax_t size) = 0;
|
||||
virtual size_t BlockSize() = 0;
|
||||
virtual uintmax_t Size() = 0;
|
||||
virtual uintmax_t Position() = 0;
|
||||
virtual bool Seek(uintmax_t position) = 0;
|
||||
virtual bool Resize(uintmax_t size) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,7 +43,10 @@
|
|||
#define SYSCALL_GET_FILEINFO 15
|
||||
#define SYSCALL_GET_NUM_FILES 16
|
||||
#define SYSCALL_WAIT 17
|
||||
#define SYSCALL_MAX_NUM 18 /* index of highest constant + 1 */
|
||||
#define SYSCALL_READ 18
|
||||
#define SYSCALL_WRITE 19
|
||||
#define SYSCALL_PIPE 20
|
||||
#define SYSCALL_MAX_NUM 21 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ namespace Sortix
|
|||
frame->physical = page;
|
||||
frame->userframe = userframe;
|
||||
|
||||
frame->Refer();
|
||||
|
||||
return mapto;
|
||||
}
|
||||
|
||||
|
@ -185,7 +187,7 @@ namespace Sortix
|
|||
process->descriptors.Free(fd);
|
||||
|
||||
if ( device == NULL ) { return -1; }
|
||||
if ( !device->Close() ) { return -1; }
|
||||
device->Unref();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -206,5 +208,8 @@ namespace Sortix
|
|||
if ( physical != 0 ) { Page::Put(physical); }
|
||||
}
|
||||
|
||||
nat DevVGAFrame::Flags() { return Device::VGABUFFER; }
|
||||
bool DevVGAFrame::IsType(unsigned type)
|
||||
{
|
||||
return type == Device::VGABUFFER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,13 +71,13 @@ namespace Sortix
|
|||
|
||||
class DevVGAFrame : public Device
|
||||
{
|
||||
public:
|
||||
virtual nat Flags();
|
||||
|
||||
public:
|
||||
DevVGAFrame();
|
||||
~DevVGAFrame();
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type);
|
||||
|
||||
public:
|
||||
Process* process;
|
||||
addr_t physical;
|
||||
|
|
Loading…
Reference in a new issue