diff --git a/libc/Makefile b/libc/Makefile
index 207fe962..84f2e49c 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -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) \
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
new file mode 100644
index 00000000..44616641
--- /dev/null
+++ b/libc/include/sys/uio.h
@@ -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 .
+
+ sys/uio.h
+ Vector IO operations.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SYS_UIO_H
+#define INCLUDE_SYS_UIO_H
+
+#include
+
+__BEGIN_DECLS
+
+@include(size_t.h)
+@include(ssize_t.h)
+@include(off_t.h)
+
+__END_DECLS
+
+#include
+
+__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
diff --git a/libc/preadv.cpp b/libc/preadv.cpp
new file mode 100644
index 00000000..0ae1c9d7
--- /dev/null
+++ b/libc/preadv.cpp
@@ -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 .
+
+ preadv.cpp
+ Read data into multiple buffers.
+
+*******************************************************************************/
+
+#include
+#include
+
+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);
+}
diff --git a/libc/pwritev.cpp b/libc/pwritev.cpp
new file mode 100644
index 00000000..ee6c3331
--- /dev/null
+++ b/libc/pwritev.cpp
@@ -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 .
+
+ pwritev.cpp
+ Write data from multiple buffers.
+
+*******************************************************************************/
+
+#include
+#include
+
+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);
+}
diff --git a/libc/readv.cpp b/libc/readv.cpp
new file mode 100644
index 00000000..b800b23c
--- /dev/null
+++ b/libc/readv.cpp
@@ -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 .
+
+ readv.cpp
+ Read data into multiple buffers.
+
+*******************************************************************************/
+
+#include
+#include
+
+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);
+}
diff --git a/libc/writev.cpp b/libc/writev.cpp
new file mode 100644
index 00000000..26066cdc
--- /dev/null
+++ b/libc/writev.cpp
@@ -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 .
+
+ writev.cpp
+ Write data from multiple buffers.
+
+*******************************************************************************/
+
+#include
+#include
+
+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);
+}
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index 64a2cf46..4e38b594 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -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
diff --git a/sortix/include/sortix/uio.h b/sortix/include/sortix/uio.h
new file mode 100644
index 00000000..78a9ecdb
--- /dev/null
+++ b/sortix/include/sortix/uio.h
@@ -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 .
+
+ sortix/uio.h
+ Vector IO operations.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SORTIX_UIO_H
+#define INCLUDE_SORTIX_UIO_H
+
+#include
+
+__BEGIN_DECLS
+
+struct iovec
+{
+ void* iov_base;
+ size_t iov_len;
+};
+
+__END_DECLS
+
+#endif
diff --git a/sortix/io.cpp b/sortix/io.cpp
index 020ea6b4..ba54a028 100644
--- a/sortix/io.cpp
+++ b/sortix/io.cpp
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include
#include
@@ -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 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 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 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 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