libc: implement 'readv()'
This patch implements the 'readv()' function in the libc. A lock guard prevents the parallel execution of either or both of the 'readv()' and 'writev()' functions. Fixes #279.
This commit is contained in:
parent
9124f303f7
commit
dbd1c425bf
|
@ -14,7 +14,7 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc munmap.cc \
|
||||||
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
|
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
|
||||||
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
|
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
|
||||||
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
|
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
|
||||||
libc_mem_alloc.cc writev.cc pread_pwrite.cc
|
libc_mem_alloc.cc pread_pwrite.cc readv_writev.cc
|
||||||
|
|
||||||
#
|
#
|
||||||
# Files from string library that are not included in libc-raw_string because
|
# Files from string library that are not included in libc-raw_string because
|
||||||
|
|
117
libports/src/lib/libc/readv_writev.cc
Normal file
117
libports/src/lib/libc/readv_writev.cc
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* \brief 'readv()' and 'writev()' implementations
|
||||||
|
* \author Josef Soentgen
|
||||||
|
* \author Christian Prochaska
|
||||||
|
* \date 2012-04-10
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/lock.h>
|
||||||
|
|
||||||
|
/* libc includes */
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
static Genode::Lock rw_lock;
|
||||||
|
|
||||||
|
|
||||||
|
struct Read
|
||||||
|
{
|
||||||
|
ssize_t operator()(int fd, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
return read(fd, buf, count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Write
|
||||||
|
{
|
||||||
|
ssize_t operator()(int fd, const void *buf, size_t count)
|
||||||
|
{
|
||||||
|
return write(fd, buf, count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Rw_func>
|
||||||
|
static ssize_t readv_writev_impl(Rw_func rw_func, int fd, const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
Genode::Lock_guard<Genode::Lock> rw_lock_guard(rw_lock);
|
||||||
|
|
||||||
|
char *v;
|
||||||
|
ssize_t bytes_transfered_total = 0;
|
||||||
|
size_t v_len = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (iovcnt < 1 || iovcnt > IOV_MAX) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < iovcnt; i++)
|
||||||
|
v_len += iov->iov_len;
|
||||||
|
|
||||||
|
if (v_len > SSIZE_MAX) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (iovcnt > 0) {
|
||||||
|
v = static_cast<char *>(iov->iov_base);
|
||||||
|
v_len = iov->iov_len;
|
||||||
|
|
||||||
|
while (v_len > 0) {
|
||||||
|
ssize_t bytes_transfered = rw_func(fd, v, v_len);
|
||||||
|
|
||||||
|
if (bytes_transfered == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (bytes_transfered == 0)
|
||||||
|
return bytes_transfered_total;
|
||||||
|
|
||||||
|
v_len -= bytes_transfered;
|
||||||
|
v += bytes_transfered;
|
||||||
|
bytes_transfered_total += bytes_transfered;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov++;
|
||||||
|
iovcnt--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_transfered_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" ssize_t _readv(int fd, const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return readv_writev_impl(Read(), fd, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return _readv(fd, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" ssize_t _writev(int fd, const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return readv_writev_impl(Write(), fd, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return _writev(fd, iov, iovcnt);
|
||||||
|
}
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Plugin implementation
|
|
||||||
* \author Josef Soentgen
|
|
||||||
* \date 2012-04-10
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-2012 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU General Public License version 2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
enum { MAX_BUFFER_LEN = 2048 };
|
|
||||||
|
|
||||||
extern "C" int _writev(int d, const struct iovec *iov, int iovcnt)
|
|
||||||
{
|
|
||||||
char buffer[MAX_BUFFER_LEN];
|
|
||||||
char *v, *b;
|
|
||||||
ssize_t written;
|
|
||||||
size_t v_len, _len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (iovcnt < 1 || iovcnt > IOV_MAX) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < iovcnt; i++)
|
|
||||||
v_len += iov->iov_len;
|
|
||||||
|
|
||||||
if (v_len > SSIZE_MAX) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
b = buffer;
|
|
||||||
while (iovcnt) {
|
|
||||||
v = static_cast<char *>(iov->iov_base);
|
|
||||||
v_len = iov->iov_len;
|
|
||||||
|
|
||||||
while (v_len > 0) {
|
|
||||||
if (v_len < sizeof(buffer))
|
|
||||||
_len = v_len;
|
|
||||||
else
|
|
||||||
_len = sizeof(buffer);
|
|
||||||
|
|
||||||
// TODO error check
|
|
||||||
memmove(b, v, _len);
|
|
||||||
i = write(d, b, _len);
|
|
||||||
v += _len;
|
|
||||||
v_len -= _len;
|
|
||||||
|
|
||||||
written += i;
|
|
||||||
}
|
|
||||||
|
|
||||||
iov++;
|
|
||||||
iovcnt--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" ssize_t writev(int d, const struct iovec *iov, int iovcnt)
|
|
||||||
{
|
|
||||||
return _writev(d, iov, iovcnt);
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -44,6 +45,7 @@ int main(int argc, char *argv[])
|
||||||
char const *dir_name = "/testdir";
|
char const *dir_name = "/testdir";
|
||||||
char const *file_name = "test.tst";
|
char const *file_name = "test.tst";
|
||||||
char const *file_name2 = "test2.tst";
|
char const *file_name2 = "test2.tst";
|
||||||
|
char const *file_name3 = "test3.tst";
|
||||||
char const *pattern = "a single line of text";
|
char const *pattern = "a single line of text";
|
||||||
|
|
||||||
size_t pattern_size = strlen(pattern) + 1;
|
size_t pattern_size = strlen(pattern) + 1;
|
||||||
|
@ -109,6 +111,35 @@ int main(int argc, char *argv[])
|
||||||
printf("file content is correct\n");
|
printf("file content is correct\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test 'readv()' and 'writev()' */
|
||||||
|
CALL_AND_CHECK(fd, open(file_name3, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name);
|
||||||
|
struct iovec iov[2];
|
||||||
|
/* write "a single line" */
|
||||||
|
iov[0].iov_base = (void*)pattern;
|
||||||
|
iov[0].iov_len = 13;
|
||||||
|
/* write " line of text" */
|
||||||
|
iov[1].iov_base = (void*)&pattern[8];
|
||||||
|
iov[1].iov_len = pattern_size - 8;
|
||||||
|
CALL_AND_CHECK(count, writev(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
|
||||||
|
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
|
||||||
|
CALL_AND_CHECK(fd, open(file_name3, O_RDONLY), fd >= 0, "file_name=%s", file_name);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
/* read "a single line" */
|
||||||
|
iov[0].iov_base = buf;
|
||||||
|
iov[0].iov_len = 13;
|
||||||
|
/* read " line of text" to offset 8 */
|
||||||
|
iov[1].iov_base = &buf[8];
|
||||||
|
iov[1].iov_len = pattern_size;
|
||||||
|
CALL_AND_CHECK(count, readv(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
|
||||||
|
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
|
||||||
|
printf("content of buffer: \"%s\"\n", buf);
|
||||||
|
if (strcmp(buf, pattern) != 0) {
|
||||||
|
printf("unexpected content of file\n");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
printf("file content is correct\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* read directory entries */
|
/* read directory entries */
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
CALL_AND_CHECK(dir, opendir(dir_name), dir, "dir_name=\"%s\"", dir_name);
|
CALL_AND_CHECK(dir, opendir(dir_name), dir, "dir_name=\"%s\"", dir_name);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user