Fix non-blocking recv(2) and send(2).
This commit is contained in:
parent
8ec5d9af44
commit
f28fc4ac39
|
@ -56,6 +56,14 @@ static const int OPEN_FLAGS = O_CREATE | O_DIRECTORY | O_EXCL | O_TRUNC |
|
||||||
// Flags that only make sense for descriptors.
|
// Flags that only make sense for descriptors.
|
||||||
static const int DESCRIPTOR_FLAGS = O_APPEND | O_NONBLOCK;
|
static const int DESCRIPTOR_FLAGS = O_APPEND | O_NONBLOCK;
|
||||||
|
|
||||||
|
// Let the ioctx_t force bits like O_NONBLOCK and otherwise use the dflags of
|
||||||
|
// the current file descriptor. This allows the caller to do non-blocking reads
|
||||||
|
// without calls to fcntl that may be racy with respect to other threads.
|
||||||
|
static int ContextFlags(int ctx_dflags, int desc_dflags)
|
||||||
|
{
|
||||||
|
return desc_dflags | (ctx_dflags & DESCRIPTOR_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
int LinkInodeInDir(ioctx_t* ctx,
|
int LinkInodeInDir(ioctx_t* ctx,
|
||||||
Ref<Descriptor> dir,
|
Ref<Descriptor> dir,
|
||||||
const char* name,
|
const char* name,
|
||||||
|
@ -269,13 +277,19 @@ ssize_t Descriptor::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||||
return 0;
|
return 0;
|
||||||
if ( SIZE_MAX < count )
|
if ( SIZE_MAX < count )
|
||||||
count = SSIZE_MAX;
|
count = SSIZE_MAX;
|
||||||
ctx->dflags = dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
if ( !IsSeekable() )
|
if ( !IsSeekable() )
|
||||||
return vnode->read(ctx, buf, count);
|
{
|
||||||
|
ssize_t result = vnode->read(ctx, buf, count);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
ScopedLock lock(¤t_offset_lock);
|
ScopedLock lock(¤t_offset_lock);
|
||||||
ssize_t ret = vnode->pread(ctx, buf, count, current_offset);
|
ssize_t ret = vnode->pread(ctx, buf, count, current_offset);
|
||||||
if ( 0 <= ret )
|
if ( 0 <= ret )
|
||||||
current_offset += ret;
|
current_offset += ret;
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,8 +303,11 @@ ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||||
return 0;
|
return 0;
|
||||||
if ( SSIZE_MAX < count )
|
if ( SSIZE_MAX < count )
|
||||||
count = SSIZE_MAX;
|
count = SSIZE_MAX;
|
||||||
ctx->dflags = dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
return vnode->pread(ctx, buf, count, off);
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->pread(ctx, buf, count, off);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
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)
|
||||||
|
@ -301,20 +318,29 @@ ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||||
return 0;
|
return 0;
|
||||||
if ( SSIZE_MAX < count )
|
if ( SSIZE_MAX < count )
|
||||||
count = SSIZE_MAX;
|
count = SSIZE_MAX;
|
||||||
ctx->dflags = dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
if ( !IsSeekable() )
|
if ( !IsSeekable() )
|
||||||
return vnode->write(ctx, buf, count);
|
{
|
||||||
|
ssize_t result = vnode->write(ctx, buf, count);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
ScopedLock lock(¤t_offset_lock);
|
ScopedLock lock(¤t_offset_lock);
|
||||||
if ( dflags & O_APPEND )
|
if ( ctx->dflags & O_APPEND )
|
||||||
{
|
{
|
||||||
off_t end = vnode->lseek(ctx, 0, SEEK_END);
|
off_t end = vnode->lseek(ctx, 0, SEEK_END);
|
||||||
if ( end < 0 )
|
if ( end < 0 )
|
||||||
|
{
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
current_offset = end;
|
current_offset = end;
|
||||||
}
|
}
|
||||||
ssize_t ret = vnode->pwrite(ctx, buf, count, current_offset);
|
ssize_t ret = vnode->pwrite(ctx, buf, count, current_offset);
|
||||||
if ( 0 <= ret )
|
if ( 0 <= ret )
|
||||||
current_offset += ret;
|
current_offset += ret;
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,8 +354,11 @@ ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t
|
||||||
return 0;
|
return 0;
|
||||||
if ( SSIZE_MAX < count )
|
if ( SSIZE_MAX < count )
|
||||||
count = SSIZE_MAX;
|
count = SSIZE_MAX;
|
||||||
ctx->dflags = dflags;
|
int old_ctx_dflags = ctx->dflags;
|
||||||
return vnode->pwrite(ctx, buf, count, off);
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->pwrite(ctx, buf, count, off);
|
||||||
|
ctx->dflags = old_ctx_dflags;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool valid_utimens_timespec(struct timespec ts)
|
static inline bool valid_utimens_timespec(struct timespec ts)
|
||||||
|
@ -722,12 +751,20 @@ 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)
|
||||||
{
|
{
|
||||||
return vnode->recv(ctx, buf, count, flags);
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->recv(ctx, buf, count, 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)
|
||||||
{
|
{
|
||||||
return vnode->send(ctx, buf, count, flags);
|
int old_ctx_dflags = ctx->dflags;
|
||||||
|
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||||
|
ssize_t result = vnode->send(ctx, buf, count, 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,
|
||||||
|
|
Loading…
Reference in New Issue