Add {,p}{read,write}v(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2013-05-03 21:43:01 +02:00
parent b3e7aafff8
commit ef32b3fcbe
9 changed files with 402 additions and 3 deletions

View File

@ -289,16 +289,19 @@ pipe.o \
poll.o \
popen.o \
ppoll.o \
preadv.o \
print.o \
psignal.o \
putc.o \
pwent.o \
pwritev.o \
raise.o \
rand.o \
readdirents.o \
readlinkat.o \
readlink.o \
read.o \
readv.o \
realpath.o \
removeat.o \
remove.o \
@ -365,6 +368,7 @@ wait.o \
waitpid.o \
winsize.o \
write.o \
writev.o \
OBJS=\
$(FREEOBJS) \

49
libc/include/sys/uio.h Normal file
View File

@ -0,0 +1,49 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
sys/uio.h
Vector IO operations.
*******************************************************************************/
#ifndef INCLUDE_SYS_UIO_H
#define INCLUDE_SYS_UIO_H
#include <features.h>
__BEGIN_DECLS
@include(size_t.h)
@include(ssize_t.h)
@include(off_t.h)
__END_DECLS
#include <sortix/uio.h>
__BEGIN_DECLS
ssize_t readv(int, const struct iovec*, int);
ssize_t writev(int, const struct iovec*, int);
ssize_t preadv(int, const struct iovec*, int, off_t);
ssize_t pwritev(int, const struct iovec*, int, off_t);
__END_DECLS
#endif

34
libc/preadv.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
preadv.cpp
Read data into multiple buffers.
*******************************************************************************/
#include <sys/syscall.h>
#include <sys/uio.h>
DEFN_SYSCALL4(ssize_t, sys_preadv, SYSCALL_PREADV, int, const struct iovec*, int, off_t);
extern "C"
ssize_t preadv(int fd, const struct iovec* iov, int iovcnt, off_t offset)
{
return sys_preadv(fd, iov, iovcnt, offset);
}

34
libc/pwritev.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
pwritev.cpp
Write data from multiple buffers.
*******************************************************************************/
#include <sys/syscall.h>
#include <sys/uio.h>
DEFN_SYSCALL4(ssize_t, sys_pwritev, SYSCALL_PWRITEV, int, const struct iovec*, int, off_t);
extern "C"
ssize_t pwritev(int fd, const struct iovec* iov, int iovcnt, off_t offset)
{
return sys_pwritev(fd, iov, iovcnt, offset);
}

33
libc/readv.cpp Normal file
View File

@ -0,0 +1,33 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
readv.cpp
Read data into multiple buffers.
*******************************************************************************/
#include <sys/syscall.h>
#include <sys/uio.h>
DEFN_SYSCALL3(ssize_t, sys_readv, SYSCALL_READV, int, const struct iovec*, int);
extern "C" ssize_t readv(int fd, const struct iovec* iov, int iovcnt)
{
return sys_readv(fd, iov, iovcnt);
}

33
libc/writev.cpp Normal file
View File

@ -0,0 +1,33 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
writev.cpp
Write data from multiple buffers.
*******************************************************************************/
#include <sys/syscall.h>
#include <sys/uio.h>
DEFN_SYSCALL3(ssize_t, sys_writev, SYSCALL_WRITEV, int, const struct iovec*, int);
extern "C" ssize_t writev(int fd, const struct iovec* iov, int iovcnt)
{
return sys_writev(fd, iov, iovcnt);
}

View File

@ -22,8 +22,8 @@
*******************************************************************************/
#ifndef SORTIX_SYSCALLNUM_H
#define SORTIX_SYSCALLNUM_H
#ifndef INCLUDE_SORTIX_SYSCALLNUM_H
#define INCLUDE_SORTIX_SYSCALLNUM_H
#define SYSCALL_BAD_SYSCALL 0
#define SYSCALL_EXIT 1
@ -114,6 +114,10 @@
#define SYSCALL_BIND 90
#define SYSCALL_CONNECT 91
#define SYSCALL_LISTEN 92
#define SYSCALL_MAX_NUM 93 /* index of highest constant + 1 */
#define SYSCALL_READV 93
#define SYSCALL_WRITEV 94
#define SYSCALL_PREADV 95
#define SYSCALL_PWRITEV 96
#define SYSCALL_MAX_NUM 97 /* index of highest constant + 1 */
#endif

View File

@ -0,0 +1,40 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
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/>.
sortix/uio.h
Vector IO operations.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_UIO_H
#define INCLUDE_SORTIX_UIO_H
#include <features.h>
__BEGIN_DECLS
struct iovec
{
void* iov_base;
size_t iov_len;
};
__END_DECLS
#endif

View File

@ -37,6 +37,7 @@
#include <sortix/fcntl.h>
#include <sortix/stat.h>
#include <sortix/socket.h>
#include <sortix/uio.h>
#include <assert.h>
#include <errno.h>
@ -687,6 +688,169 @@ static ssize_t sys_send(int fd, const void* buffer, size_t count, int flags)
return desc->send(&ctx, (const uint8_t*) buffer, count, flags);
}
// TODO: We need to move these vector operations into the file descriptors or
// inodes themselves to ensure that they are atomic. Currently these
// operations may overlap and cause nasty bugs/race conditions when
// multiple threads concurrently operates on a file.
// TODO: There is quite a bit of boiler plate code here. Can we do better?
static struct iovec* FetchIOV(const struct iovec* user_iov, int iovcnt)
{
if ( iovcnt < 0 )
return errno = EINVAL, (struct iovec*) NULL;
struct iovec* ret = new struct iovec[iovcnt];
if ( !ret )
return NULL;
if ( !CopyFromUser(ret, user_iov, sizeof(struct iovec) * (size_t) iovcnt) )
{
delete[] ret;
return NULL;
}
return ret;
}
static ssize_t sys_readv(int fd, const struct iovec* user_iov, int iovcnt)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
struct iovec* iov = FetchIOV(user_iov, iovcnt);
if ( !iov )
return -1;
ssize_t so_far = 0;
for ( int i = 0; i < iovcnt && so_far != SSIZE_MAX; i++ )
{
uint8_t* buffer = (uint8_t*) iov[i].iov_base;
size_t amount = iov[i].iov_len;
ssize_t max_left = SSIZE_MAX - so_far;
if ( (size_t) max_left < amount )
amount = (size_t) max_left;
ssize_t num_bytes = desc->read(&ctx, buffer, amount);
if ( num_bytes < 0 )
{
delete[] iov;
return so_far ? so_far : -1;
}
if ( num_bytes == 0 )
break;
so_far += num_bytes;
// TODO: Is this the correct behavior?
if ( (size_t) num_bytes != amount )
break;
}
delete[] iov;
return so_far;
}
static ssize_t sys_preadv(int fd, const struct iovec* user_iov, int iovcnt,
off_t offset)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
struct iovec* iov = FetchIOV(user_iov, iovcnt);
if ( !iov )
return -1;
ssize_t so_far = 0;
for ( int i = 0; i < iovcnt && so_far != SSIZE_MAX; i++ )
{
uint8_t* buffer = (uint8_t*) iov[i].iov_base;
size_t amount = iov[i].iov_len;
ssize_t max_left = SSIZE_MAX - so_far;
if ( (size_t) max_left < amount )
amount = (size_t) max_left;
ssize_t num_bytes = desc->pread(&ctx, buffer, amount, offset + so_far);
if ( num_bytes < 0 )
{
delete[] iov;
return so_far ? so_far : -1;
}
if ( num_bytes == 0 )
break;
so_far += num_bytes;
// TODO: Is this the correct behavior?
if ( (size_t) num_bytes != amount )
break;
}
delete[] iov;
return so_far;
}
static ssize_t sys_writev(int fd, const struct iovec* user_iov, int iovcnt)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
struct iovec* iov = FetchIOV(user_iov, iovcnt);
if ( !iov )
return -1;
ssize_t so_far = 0;
for ( int i = 0; i < iovcnt && so_far != SSIZE_MAX; i++ )
{
const uint8_t* buffer = (const uint8_t*) iov[i].iov_base;
size_t amount = iov[i].iov_len;
ssize_t max_left = SSIZE_MAX - so_far;
if ( (size_t) max_left < amount )
amount = (size_t) max_left;
ssize_t num_bytes = desc->write(&ctx, buffer, amount);
if ( num_bytes < 0 )
{
delete[] iov;
return so_far ? so_far : -1;
}
if ( num_bytes == 0 )
break;
so_far += num_bytes;
// TODO: Is this the correct behavior?
if ( (size_t) num_bytes != amount )
break;
}
delete[] iov;
return so_far;
}
static ssize_t sys_pwritev(int fd, const struct iovec* user_iov, int iovcnt,
off_t offset)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
struct iovec* iov = FetchIOV(user_iov, iovcnt);
if ( !iov )
return -1;
ssize_t so_far = 0;
for ( int i = 0; i < iovcnt && so_far != SSIZE_MAX; i++ )
{
const uint8_t* buffer = (const uint8_t*) iov[i].iov_base;
size_t amount = iov[i].iov_len;
ssize_t max_left = SSIZE_MAX - so_far;
if ( (size_t) max_left < amount )
amount = (size_t) max_left;
ssize_t num_bytes = desc->pwrite(&ctx, buffer, amount, offset + so_far);
if ( num_bytes < 0 )
{
delete[] iov;
return so_far ? so_far : -1;
}
if ( num_bytes == 0 )
break;
so_far += num_bytes;
// TODO: Is this the correct behavior?
if ( (size_t) num_bytes != amount )
break;
}
delete[] iov;
return so_far;
}
void Init()
{
Syscall::Register(SYSCALL_ACCEPT4, (void*) sys_accept4);
@ -722,10 +886,13 @@ void Init()
Syscall::Register(SYSCALL_OPENAT, (void*) sys_openat);
Syscall::Register(SYSCALL_OPEN, (void*) sys_open);
Syscall::Register(SYSCALL_PREAD, (void*) sys_pread);
Syscall::Register(SYSCALL_PREADV, (void*) sys_preadv);
Syscall::Register(SYSCALL_PWRITE, (void*) sys_pwrite);
Syscall::Register(SYSCALL_PWRITEV, (void*) sys_pwritev);
Syscall::Register(SYSCALL_READDIRENTS, (void*) sys_readdirents);
Syscall::Register(SYSCALL_READLINKAT, (void*) sys_readlinkat);
Syscall::Register(SYSCALL_READ, (void*) sys_read);
Syscall::Register(SYSCALL_READV, (void*) sys_readv);
Syscall::Register(SYSCALL_RECV, (void*) sys_recv);
Syscall::Register(SYSCALL_RENAMEAT, (void*) sys_renameat);
Syscall::Register(SYSCALL_RMDIR, (void*) sys_rmdir);
@ -740,6 +907,7 @@ void Init()
Syscall::Register(SYSCALL_UNLINK, (void*) sys_unlink);
Syscall::Register(SYSCALL_UTIMENSAT, (void*) sys_utimensat);
Syscall::Register(SYSCALL_WRITE, (void*) sys_write);
Syscall::Register(SYSCALL_WRITEV, (void*) sys_writev);
}
} // namespace IO