mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add {,p}{read,write}v(2).
This commit is contained in:
parent
b3e7aafff8
commit
ef32b3fcbe
9 changed files with 402 additions and 3 deletions
|
@ -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
49
libc/include/sys/uio.h
Normal 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
34
libc/preadv.cpp
Normal 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
34
libc/pwritev.cpp
Normal 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
33
libc/readv.cpp
Normal 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
33
libc/writev.cpp
Normal 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);
|
||||
}
|
|
@ -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
|
||||
|
|
40
sortix/include/sortix/uio.h
Normal file
40
sortix/include/sortix/uio.h
Normal 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
|
168
sortix/io.cpp
168
sortix/io.cpp
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue