Move readv/writev family and sendmsg/recvmsg into drivers.
This commit is contained in:
parent
28229eb6e6
commit
7a8a71674e
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -17,16 +17,22 @@
|
||||||
* A file descriptor.
|
* A file descriptor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fsmarshall-msg.h>
|
#include <fsmarshall-msg.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sortix/dirent.h>
|
#include <sortix/dirent.h>
|
||||||
#include <sortix/fcntl.h>
|
#include <sortix/fcntl.h>
|
||||||
|
#ifndef IOV_MAX
|
||||||
|
#include <sortix/limits.h>
|
||||||
|
#endif
|
||||||
#include <sortix/mount.h>
|
#include <sortix/mount.h>
|
||||||
#include <sortix/seek.h>
|
#include <sortix/seek.h>
|
||||||
#include <sortix/stat.h>
|
#include <sortix/stat.h>
|
||||||
|
@ -293,6 +299,36 @@ ssize_t Descriptor::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::readv(ioctx_t* ctx, const struct iovec* iov_ptr, int iovcnt)
|
||||||
|
{
|
||||||
|
if ( !(dflags & O_READ) )
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
if ( iovcnt < 0 || IOV_MAX < iovcnt )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
struct iovec* iov = new struct iovec[iovcnt];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
size_t iov_size = sizeof(struct iovec) * iovcnt;
|
||||||
|
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( !IsSeekable() )
|
||||||
|
{
|
||||||
|
ssize_t result = vnode->readv(ctx, iov, iovcnt);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ScopedLock lock(¤t_offset_lock);
|
||||||
|
ssize_t ret = vnode->preadv(ctx, iov, iovcnt, current_offset);
|
||||||
|
if ( 0 <= ret )
|
||||||
|
current_offset += ret;
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
if ( !(dflags & O_READ) )
|
if ( !(dflags & O_READ) )
|
||||||
|
@ -310,6 +346,27 @@ ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::preadv(ioctx_t* ctx, const struct iovec* iov_ptr,
|
||||||
|
int iovcnt, off_t off)
|
||||||
|
{
|
||||||
|
if ( !(dflags & O_READ) )
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
if ( off < 0 || iovcnt < 0 || IOV_MAX < iovcnt )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
struct iovec* iov = new struct iovec[iovcnt];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
size_t iov_size = sizeof(struct iovec) * iovcnt;
|
||||||
|
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->preadv(ctx, iov, iovcnt, off);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
{
|
{
|
||||||
if ( !(dflags & O_WRITE) )
|
if ( !(dflags & O_WRITE) )
|
||||||
|
@ -344,7 +401,49 @@ ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
ssize_t Descriptor::writev(ioctx_t* ctx, const struct iovec* iov_ptr,
|
||||||
|
int iovcnt)
|
||||||
|
{
|
||||||
|
if ( !(dflags & O_WRITE) )
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
if ( iovcnt < 0 || IOV_MAX < iovcnt )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
struct iovec* iov = new struct iovec[iovcnt];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
size_t iov_size = sizeof(struct iovec) * iovcnt;
|
||||||
|
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( !IsSeekable() )
|
||||||
|
{
|
||||||
|
ssize_t result = vnode->writev(ctx, iov, iovcnt);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
ScopedLock lock(¤t_offset_lock);
|
||||||
|
if ( ctx->dflags & O_APPEND )
|
||||||
|
{
|
||||||
|
off_t end = vnode->lseek(ctx, 0, SEEK_END);
|
||||||
|
if ( end < 0 )
|
||||||
|
{
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
current_offset = end;
|
||||||
|
}
|
||||||
|
ssize_t ret = vnode->pwritev(ctx, iov, iovcnt, current_offset);
|
||||||
|
if ( 0 <= ret )
|
||||||
|
current_offset += ret;
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
|
off_t off)
|
||||||
{
|
{
|
||||||
if ( !(dflags & O_WRITE) )
|
if ( !(dflags & O_WRITE) )
|
||||||
return errno = EPERM, -1;
|
return errno = EPERM, -1;
|
||||||
|
@ -361,6 +460,27 @@ ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::pwritev(ioctx_t* ctx, const struct iovec* iov_ptr,
|
||||||
|
int iovcnt, off_t off)
|
||||||
|
{
|
||||||
|
if ( !(dflags & O_WRITE) )
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
if ( off < 0 || iovcnt < 0 || IOV_MAX < iovcnt )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
struct iovec* iov = new struct iovec[iovcnt];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
size_t iov_size = sizeof(struct iovec) * iovcnt;
|
||||||
|
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->pwritev(ctx, iov, iovcnt, off);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
delete[] iov;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool valid_utimens_timespec(struct timespec ts)
|
static inline bool valid_utimens_timespec(struct timespec ts)
|
||||||
{
|
{
|
||||||
return ts.tv_nsec < 1000000000 ||
|
return ts.tv_nsec < 1000000000 ||
|
||||||
|
@ -755,22 +875,56 @@ int Descriptor::listen(ioctx_t* ctx, int backlog)
|
||||||
|
|
||||||
ssize_t Descriptor::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
|
ssize_t Descriptor::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
|
||||||
{
|
{
|
||||||
|
if ( SIZE_MAX < count )
|
||||||
|
count = SSIZE_MAX;
|
||||||
int old_ctx_dflags = ctx->dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( flags & MSG_DONTWAIT )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
flags &= ~MSG_DONTWAIT;
|
||||||
ssize_t result = vnode->recv(ctx, buf, count, flags);
|
ssize_t result = vnode->recv(ctx, buf, count, flags);
|
||||||
ctx->dflags = old_ctx_dflags;
|
ctx->dflags = old_ctx_dflags;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( flags & MSG_DONTWAIT )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
flags &= ~MSG_DONTWAIT;
|
||||||
|
ssize_t result = vnode->recvmsg(ctx, msg, flags);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Descriptor::send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags)
|
ssize_t Descriptor::send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags)
|
||||||
{
|
{
|
||||||
|
if ( SIZE_MAX < count )
|
||||||
|
count = SSIZE_MAX;
|
||||||
int old_ctx_dflags = ctx->dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( flags & MSG_DONTWAIT )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
flags &= ~MSG_DONTWAIT;
|
||||||
ssize_t result = vnode->send(ctx, buf, count, flags);
|
ssize_t result = vnode->send(ctx, buf, count, flags);
|
||||||
ctx->dflags = old_ctx_dflags;
|
ctx->dflags = old_ctx_dflags;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Descriptor::sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
if ( flags & MSG_DONTWAIT )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
flags &= ~MSG_DONTWAIT;
|
||||||
|
ssize_t result = vnode->sendmsg(ctx, msg, flags);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int Descriptor::getsockopt(ioctx_t* ctx, int level, int option_name,
|
int Descriptor::getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr)
|
void* option_value, size_t* option_size_ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2013, 2014, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -309,91 +310,118 @@ void FileCache::InitializeFileData(off_t to_where)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t FileCache::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
ssize_t FileCache::preadv(ioctx_t* ctx, const struct iovec* iovs, int iovcnt,
|
||||||
|
off_t off)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&fcache_mutex);
|
ScopedLock lock(&fcache_mutex);
|
||||||
if ( off < 0 )
|
ssize_t so_far = 0;
|
||||||
return errno = EINVAL, -1;
|
int iov_i = 0;
|
||||||
if ( file_size <= off )
|
size_t iov_offset = 0;
|
||||||
return 0;
|
while ( iov_i < iovcnt && so_far < SSIZE_MAX )
|
||||||
off_t available_bytes = file_size - off;
|
|
||||||
if ( (uintmax_t) available_bytes < (uintmax_t) count )
|
|
||||||
count = available_bytes;
|
|
||||||
if ( (size_t) SSIZE_MAX < count )
|
|
||||||
count = (size_t) SSIZE_MAX;
|
|
||||||
size_t sofar = 0;
|
|
||||||
while ( sofar < count )
|
|
||||||
{
|
{
|
||||||
off_t current_off = off + (off_t) sofar;
|
off_t current_off = off + (off_t) so_far;
|
||||||
size_t left = count - sofar;
|
if ( file_size <= current_off )
|
||||||
|
break;
|
||||||
|
size_t maxcount = SSIZE_MAX - so_far;
|
||||||
|
if ( (uintmax_t) (file_size - current_off) < maxcount )
|
||||||
|
maxcount = file_size - current_off;
|
||||||
|
if ( maxcount == 0 )
|
||||||
|
break;
|
||||||
|
const struct iovec* iov = &iovs[iov_i];
|
||||||
|
uint8_t* buf = (uint8_t*) iov->iov_base + iov_offset;
|
||||||
|
size_t count = iov->iov_len - iov_offset;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
if ( count == 0 )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
size_t block_off = (size_t) (current_off % Page::Size());
|
size_t block_off = (size_t) (current_off % Page::Size());
|
||||||
size_t block_num = (size_t) (current_off / Page::Size());
|
size_t block_num = (size_t) (current_off / Page::Size());
|
||||||
size_t block_left = Page::Size() - block_off;
|
size_t block_left = Page::Size() - block_off;
|
||||||
size_t amount_to_copy = left < block_left ? left : block_left;
|
size_t amount = count < block_left ? count : block_left;
|
||||||
assert(block_num < blocks_used);
|
assert(block_num < blocks_used);
|
||||||
BlockCacheBlock* block = blocks[block_num];
|
BlockCacheBlock* block = blocks[block_num];
|
||||||
const uint8_t* block_data = kernel_block_cache->BlockData(block);
|
const uint8_t* block_data = kernel_block_cache->BlockData(block);
|
||||||
const uint8_t* src_data = block_data + block_off;
|
const uint8_t* src_data = block_data + block_off;
|
||||||
uint8_t* dest_buf = buf + sofar;
|
if ( file_written < current_off + (off_t) amount )
|
||||||
off_t end_at = current_off + (off_t) amount_to_copy;
|
InitializeFileData(current_off + (off_t) amount);
|
||||||
if ( file_written < end_at )
|
if ( !ctx->copy_to_dest(buf, src_data, amount) )
|
||||||
InitializeFileData(end_at);
|
return so_far ? (ssize_t) so_far : -1;
|
||||||
if ( !ctx->copy_to_dest(dest_buf, src_data, amount_to_copy) )
|
so_far += amount;
|
||||||
return sofar ? (ssize_t) sofar : -1;
|
|
||||||
sofar += amount_to_copy;
|
|
||||||
kernel_block_cache->MarkUsed(block);
|
kernel_block_cache->MarkUsed(block);
|
||||||
|
iov_offset += amount;
|
||||||
|
if ( iov_offset == iov->iov_len )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
}
|
}
|
||||||
return (ssize_t) sofar;
|
}
|
||||||
|
return so_far;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t FileCache::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
ssize_t FileCache::pwritev(ioctx_t* ctx, const struct iovec* iovs, int iovcnt,
|
||||||
|
off_t off)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&fcache_mutex);
|
ScopedLock lock(&fcache_mutex);
|
||||||
if ( off < 0 )
|
ssize_t so_far = 0;
|
||||||
return errno = EINVAL, -1;
|
int iov_i = 0;
|
||||||
off_t available_growth = OFF_MAX - off;
|
size_t iov_offset = 0;
|
||||||
if ( (uintmax_t) available_growth < (uintmax_t) count )
|
while ( iov_i < iovcnt && so_far < SSIZE_MAX )
|
||||||
count = (size_t) available_growth;
|
{
|
||||||
// TODO: Rather than doing an EOF - shouldn't errno be set to something like
|
off_t current_off = off + (off_t) so_far;
|
||||||
// "Hey, the filesize limit has been reached"?
|
size_t maxcount = SSIZE_MAX - so_far;
|
||||||
if ( (size_t) SSIZE_MAX < count )
|
if ( (uintmax_t) (OFF_MAX - current_off) < maxcount )
|
||||||
count = (size_t) SSIZE_MAX;
|
maxcount = OFF_MAX - current_off;
|
||||||
off_t write_end = off + (off_t) count;
|
const struct iovec* iov = &iovs[iov_i];
|
||||||
|
uint8_t* buf = (uint8_t*) iov->iov_base + iov_offset;
|
||||||
|
size_t count = iov->iov_len - iov_offset;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
if ( count == 0 )
|
||||||
|
{
|
||||||
|
if ( so_far == 0 && maxcount == 0 && iov->iov_len != 0 )
|
||||||
|
return errno = ENOSPC, -1;
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
off_t write_end = current_off + count;
|
||||||
if ( file_size < write_end && !ChangeSize(write_end, false) )
|
if ( file_size < write_end && !ChangeSize(write_end, false) )
|
||||||
{
|
{
|
||||||
if ( file_size < off )
|
if ( file_size <= current_off )
|
||||||
return -1;
|
return -1;
|
||||||
count = (size_t) (file_size - off);
|
if ( (uintmax_t) (file_size - current_off) < count )
|
||||||
write_end = off + (off_t) count;
|
count = file_size - current_off;
|
||||||
}
|
}
|
||||||
assert(write_end <= file_size);
|
|
||||||
size_t sofar = 0;
|
|
||||||
while ( sofar < count )
|
|
||||||
{
|
|
||||||
off_t current_off = off + (off_t) sofar;
|
|
||||||
size_t left = count - sofar;
|
|
||||||
size_t block_off = (size_t) (current_off % Page::Size());
|
size_t block_off = (size_t) (current_off % Page::Size());
|
||||||
size_t block_num = (size_t) (current_off / Page::Size());
|
size_t block_num = (size_t) (current_off / Page::Size());
|
||||||
size_t block_left = Page::Size() - block_off;
|
size_t block_left = Page::Size() - block_off;
|
||||||
size_t amount_to_copy = left < block_left ? left : block_left;
|
size_t amount = count < block_left ? count : block_left;
|
||||||
assert(block_num < blocks_used);
|
assert(block_num < blocks_used);
|
||||||
BlockCacheBlock* block = blocks[block_num];
|
BlockCacheBlock* block = blocks[block_num];
|
||||||
uint8_t* block_data = kernel_block_cache->BlockData(block);
|
uint8_t* block_data = kernel_block_cache->BlockData(block);
|
||||||
uint8_t* data = block_data + block_off;
|
uint8_t* data = block_data + block_off;
|
||||||
const uint8_t* src_buf = buf + sofar;
|
if ( file_written < current_off )
|
||||||
off_t begin_at = off + (off_t) sofar;
|
InitializeFileData(current_off);
|
||||||
off_t end_at = current_off + (off_t) amount_to_copy;
|
assert(amount);
|
||||||
if ( file_written < begin_at )
|
|
||||||
InitializeFileData(begin_at);
|
|
||||||
modified = true; /* Unconditionally - copy_from_src can fail midway. */
|
modified = true; /* Unconditionally - copy_from_src can fail midway. */
|
||||||
if ( !ctx->copy_from_src(data, src_buf, amount_to_copy) )
|
if ( !ctx->copy_from_src(data, buf, amount) )
|
||||||
return sofar ? (ssize_t) sofar : -1;
|
return so_far ? (ssize_t) so_far : -1;
|
||||||
if ( file_written < end_at )
|
if ( file_written < current_off + (off_t) amount )
|
||||||
file_written = end_at;
|
file_written = current_off + (off_t) amount;
|
||||||
sofar += amount_to_copy;
|
so_far += amount;
|
||||||
kernel_block_cache->MarkModified(block);
|
kernel_block_cache->MarkModified(block);
|
||||||
|
iov_offset += amount;
|
||||||
|
if ( iov_offset == iov->iov_len )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
}
|
}
|
||||||
return (ssize_t) sofar;
|
}
|
||||||
|
return so_far;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCache::truncate(ioctx_t* /*ctx*/, off_t length)
|
int FileCache::truncate(ioctx_t* /*ctx*/, off_t length)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -124,6 +125,7 @@ File::File(InodeType inode_type, mode_t type, dev_t dev, ino_t ino, uid_t owner,
|
||||||
this->stat_blksize = 1;
|
this->stat_blksize = 1;
|
||||||
this->dev = dev;
|
this->dev = dev;
|
||||||
this->ino = ino;
|
this->ino = ino;
|
||||||
|
this->supports_iovec = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
File::~File()
|
File::~File()
|
||||||
|
@ -147,14 +149,16 @@ off_t File::lseek(ioctx_t* ctx, off_t offset, int whence)
|
||||||
return fcache.lseek(ctx, offset, whence);
|
return fcache.lseek(ctx, offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t File::pread(ioctx_t* ctx, uint8_t* dest, size_t count, off_t off)
|
ssize_t File::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
{
|
{
|
||||||
return fcache.pread(ctx, dest, count, off);
|
return fcache.preadv(ctx, iov, iovcnt, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t File::pwrite(ioctx_t* ctx, const uint8_t* src, size_t count, off_t off)
|
ssize_t File::pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
{
|
{
|
||||||
ssize_t ret = fcache.pwrite(ctx, src, count, off);
|
ssize_t ret = fcache.pwritev(ctx, iov, iovcnt, off);
|
||||||
if ( 0 < ret )
|
if ( 0 < ret )
|
||||||
{
|
{
|
||||||
ScopedLock lock(&metalock);
|
ScopedLock lock(&metalock);
|
||||||
|
@ -170,7 +174,11 @@ ssize_t File::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
|
||||||
return errno = EINVAL, -1;
|
return errno = EINVAL, -1;
|
||||||
if ( (size_t) SSIZE_MAX < bufsize )
|
if ( (size_t) SSIZE_MAX < bufsize )
|
||||||
bufsize = SSIZE_MAX;
|
bufsize = SSIZE_MAX;
|
||||||
return fcache.pread(ctx, (uint8_t*) buf, bufsize, 0);
|
struct iovec iov;
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = buf;
|
||||||
|
iov.iov_len = bufsize;
|
||||||
|
return fcache.preadv(ctx, &iov, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t File::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count)
|
ssize_t File::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count)
|
||||||
|
|
|
@ -41,9 +41,9 @@ public:
|
||||||
virtual ~File();
|
virtual ~File();
|
||||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
off_t off);
|
off_t off);
|
||||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
off_t off);
|
off_t off);
|
||||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||||
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer,
|
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -204,11 +204,17 @@ public:
|
||||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
|
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||||
|
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
off_t off);
|
off_t off);
|
||||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
off_t off);
|
off_t off);
|
||||||
|
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
|
|
||||||
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
|
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
|
||||||
virtual int isatty(ioctx_t* ctx);
|
virtual int isatty(ioctx_t* ctx);
|
||||||
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
||||||
|
@ -242,8 +248,10 @@ public:
|
||||||
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
||||||
virtual int listen(ioctx_t* ctx, int backlog);
|
virtual int listen(ioctx_t* ctx, int backlog);
|
||||||
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
virtual ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
int flags);
|
int flags);
|
||||||
|
virtual ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr);
|
void* option_value, size_t* option_size_ptr);
|
||||||
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
|
@ -898,6 +906,32 @@ ssize_t Unode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = read(ctx, buf, count);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
Channel* channel = server->Connect(ctx);
|
Channel* channel = server->Connect(ctx);
|
||||||
|
@ -921,6 +955,36 @@ ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
off_t offset;
|
||||||
|
if ( __builtin_add_overflow(off, sofar, &offset) )
|
||||||
|
return sofar ? sofar : (errno = EOVERFLOW, -1);
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = pread(ctx, buf, count, offset);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
{
|
{
|
||||||
Channel* channel = server->Connect(ctx);
|
Channel* channel = server->Connect(ctx);
|
||||||
|
@ -945,6 +1009,32 @@ ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
const uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = write(ctx, buf, count);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
Channel* channel = server->Connect(ctx);
|
Channel* channel = server->Connect(ctx);
|
||||||
|
@ -970,6 +1060,36 @@ ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
off_t offset;
|
||||||
|
if ( __builtin_add_overflow(off, sofar, &offset) )
|
||||||
|
return sofar ? sofar : (errno = EOVERFLOW, -1);
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = pwrite(ctx, buf, count, offset);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
int Unode::utimens(ioctx_t* ctx, const struct timespec* times)
|
int Unode::utimens(ioctx_t* ctx, const struct timespec* times)
|
||||||
{
|
{
|
||||||
Channel* channel = server->Connect(ctx);
|
Channel* channel = server->Connect(ctx);
|
||||||
|
@ -1368,12 +1488,23 @@ ssize_t Unode::recv(ioctx_t* /*ctx*/, uint8_t* /*buf*/, size_t /*count*/,
|
||||||
return errno = ENOTSOCK, -1;
|
return errno = ENOTSOCK, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::recvmsg(ioctx_t* /*ctx*/, struct msghdr* /*msg*/, int /*flags*/)
|
||||||
|
{
|
||||||
|
return errno = ENOTSOCK, -1;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Unode::send(ioctx_t* /*ctx*/, const uint8_t* /*buf*/, size_t /*count*/,
|
ssize_t Unode::send(ioctx_t* /*ctx*/, const uint8_t* /*buf*/, size_t /*count*/,
|
||||||
int /*flags*/)
|
int /*flags*/)
|
||||||
{
|
{
|
||||||
return errno = ENOTSOCK, -1;
|
return errno = ENOTSOCK, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Unode::sendmsg(ioctx_t* /*ctx*/, const struct msghdr* /*msg*/,
|
||||||
|
int /*flags*/)
|
||||||
|
{
|
||||||
|
return errno = ENOTSOCK, -1;
|
||||||
|
}
|
||||||
|
|
||||||
int Unode::getsockopt(ioctx_t* ctx, int level, int option_name,
|
int Unode::getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr)
|
void* option_value, size_t* option_size_ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -30,6 +30,8 @@
|
||||||
#include <sortix/kernel/refcount.h>
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
struct dirent;
|
struct dirent;
|
||||||
|
struct iovec;
|
||||||
|
struct msghdr;
|
||||||
struct stat;
|
struct stat;
|
||||||
struct statvfs;
|
struct statvfs;
|
||||||
struct termios;
|
struct termios;
|
||||||
|
@ -64,9 +66,15 @@ public:
|
||||||
int truncate(ioctx_t* ctx, off_t length);
|
int truncate(ioctx_t* ctx, off_t length);
|
||||||
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
|
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||||
|
ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
|
ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
||||||
|
ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
int utimens(ioctx_t* ctx, const struct timespec* times);
|
int utimens(ioctx_t* ctx, const struct timespec* times);
|
||||||
int isatty(ioctx_t* ctx);
|
int isatty(ioctx_t* ctx);
|
||||||
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size);
|
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size);
|
||||||
|
@ -92,7 +100,9 @@ public:
|
||||||
int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
||||||
int listen(ioctx_t* ctx, int backlog);
|
int listen(ioctx_t* ctx, int backlog);
|
||||||
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
int getsockopt(ioctx_t* ctx, int level, int option_name,
|
int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr);
|
void* option_value, size_t* option_size_ptr);
|
||||||
int setsockopt(ioctx_t* ctx, int level, int option_name,
|
int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2013, 2014, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -29,6 +29,8 @@
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#include <sortix/kernel/memorymanagement.h>
|
#include <sortix/kernel/memorymanagement.h>
|
||||||
|
|
||||||
|
struct iovec;
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
struct ioctx_struct;
|
struct ioctx_struct;
|
||||||
|
@ -102,8 +104,10 @@ public:
|
||||||
FileCache(/*FileCacheBackend* backend = NULL*/);
|
FileCache(/*FileCacheBackend* backend = NULL*/);
|
||||||
~FileCache();
|
~FileCache();
|
||||||
int sync(ioctx_t* ctx);
|
int sync(ioctx_t* ctx);
|
||||||
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
off_t off);
|
||||||
|
ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
int truncate(ioctx_t* ctx, off_t length);
|
int truncate(ioctx_t* ctx, off_t length);
|
||||||
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
//bool ChangeBackend(FileCacheBackend* backend, bool sync_old);
|
//bool ChangeBackend(FileCacheBackend* backend, bool sync_old);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -30,6 +30,8 @@
|
||||||
#include <sortix/kernel/refcount.h>
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
struct dirent;
|
struct dirent;
|
||||||
|
struct iovec;
|
||||||
|
struct msghdr;
|
||||||
struct stat;
|
struct stat;
|
||||||
struct statvfs;
|
struct statvfs;
|
||||||
struct termios;
|
struct termios;
|
||||||
|
@ -62,11 +64,19 @@ public:
|
||||||
virtual int truncate(ioctx_t* ctx, off_t length) = 0;
|
virtual int truncate(ioctx_t* ctx, off_t length) = 0;
|
||||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence) = 0;
|
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence) = 0;
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count) = 0;
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count) = 0;
|
||||||
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov,
|
||||||
|
int iovcnt) = 0;
|
||||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||||
off_t off) = 0;
|
off_t off) = 0;
|
||||||
|
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off) = 0;
|
||||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count) = 0;
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count) = 0;
|
||||||
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov,
|
||||||
|
int iovcnt) = 0;
|
||||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
off_t off) = 0;
|
off_t off) = 0;
|
||||||
|
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off) = 0;
|
||||||
virtual int utimens(ioctx_t* ctx, const struct timespec* times) = 0;
|
virtual int utimens(ioctx_t* ctx, const struct timespec* times) = 0;
|
||||||
virtual int isatty(ioctx_t* ctx) = 0;
|
virtual int isatty(ioctx_t* ctx) = 0;
|
||||||
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
||||||
|
@ -100,8 +110,11 @@ public:
|
||||||
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen) = 0;
|
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen) = 0;
|
||||||
virtual int listen(ioctx_t* ctx, int backlog) = 0;
|
virtual int listen(ioctx_t* ctx, int backlog) = 0;
|
||||||
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags) = 0;
|
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags) = 0;
|
||||||
|
virtual ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags) = 0;
|
||||||
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
int flags) = 0;
|
int flags) = 0;
|
||||||
|
virtual ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg,
|
||||||
|
int flags) = 0;
|
||||||
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr) = 0;
|
void* option_value, size_t* option_size_ptr) = 0;
|
||||||
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
|
@ -144,6 +157,7 @@ protected:
|
||||||
struct timespec stat_ctim;
|
struct timespec stat_ctim;
|
||||||
blksize_t stat_blksize;
|
blksize_t stat_blksize;
|
||||||
blkcnt_t stat_blocks;
|
blkcnt_t stat_blocks;
|
||||||
|
bool supports_iovec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractInode();
|
AbstractInode();
|
||||||
|
@ -158,10 +172,16 @@ public:
|
||||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||||
|
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
off_t off);
|
off_t off);
|
||||||
|
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
|
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
|
||||||
virtual int isatty(ioctx_t* ctx);
|
virtual int isatty(ioctx_t* ctx);
|
||||||
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
|
||||||
|
@ -195,8 +215,10 @@ public:
|
||||||
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
||||||
virtual int listen(ioctx_t* ctx, int backlog);
|
virtual int listen(ioctx_t* ctx, int backlog);
|
||||||
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
virtual ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
int flags);
|
int flags);
|
||||||
|
virtual ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr);
|
void* option_value, size_t* option_size_ptr);
|
||||||
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 2012, 2013, 2014, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -25,6 +25,9 @@
|
||||||
#include <sortix/kernel/ioctx.h>
|
#include <sortix/kernel/ioctx.h>
|
||||||
#include <sortix/kernel/poll.h>
|
#include <sortix/kernel/poll.h>
|
||||||
|
|
||||||
|
struct msghdr;
|
||||||
|
struct iovec;
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class PipeChannel;
|
class PipeChannel;
|
||||||
|
@ -40,8 +43,12 @@ public:
|
||||||
bool SetSIGPIPEDelivery(bool deliver_sigpipe);
|
bool SetSIGPIPEDelivery(bool deliver_sigpipe);
|
||||||
size_t Size();
|
size_t Size();
|
||||||
bool Resize(size_t new_size);
|
bool Resize(size_t new_size);
|
||||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
|
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
|
ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
int poll(ioctx_t* ctx, PollNode* node);
|
int poll(ioctx_t* ctx, PollNode* node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -29,6 +29,8 @@
|
||||||
#include <sortix/kernel/refcount.h>
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
struct dirent;
|
struct dirent;
|
||||||
|
struct iovec;
|
||||||
|
struct msghdr;
|
||||||
struct stat;
|
struct stat;
|
||||||
struct statvfs;
|
struct statvfs;
|
||||||
struct termios;
|
struct termios;
|
||||||
|
@ -61,9 +63,15 @@ public:
|
||||||
int truncate(ioctx_t* ctx, off_t length);
|
int truncate(ioctx_t* ctx, off_t length);
|
||||||
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
|
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||||
|
ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
|
ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
||||||
|
ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off);
|
||||||
int utimens(ioctx_t* ctx, const struct timespec* times);
|
int utimens(ioctx_t* ctx, const struct timespec* times);
|
||||||
int isatty(ioctx_t* ctx);
|
int isatty(ioctx_t* ctx);
|
||||||
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
|
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
|
||||||
|
@ -90,7 +98,9 @@ public:
|
||||||
int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
|
||||||
int listen(ioctx_t* ctx, int backlog);
|
int listen(ioctx_t* ctx, int backlog);
|
||||||
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
int getsockopt(ioctx_t* ctx, int level, int option_name,
|
int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr);
|
void* option_value, size_t* option_size_ptr);
|
||||||
int setsockopt(ioctx_t* ctx, int level, int option_name,
|
int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#if __USE_SORTIX || __USE_POSIX
|
#if __USE_SORTIX || __USE_POSIX
|
||||||
#define HOST_NAME_MAX 255
|
#define HOST_NAME_MAX 255
|
||||||
#define TTY_NAME_MAX 32
|
#define TTY_NAME_MAX 32
|
||||||
|
#define IOV_MAX 1024
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
196
kernel/inode.cpp
196
kernel/inode.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -17,7 +17,10 @@
|
||||||
* Interfaces and utility classes for implementing inodes.
|
* Interfaces and utility classes for implementing inodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -49,6 +52,7 @@ AbstractInode::AbstractInode()
|
||||||
stat_mtim = Time::Get(CLOCK_REALTIME);
|
stat_mtim = Time::Get(CLOCK_REALTIME);
|
||||||
stat_blksize = 0;
|
stat_blksize = 0;
|
||||||
stat_blocks = 0;
|
stat_blocks = 0;
|
||||||
|
supports_iovec = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractInode::~AbstractInode()
|
AbstractInode::~AbstractInode()
|
||||||
|
@ -147,32 +151,186 @@ off_t AbstractInode::lseek(ioctx_t* /*ctx*/, off_t /*offset*/, int /*whence*/)
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t AbstractInode::read(ioctx_t* /*ctx*/, uint8_t* /*buf*/,
|
ssize_t AbstractInode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
size_t /*count*/)
|
|
||||||
{
|
{
|
||||||
|
if ( !supports_iovec )
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
|
struct iovec iov;
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
return readv(ctx, &iov, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t AbstractInode::pread(ioctx_t* /*ctx*/, uint8_t* /*buf*/,
|
ssize_t AbstractInode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
size_t /*count*/, off_t /*off*/)
|
|
||||||
{
|
{
|
||||||
|
if ( supports_iovec )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = read(ctx, buf, count);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
if ( !supports_iovec )
|
||||||
|
{
|
||||||
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||||
return errno = ESPIPE, -1;
|
return errno = ESPIPE, -1;
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
|
}
|
||||||
|
struct iovec iov;
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
return preadv(ctx, &iov, 1, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t AbstractInode::write(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
ssize_t AbstractInode::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
size_t /*count*/)
|
off_t off)
|
||||||
{
|
|
||||||
return errno = EBADF, -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t AbstractInode::pwrite(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
|
||||||
size_t /*count*/, off_t /*off*/)
|
|
||||||
{
|
{
|
||||||
|
if ( supports_iovec )
|
||||||
|
{
|
||||||
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||||
return errno = ESPIPE, -1;
|
return errno = ESPIPE, -1;
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
|
}
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
off_t offset;
|
||||||
|
if ( __builtin_add_overflow(off, sofar, &offset) )
|
||||||
|
return sofar ? sofar : (errno = EOVERFLOW, -1);
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = pread(ctx, buf, count, offset);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
|
{
|
||||||
|
if ( !supports_iovec )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
struct iovec iov;
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
return writev(ctx, &iov, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
if ( supports_iovec )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
const uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = write(ctx, buf, count);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
if ( !supports_iovec )
|
||||||
|
{
|
||||||
|
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||||
|
return errno = ESPIPE, -1;
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
}
|
||||||
|
struct iovec iov;
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
return pwritev(ctx, &iov, 1, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::pwritev(ioctx_t* ctx, const struct iovec* iov,
|
||||||
|
int iovcnt, off_t off)
|
||||||
|
{
|
||||||
|
if ( supports_iovec )
|
||||||
|
{
|
||||||
|
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||||
|
return errno = ESPIPE, -1;
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
}
|
||||||
|
ssize_t sofar = 0;
|
||||||
|
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
|
||||||
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - sofar;
|
||||||
|
uint8_t* buf = (uint8_t*) iov[i].iov_base;
|
||||||
|
size_t count = iov[i].iov_len;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
off_t offset;
|
||||||
|
if ( __builtin_add_overflow(off, sofar, &offset) )
|
||||||
|
return sofar ? sofar : (errno = EOVERFLOW, -1);
|
||||||
|
int old_dflags = ctx->dflags;
|
||||||
|
if ( sofar )
|
||||||
|
ctx->dflags |= O_NONBLOCK;
|
||||||
|
ssize_t amount = pwrite(ctx, buf, count, offset);
|
||||||
|
ctx->dflags = old_dflags;
|
||||||
|
if ( amount < 0 )
|
||||||
|
return sofar ? sofar : -1;
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
sofar += amount;
|
||||||
|
if ( (size_t) amount < count )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sofar;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AbstractInode::utimens(ioctx_t* /*ctx*/, const struct timespec* times)
|
int AbstractInode::utimens(ioctx_t* /*ctx*/, const struct timespec* times)
|
||||||
|
@ -383,12 +541,24 @@ ssize_t AbstractInode::recv(ioctx_t* /*ctx*/, uint8_t* /*buf*/,
|
||||||
return errno = ENOTSOCK, -1;
|
return errno = ENOTSOCK, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::recvmsg(ioctx_t* /*ctx*/, struct msghdr* /*msg*/,
|
||||||
|
int /*flags*/)
|
||||||
|
{
|
||||||
|
return errno = ENOTSOCK, -1;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t AbstractInode::send(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
ssize_t AbstractInode::send(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
||||||
size_t /*count*/, int /*flags*/)
|
size_t /*count*/, int /*flags*/)
|
||||||
{
|
{
|
||||||
return errno = ENOTSOCK, -1;
|
return errno = ENOTSOCK, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t AbstractInode::sendmsg(ioctx_t* /*ctx*/, const struct msghdr* /*msg*/,
|
||||||
|
int /*flags*/)
|
||||||
|
{
|
||||||
|
return errno = ENOTSOCK, -1;
|
||||||
|
}
|
||||||
|
|
||||||
int AbstractInode::getsockopt(ioctx_t* /*ctx*/, int /*level*/, int /*option_name*/,
|
int AbstractInode::getsockopt(ioctx_t* /*ctx*/, int /*level*/, int /*option_name*/,
|
||||||
void* /*option_value*/, size_t* /*option_size_ptr*/)
|
void* /*option_value*/, size_t* /*option_size_ptr*/)
|
||||||
{
|
{
|
||||||
|
|
186
kernel/io.cpp
186
kernel/io.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -786,165 +786,40 @@ ssize_t sys_send(int fd, const void* buffer, size_t count, int flags)
|
||||||
return desc->send(&ctx, (const uint8_t*) buffer, count, flags);
|
return desc->send(&ctx, (const uint8_t*) buffer, count, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We need to move these vector operations into the file descriptors or
|
ssize_t sys_readv(int fd, const struct iovec* iov, int iovcnt)
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t sys_readv(int fd, const struct iovec* user_iov, int iovcnt)
|
|
||||||
{
|
{
|
||||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return -1;
|
return -1;
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
struct iovec* iov = FetchIOV(user_iov, iovcnt);
|
return desc->readv(&ctx, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sys_preadv(int fd, const struct iovec* user_iov, int iovcnt, off_t offset)
|
ssize_t sys_preadv(int fd, const struct iovec* iov, int iovcnt, off_t offset)
|
||||||
{
|
{
|
||||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return -1;
|
return -1;
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
struct iovec* iov = FetchIOV(user_iov, iovcnt);
|
return desc->preadv(&ctx, iov, iovcnt, offset);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sys_writev(int fd, const struct iovec* user_iov, int iovcnt)
|
ssize_t sys_writev(int fd, const struct iovec* iov, int iovcnt)
|
||||||
{
|
{
|
||||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return -1;
|
return -1;
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
struct iovec* iov = FetchIOV(user_iov, iovcnt);
|
return desc->writev(&ctx, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sys_pwritev(int fd, const struct iovec* user_iov, int iovcnt, off_t offset)
|
ssize_t sys_pwritev(int fd, const struct iovec* iov, int iovcnt, off_t offset)
|
||||||
{
|
{
|
||||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return -1;
|
return -1;
|
||||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
struct iovec* iov = FetchIOV(user_iov, iovcnt);
|
return desc->pwritev(&ctx, iov, iovcnt, offset);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_mkpartition(int fd, off_t start, off_t length, int flags)
|
int sys_mkpartition(int fd, off_t start, off_t length, int flags)
|
||||||
|
@ -979,45 +854,22 @@ int sys_mkpartition(int fd, off_t start, off_t length, int flags)
|
||||||
return CurrentProcess()->GetDTable()->Allocate(partition_desc, fdflags);
|
return CurrentProcess()->GetDTable()->Allocate(partition_desc, fdflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t sys_sendmsg(int fd, const struct msghdr* user_msg, int flags)
|
ssize_t sys_sendmsg(int fd, const struct msghdr* msg, int flags)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
|
||||||
if ( !CopyFromUser(&msg, user_msg, sizeof(msg)) )
|
|
||||||
return -1;
|
|
||||||
// TODO: MSG_DONTWAIT and MSG_NOSIGNAL aren't actually supported here!
|
|
||||||
if ( flags & ~(MSG_EOR | MSG_DONTWAIT | MSG_NOSIGNAL) )
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
if ( msg.msg_name )
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
if ( msg.msg_control && msg.msg_controllen )
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
return sys_writev(fd, msg.msg_iov, msg.msg_iovlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t sys_recvmsg(int fd, struct msghdr* user_msg, int flags)
|
|
||||||
{
|
|
||||||
struct msghdr msg;
|
|
||||||
if ( !CopyFromUser(&msg, user_msg, sizeof(msg)) )
|
|
||||||
return -1;
|
|
||||||
if ( flags & ~(MSG_CMSG_CLOEXEC | MSG_DONTWAIT) )
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
if ( msg.msg_name )
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
if ( !desc )
|
if ( !desc )
|
||||||
return -1;
|
return -1;
|
||||||
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
|
return desc->sendmsg(&ctx, msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This is not atomic.
|
ssize_t sys_recvmsg(int fd, struct msghdr* msg, int flags)
|
||||||
int old_flags = desc->GetFlags();
|
{
|
||||||
desc->SetFlags(old_flags | O_NONBLOCK);
|
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||||
ssize_t result = sys_readv(fd, msg.msg_iov, msg.msg_iovlen);
|
if ( !desc )
|
||||||
desc->SetFlags(old_flags);
|
|
||||||
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
if ( !CopyToUser(&user_msg->msg_flags, &msg.msg_flags, sizeof(msg.msg_flags)) )
|
|
||||||
return -1;
|
return -1;
|
||||||
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||||
return result;
|
return desc->recvmsg(&ctx, msg, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_getsockopt(int fd, int level, int option_name,
|
int sys_getsockopt(int fd, int level, int option_name,
|
||||||
|
|
|
@ -90,10 +90,14 @@ public:
|
||||||
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrsize);
|
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrsize);
|
||||||
virtual int listen(ioctx_t* ctx, int backlog);
|
virtual int listen(ioctx_t* ctx, int backlog);
|
||||||
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
virtual ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
int flags);
|
int flags);
|
||||||
|
virtual ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
virtual int poll(ioctx_t* ctx, PollNode* node);
|
||||||
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr);
|
void* option_value, size_t* option_size_ptr);
|
||||||
|
@ -171,6 +175,7 @@ StreamSocket::StreamSocket(uid_t owner, gid_t group, mode_t mode,
|
||||||
this->socket_lock = KTHREAD_MUTEX_INITIALIZER;
|
this->socket_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
this->pending_cond = KTHREAD_COND_INITIALIZER;
|
this->pending_cond = KTHREAD_COND_INITIALIZER;
|
||||||
this->accepted_cond = KTHREAD_COND_INITIALIZER;
|
this->accepted_cond = KTHREAD_COND_INITIALIZER;
|
||||||
|
this->supports_iovec = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSocket::~StreamSocket()
|
StreamSocket::~StreamSocket()
|
||||||
|
@ -254,21 +259,37 @@ int StreamSocket::listen(ioctx_t* /*ctx*/, int /*backlog*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t StreamSocket::recv(ioctx_t* ctx, uint8_t* buf, size_t count,
|
ssize_t StreamSocket::recv(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||||
int /*flags*/)
|
int flags)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&socket_lock);
|
ScopedLock lock(&socket_lock);
|
||||||
if ( !is_connected )
|
if ( !is_connected )
|
||||||
return errno = ENOTCONN, -1;
|
return errno = ENOTCONN, -1;
|
||||||
return incoming.read(ctx, buf, count);
|
return incoming.recv(ctx, buf, count, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t StreamSocket::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
ScopedLock lock(&socket_lock);
|
||||||
|
if ( !is_connected )
|
||||||
|
return errno = ENOTCONN, -1;
|
||||||
|
return incoming.recvmsg(ctx, msg, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t StreamSocket::send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
ssize_t StreamSocket::send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
int /*flags*/)
|
int flags)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&socket_lock);
|
ScopedLock lock(&socket_lock);
|
||||||
if ( !is_connected )
|
if ( !is_connected )
|
||||||
return errno = ENOTCONN, -1;
|
return errno = ENOTCONN, -1;
|
||||||
return outgoing.write(ctx, buf, count);
|
return outgoing.send(ctx, buf, count, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t StreamSocket::sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
ScopedLock lock(&socket_lock);
|
||||||
|
if ( !is_connected )
|
||||||
|
return errno = ENOTCONN, -1;
|
||||||
|
return outgoing.sendmsg(ctx, msg, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t StreamSocket::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
ssize_t StreamSocket::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
|
@ -276,11 +297,27 @@ ssize_t StreamSocket::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
return recv(ctx, buf, count, 0);
|
return recv(ctx, buf, count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t StreamSocket::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
ScopedLock lock(&socket_lock);
|
||||||
|
if ( !is_connected )
|
||||||
|
return errno = ENOTCONN, -1;
|
||||||
|
return outgoing.readv(ctx, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t StreamSocket::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t StreamSocket::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
{
|
{
|
||||||
return send(ctx, buf, count, 0);
|
return send(ctx, buf, count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t StreamSocket::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
ScopedLock lock(&socket_lock);
|
||||||
|
if ( !is_connected )
|
||||||
|
return errno = ENOTCONN, -1;
|
||||||
|
return outgoing.writev(ctx, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
int StreamSocket::poll(ioctx_t* ctx, PollNode* node)
|
int StreamSocket::poll(ioctx_t* ctx, PollNode* node)
|
||||||
{
|
{
|
||||||
if ( is_connected )
|
if ( is_connected )
|
||||||
|
|
277
kernel/pipe.cpp
277
kernel/pipe.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -19,10 +19,14 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sortix/fcntl.h>
|
#include <sortix/fcntl.h>
|
||||||
|
#ifndef IOV_MAX
|
||||||
|
#include <sortix/limits.h>
|
||||||
|
#endif
|
||||||
#include <sortix/poll.h>
|
#include <sortix/poll.h>
|
||||||
#include <sortix/signal.h>
|
#include <sortix/signal.h>
|
||||||
#include <sortix/stat.h>
|
#include <sortix/stat.h>
|
||||||
|
@ -60,8 +64,14 @@ public:
|
||||||
size_t WriteSize();
|
size_t WriteSize();
|
||||||
bool ReadResize(size_t new_size);
|
bool ReadResize(size_t new_size);
|
||||||
bool WriteResize(size_t new_size);
|
bool WriteResize(size_t new_size);
|
||||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
|
ssize_t recvmsg_internal(ioctx_t* ctx, struct msghdr* msg, int flags);
|
||||||
|
ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags);
|
||||||
|
ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
|
ssize_t sendmsg_internal(ioctx_t* ctx, const struct msghdr* msg, int flags);
|
||||||
|
ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
int read_poll(ioctx_t* ctx, PollNode* node);
|
int read_poll(ioctx_t* ctx, PollNode* node);
|
||||||
int write_poll(ioctx_t* ctx, PollNode* node);
|
int write_poll(ioctx_t* ctx, PollNode* node);
|
||||||
|
|
||||||
|
@ -139,21 +149,83 @@ void PipeChannel::CloseWriting()
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeChannel::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
ssize_t PipeChannel::recv(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
if ( SSIZE_MAX < count )
|
struct iovec iov;
|
||||||
count = SSIZE_MAX;
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
struct msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
return recvmsg_internal(ctx, &msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = (struct iovec*) iov;
|
||||||
|
msg.msg_iovlen = iovcnt;
|
||||||
|
return recvmsg_internal(ctx, &msg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::recvmsg(ioctx_t* ctx, struct msghdr* msg_ptr, int flags)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
if ( !ctx->copy_from_src(&msg, msg_ptr, sizeof(msg)) )
|
||||||
|
return -1;
|
||||||
|
if ( msg.msg_iovlen < 0 || IOV_MAX < msg.msg_iovlen )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
size_t iov_size = msg.msg_iovlen * sizeof(struct iovec);
|
||||||
|
struct iovec* iov = new struct iovec[msg.msg_iovlen];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
if ( !ctx->copy_from_src(&iov, msg.msg_iov, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
size_t result = recvmsg_internal(ctx, &msg, flags);
|
||||||
|
delete[] iov;
|
||||||
|
if ( !ctx->copy_to_dest(msg_ptr, &msg, sizeof(msg)) )
|
||||||
|
return -1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::recvmsg_internal(ioctx_t* ctx, struct msghdr* msg,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if ( flags & ~(MSG_PEEK | MSG_WAITALL) )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
Thread* this_thread = CurrentThread();
|
Thread* this_thread = CurrentThread();
|
||||||
this_thread->yield_to_tid = sender_system_tid;
|
this_thread->yield_to_tid = sender_system_tid;
|
||||||
ScopedLockSignal lock(&pipelock);
|
ScopedLockSignal lock(&pipelock);
|
||||||
if ( !lock.IsAcquired() )
|
if ( !lock.IsAcquired() )
|
||||||
return errno = EINTR, -1;
|
return errno = EINTR, -1;
|
||||||
size_t so_far = 0;
|
ssize_t so_far = 0;
|
||||||
while ( count )
|
size_t peeked = 0;
|
||||||
|
int iov_i = 0;
|
||||||
|
size_t iov_offset = 0;
|
||||||
|
while ( iov_i < msg->msg_iovlen && so_far < SSIZE_MAX )
|
||||||
{
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - so_far;
|
||||||
|
struct iovec* iov = &msg->msg_iov[iov_i];
|
||||||
|
uint8_t* buf = (uint8_t*) iov->iov_base + iov_offset;
|
||||||
|
size_t count = iov->iov_len - iov_offset;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
if ( count == 0 )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
receiver_system_tid = this_thread->system_tid;
|
receiver_system_tid = this_thread->system_tid;
|
||||||
while ( anywriting && !bufferused )
|
while ( anywriting && bufferused <= peeked )
|
||||||
{
|
{
|
||||||
|
if ( (flags & MSG_PEEK) && so_far )
|
||||||
|
return so_far;
|
||||||
this_thread->yield_to_tid = sender_system_tid;
|
this_thread->yield_to_tid = sender_system_tid;
|
||||||
if ( pledged_read )
|
if ( pledged_read )
|
||||||
{
|
{
|
||||||
|
@ -164,7 +236,7 @@ ssize_t PipeChannel::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
pledged_write--;
|
pledged_write--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( so_far )
|
if ( !(flags & MSG_WAITALL) && so_far )
|
||||||
return so_far;
|
return so_far;
|
||||||
if ( ctx->dflags & O_NONBLOCK )
|
if ( ctx->dflags & O_NONBLOCK )
|
||||||
return errno = EWOULDBLOCK, -1;
|
return errno = EWOULDBLOCK, -1;
|
||||||
|
@ -172,44 +244,115 @@ ssize_t PipeChannel::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
bool interrupted = !kthread_cond_wait_signal(&readcond, &pipelock);
|
bool interrupted = !kthread_cond_wait_signal(&readcond, &pipelock);
|
||||||
pledged_write--;
|
pledged_write--;
|
||||||
if ( interrupted )
|
if ( interrupted )
|
||||||
return errno = EINTR, -1;
|
return so_far ? so_far : (errno = EINTR, -1);
|
||||||
}
|
}
|
||||||
if ( !bufferused && !anywriting )
|
size_t used = bufferused - peeked;
|
||||||
return (ssize_t) so_far;
|
if ( !used && !anywriting )
|
||||||
|
return so_far;
|
||||||
size_t amount = count;
|
size_t amount = count;
|
||||||
if ( bufferused < amount )
|
if ( used < amount )
|
||||||
amount = bufferused;
|
amount = used;
|
||||||
size_t linear = buffersize - bufferoffset;
|
size_t offset = bufferoffset;
|
||||||
|
if ( peeked )
|
||||||
|
offset = (bufferoffset + peeked) % buffersize;
|
||||||
|
size_t linear = buffersize - offset;
|
||||||
if ( linear < amount )
|
if ( linear < amount )
|
||||||
amount = linear;
|
amount = linear;
|
||||||
assert(amount);
|
assert(amount);
|
||||||
if ( !ctx->copy_to_dest(buf, buffer + bufferoffset, amount) )
|
if ( !ctx->copy_to_dest(buf, buffer + offset, amount) )
|
||||||
return so_far ? (ssize_t) so_far : -1;
|
return so_far ? so_far : -1;
|
||||||
|
so_far += amount;
|
||||||
|
if ( flags & MSG_PEEK )
|
||||||
|
peeked += amount;
|
||||||
|
else
|
||||||
|
{
|
||||||
bufferoffset = (bufferoffset + amount) % buffersize;
|
bufferoffset = (bufferoffset + amount) % buffersize;
|
||||||
bufferused -= amount;
|
bufferused -= amount;
|
||||||
buf += amount;
|
|
||||||
count -= amount;
|
|
||||||
so_far += amount;
|
|
||||||
kthread_cond_broadcast(&writecond);
|
kthread_cond_broadcast(&writecond);
|
||||||
read_poll_channel.Signal(ReadPollEventStatus());
|
read_poll_channel.Signal(ReadPollEventStatus());
|
||||||
write_poll_channel.Signal(WritePollEventStatus());
|
write_poll_channel.Signal(WritePollEventStatus());
|
||||||
}
|
}
|
||||||
return (ssize_t) so_far;
|
iov_offset += amount;
|
||||||
|
if ( iov_offset == iov->iov_len )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return so_far;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeChannel::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t PipeChannel::send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
if ( SSIZE_MAX < count )
|
struct iovec iov;
|
||||||
count = SSIZE_MAX;
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
iov.iov_base = (void*) buf;
|
||||||
|
iov.iov_len = count;
|
||||||
|
struct msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
return sendmsg_internal(ctx, &msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = (struct iovec*) iov;
|
||||||
|
msg.msg_iovlen = iovcnt;
|
||||||
|
return sendmsg_internal(ctx, &msg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::sendmsg(ioctx_t* ctx, const struct msghdr* msg_ptr,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
if ( !ctx->copy_from_src(&msg, msg_ptr, sizeof(msg)) )
|
||||||
|
return -1;
|
||||||
|
if ( msg.msg_iovlen < 0 || IOV_MAX < msg.msg_iovlen )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
size_t iov_size = msg.msg_iovlen * sizeof(struct iovec);
|
||||||
|
struct iovec* iov = new struct iovec[msg.msg_iovlen];
|
||||||
|
if ( !iov )
|
||||||
|
return -1;
|
||||||
|
if ( !ctx->copy_from_src(&iov, msg.msg_iov, iov_size) )
|
||||||
|
return delete[] iov, -1;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
size_t result = sendmsg_internal(ctx, &msg, flags);
|
||||||
|
delete[] iov;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeChannel::sendmsg_internal(ioctx_t* ctx, const struct msghdr* msg,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if ( flags & ~(MSG_WAITALL | MSG_NOSIGNAL) )
|
||||||
|
return errno = EINVAL, -1;
|
||||||
Thread* this_thread = CurrentThread();
|
Thread* this_thread = CurrentThread();
|
||||||
this_thread->yield_to_tid = receiver_system_tid;
|
this_thread->yield_to_tid = receiver_system_tid;
|
||||||
ScopedLockSignal lock(&pipelock);
|
ScopedLockSignal lock(&pipelock);
|
||||||
if ( !lock.IsAcquired() )
|
if ( !lock.IsAcquired() )
|
||||||
return errno = EINTR, -1;
|
return errno = EINTR, -1;
|
||||||
sender_system_tid = this_thread->system_tid;
|
sender_system_tid = this_thread->system_tid;
|
||||||
size_t so_far = 0;
|
ssize_t so_far = 0;
|
||||||
while ( count )
|
int iov_i = 0;
|
||||||
|
size_t iov_offset = 0;
|
||||||
|
while ( iov_i < msg->msg_iovlen && so_far < SSIZE_MAX )
|
||||||
{
|
{
|
||||||
|
size_t maxcount = SSIZE_MAX - so_far;
|
||||||
|
struct iovec* iov = &msg->msg_iov[iov_i];
|
||||||
|
const uint8_t* buf = (const uint8_t*) iov->iov_base + iov_offset;
|
||||||
|
size_t count = iov->iov_len - iov_offset;
|
||||||
|
if ( maxcount < count )
|
||||||
|
count = maxcount;
|
||||||
|
if ( count == 0 )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
sender_system_tid = this_thread->system_tid;
|
sender_system_tid = this_thread->system_tid;
|
||||||
while ( anyreading && bufferused == buffersize )
|
while ( anyreading && bufferused == buffersize )
|
||||||
{
|
{
|
||||||
|
@ -223,7 +366,7 @@ ssize_t PipeChannel::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
pledged_read--;
|
pledged_read--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( so_far )
|
if ( so_far && !(flags & MSG_WAITALL) )
|
||||||
return so_far;
|
return so_far;
|
||||||
if ( ctx->dflags & O_NONBLOCK )
|
if ( ctx->dflags & O_NONBLOCK )
|
||||||
return errno = EWOULDBLOCK, -1;
|
return errno = EWOULDBLOCK, -1;
|
||||||
|
@ -236,8 +379,8 @@ ssize_t PipeChannel::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
if ( !anyreading )
|
if ( !anyreading )
|
||||||
{
|
{
|
||||||
if ( so_far )
|
if ( so_far )
|
||||||
return (ssize_t) so_far;
|
return so_far;
|
||||||
if ( is_sigpipe_enabled )
|
if ( is_sigpipe_enabled && !(flags & MSG_NOSIGNAL) )
|
||||||
CurrentThread()->DeliverSignal(SIGPIPE);
|
CurrentThread()->DeliverSignal(SIGPIPE);
|
||||||
return errno = EPIPE, -1;
|
return errno = EPIPE, -1;
|
||||||
}
|
}
|
||||||
|
@ -250,16 +393,20 @@ ssize_t PipeChannel::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
amount = linear;
|
amount = linear;
|
||||||
assert(amount);
|
assert(amount);
|
||||||
if ( !ctx->copy_from_src(buffer + writeoffset, buf, amount) )
|
if ( !ctx->copy_from_src(buffer + writeoffset, buf, amount) )
|
||||||
return so_far ? (ssize_t) so_far : -1;
|
return so_far ? so_far : -1;
|
||||||
bufferused += amount;
|
bufferused += amount;
|
||||||
buf += amount;
|
|
||||||
count -= amount;
|
|
||||||
so_far += amount;
|
so_far += amount;
|
||||||
kthread_cond_broadcast(&readcond);
|
kthread_cond_broadcast(&readcond);
|
||||||
read_poll_channel.Signal(ReadPollEventStatus());
|
read_poll_channel.Signal(ReadPollEventStatus());
|
||||||
write_poll_channel.Signal(WritePollEventStatus());
|
write_poll_channel.Signal(WritePollEventStatus());
|
||||||
|
iov_offset += amount;
|
||||||
|
if ( iov_offset == iov->iov_len )
|
||||||
|
{
|
||||||
|
iov_i++;
|
||||||
|
iov_offset = 0;
|
||||||
}
|
}
|
||||||
return (ssize_t) so_far;
|
}
|
||||||
|
return so_far;
|
||||||
}
|
}
|
||||||
|
|
||||||
short PipeChannel::ReadPollEventStatus()
|
short PipeChannel::ReadPollEventStatus()
|
||||||
|
@ -405,21 +552,62 @@ void PipeEndpoint::Disconnect()
|
||||||
reading = false;
|
reading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeEndpoint::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
ssize_t PipeEndpoint::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
|
||||||
{
|
{
|
||||||
if ( !reading )
|
if ( !reading )
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
ssize_t result = channel->read(ctx, buf, count);
|
ssize_t result = channel->recv(ctx, buf, count, flags);
|
||||||
CurrentThread()->yield_to_tid = 0;
|
CurrentThread()->yield_to_tid = 0;
|
||||||
Scheduler::ScheduleTrueThread();
|
Scheduler::ScheduleTrueThread();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeEndpoint::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t PipeEndpoint::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
if ( !reading )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t result = channel->recvmsg(ctx, msg, flags);
|
||||||
|
CurrentThread()->yield_to_tid = 0;
|
||||||
|
Scheduler::ScheduleTrueThread();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeEndpoint::send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
if ( reading )
|
if ( reading )
|
||||||
return errno = EBADF, -1;
|
return errno = EBADF, -1;
|
||||||
ssize_t result = channel->write(ctx, buf, count);
|
ssize_t result = channel->send(ctx, buf, count, flags);
|
||||||
|
CurrentThread()->yield_to_tid = 0;
|
||||||
|
Scheduler::ScheduleTrueThread();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeEndpoint::sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
if ( reading )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t result = channel->sendmsg(ctx, msg, flags);
|
||||||
|
CurrentThread()->yield_to_tid = 0;
|
||||||
|
Scheduler::ScheduleTrueThread();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeEndpoint::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
if ( !reading )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t result = channel->readv(ctx, iov, iovcnt);
|
||||||
|
CurrentThread()->yield_to_tid = 0;
|
||||||
|
Scheduler::ScheduleTrueThread();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PipeEndpoint::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
if ( reading )
|
||||||
|
return errno = EBADF, -1;
|
||||||
|
ssize_t result = channel->writev(ctx, iov, iovcnt);
|
||||||
CurrentThread()->yield_to_tid = 0;
|
CurrentThread()->yield_to_tid = 0;
|
||||||
Scheduler::ScheduleTrueThread();
|
Scheduler::ScheduleTrueThread();
|
||||||
return result;
|
return result;
|
||||||
|
@ -462,8 +650,8 @@ class PipeNode : public AbstractInode
|
||||||
public:
|
public:
|
||||||
PipeNode(dev_t dev, uid_t owner, gid_t group, mode_t mode);
|
PipeNode(dev_t dev, uid_t owner, gid_t group, mode_t mode);
|
||||||
virtual ~PipeNode();
|
virtual ~PipeNode();
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
||||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
virtual int poll(ioctx_t* ctx, PollNode* node);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -488,20 +676,21 @@ PipeNode::PipeNode(dev_t dev, uid_t owner, gid_t group, mode_t mode)
|
||||||
this->stat_gid = group;
|
this->stat_gid = group;
|
||||||
this->type = S_IFCHR;
|
this->type = S_IFCHR;
|
||||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||||
|
supports_iovec = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PipeNode::~PipeNode()
|
PipeNode::~PipeNode()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeNode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
ssize_t PipeNode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
{
|
{
|
||||||
return endpoint.read(ctx, buf, count);
|
return endpoint.readv(ctx, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t PipeNode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t PipeNode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
{
|
{
|
||||||
return endpoint.write(ctx, buf, count);
|
return endpoint.writev(ctx, iov, iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PipeNode::poll(ioctx_t* ctx, PollNode* node)
|
int PipeNode::poll(ioctx_t* ctx, PollNode* node)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -256,21 +256,43 @@ ssize_t Vnode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
return inode->read(ctx, buf, count);
|
return inode->read(ctx, buf, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return inode->readv(ctx, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Vnode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
ssize_t Vnode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
return inode->pread(ctx, buf, count, off);
|
return inode->pread(ctx, buf, count, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
return inode->preadv(ctx, iov, iovcnt, off);
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Vnode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
ssize_t Vnode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
{
|
{
|
||||||
return inode->write(ctx, buf, count);
|
return inode->write(ctx, buf, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
||||||
|
{
|
||||||
|
return inode->writev(ctx, iov, iovcnt);
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Vnode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
ssize_t Vnode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
return inode->pwrite(ctx, buf, count, off);
|
return inode->pwrite(ctx, buf, count, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
return inode->pwritev(ctx, iov, iovcnt, off);
|
||||||
|
}
|
||||||
|
|
||||||
int Vnode::utimens(ioctx_t* ctx, const struct timespec* times)
|
int Vnode::utimens(ioctx_t* ctx, const struct timespec* times)
|
||||||
{
|
{
|
||||||
return inode->utimens(ctx, times);
|
return inode->utimens(ctx, times);
|
||||||
|
@ -397,11 +419,21 @@ ssize_t Vnode::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
|
||||||
return inode->recv(ctx, buf, count, flags);
|
return inode->recv(ctx, buf, count, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
return inode->recvmsg(ctx, msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Vnode::send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags)
|
ssize_t Vnode::send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags)
|
||||||
{
|
{
|
||||||
return inode->send(ctx, buf, count, flags);
|
return inode->send(ctx, buf, count, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Vnode::sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags)
|
||||||
|
{
|
||||||
|
return inode->sendmsg(ctx, msg, flags);
|
||||||
|
}
|
||||||
|
|
||||||
int Vnode::getsockopt(ioctx_t* ctx, int level, int option_name,
|
int Vnode::getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||||
void* option_value, size_t* option_size_ptr)
|
void* option_value, size_t* option_size_ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@ regress \
|
||||||
|
|
||||||
TESTS:=\
|
TESTS:=\
|
||||||
test-fmemopen \
|
test-fmemopen \
|
||||||
|
test-pipe-one-byte \
|
||||||
test-pthread-argv \
|
test-pthread-argv \
|
||||||
test-pthread-basic \
|
test-pthread-basic \
|
||||||
test-pthread-main-exit \
|
test-pthread-main-exit \
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* test-pthread-basic.c
|
||||||
|
* Tests whether basic pthread support works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
pipe(fds);
|
||||||
|
pid_t pid = fork();
|
||||||
|
test_assert(0 <= pid);
|
||||||
|
if ( pid == 0 )
|
||||||
|
{
|
||||||
|
close(fds[0]);
|
||||||
|
char c = 'X';
|
||||||
|
test_assert(write(fds[1], &c, 1) == 1);
|
||||||
|
while (1)
|
||||||
|
sleep(1000);
|
||||||
|
}
|
||||||
|
close(fds[1]);
|
||||||
|
char c;
|
||||||
|
test_assert(read(fds[0], &c, 1) == 1);
|
||||||
|
test_assert(c == 'X');
|
||||||
|
kill(pid, SIGKILL);
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue