Relicense Sortix to the ISC license.
I hereby relicense all my work on Sortix under the ISC license as below.
All Sortix contributions by other people are already under this license,
are not substantial enough to be copyrightable, or have been removed.
All imported code from other projects is compatible with this license.
All GPL licensed code from other projects had previously been removed.
Copyright 2011-2016 Jonas 'Sortie' Termansen and contributors.
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.
2016-03-02 17:38:16 -05:00
|
|
|
/*
|
2021-02-06 15:41:49 -05:00
|
|
|
* Copyright (c) 2011-2017, 2021 Jonas 'Sortie' Termansen.
|
Relicense Sortix to the ISC license.
I hereby relicense all my work on Sortix under the ISC license as below.
All Sortix contributions by other people are already under this license,
are not substantial enough to be copyrightable, or have been removed.
All imported code from other projects is compatible with this license.
All GPL licensed code from other projects had previously been removed.
Copyright 2011-2016 Jonas 'Sortie' Termansen and contributors.
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.
2016-03-02 17:38:16 -05:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* pipe.cpp
|
|
|
|
* A device with a writing end and a reading end.
|
|
|
|
*/
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2013-01-02 11:34:40 -05:00
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
2017-01-09 17:40:56 -05:00
|
|
|
#include <limits.h>
|
2014-10-03 18:47:20 -04:00
|
|
|
#include <stdint.h>
|
2013-01-02 11:34:40 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
2013-03-21 10:26:08 -04:00
|
|
|
#include <sortix/fcntl.h>
|
2017-01-09 17:40:56 -05:00
|
|
|
#ifndef IOV_MAX
|
|
|
|
#include <sortix/limits.h>
|
|
|
|
#endif
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/poll.h>
|
2013-01-02 11:34:40 -05:00
|
|
|
#include <sortix/signal.h>
|
|
|
|
#include <sortix/stat.h>
|
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
#include <sortix/kernel/copy.h>
|
|
|
|
#include <sortix/kernel/descriptor.h>
|
|
|
|
#include <sortix/kernel/dtable.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/inode.h>
|
|
|
|
#include <sortix/kernel/interlock.h>
|
|
|
|
#include <sortix/kernel/ioctx.h>
|
|
|
|
#include <sortix/kernel/kernel.h>
|
|
|
|
#include <sortix/kernel/kthread.h>
|
2013-04-24 11:32:36 -04:00
|
|
|
#include <sortix/kernel/pipe.h>
|
|
|
|
#include <sortix/kernel/poll.h>
|
2013-05-12 18:41:30 -04:00
|
|
|
#include <sortix/kernel/process.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/refcount.h>
|
2014-10-03 18:47:20 -04:00
|
|
|
#include <sortix/kernel/scheduler.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/signal.h>
|
|
|
|
#include <sortix/kernel/syscall.h>
|
2013-05-12 18:41:30 -04:00
|
|
|
#include <sortix/kernel/thread.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/vnode.h>
|
2013-01-08 18:41:35 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
namespace Sortix {
|
|
|
|
|
|
|
|
class PipeChannel
|
2011-11-16 02:37:29 -05:00
|
|
|
{
|
2012-08-07 18:19:44 -04:00
|
|
|
public:
|
|
|
|
PipeChannel(uint8_t* buffer, size_t buffersize);
|
|
|
|
~PipeChannel();
|
|
|
|
void CloseReading();
|
|
|
|
void CloseWriting();
|
2014-04-30 17:14:20 -04:00
|
|
|
bool GetSIGPIPEDelivery();
|
|
|
|
void SetSIGPIPEDelivery(bool deliver_sigpipe);
|
2014-04-30 11:25:52 -04:00
|
|
|
size_t ReadSize();
|
|
|
|
size_t WriteSize();
|
|
|
|
bool ReadResize(size_t new_size);
|
|
|
|
bool WriteResize(size_t new_size);
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
|
|
|
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);
|
2014-04-29 16:16:07 -04:00
|
|
|
int read_poll(ioctx_t* ctx, PollNode* node);
|
|
|
|
int write_poll(ioctx_t* ctx, PollNode* node);
|
2013-01-02 11:34:40 -05:00
|
|
|
|
|
|
|
private:
|
2014-04-29 16:16:07 -04:00
|
|
|
short ReadPollEventStatus();
|
|
|
|
short WritePollEventStatus();
|
2012-08-07 18:19:44 -04:00
|
|
|
|
|
|
|
private:
|
2014-04-29 16:16:07 -04:00
|
|
|
PollChannel read_poll_channel;
|
|
|
|
PollChannel write_poll_channel;
|
2012-08-07 18:19:44 -04:00
|
|
|
kthread_mutex_t pipelock;
|
|
|
|
kthread_cond_t readcond;
|
|
|
|
kthread_cond_t writecond;
|
|
|
|
uint8_t* buffer;
|
2014-10-03 18:47:20 -04:00
|
|
|
uintptr_t sender_system_tid;
|
|
|
|
uintptr_t receiver_system_tid;
|
2012-08-07 18:19:44 -04:00
|
|
|
size_t bufferoffset;
|
|
|
|
size_t bufferused;
|
|
|
|
size_t buffersize;
|
2014-04-30 11:25:52 -04:00
|
|
|
size_t pretended_read_buffer_size;
|
2014-10-03 18:47:20 -04:00
|
|
|
size_t pledged_read;
|
|
|
|
size_t pledged_write;
|
2015-10-08 19:40:55 -04:00
|
|
|
unsigned long closers;
|
2012-08-07 18:19:44 -04:00
|
|
|
bool anyreading;
|
|
|
|
bool anywriting;
|
2014-04-30 17:14:20 -04:00
|
|
|
bool is_sigpipe_enabled;
|
2012-08-07 18:19:44 -04:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeChannel::PipeChannel(uint8_t* buffer, size_t buffersize)
|
|
|
|
{
|
|
|
|
pipelock = KTHREAD_MUTEX_INITIALIZER;
|
|
|
|
readcond = KTHREAD_COND_INITIALIZER;
|
|
|
|
writecond = KTHREAD_COND_INITIALIZER;
|
|
|
|
this->buffer = buffer;
|
|
|
|
this->buffersize = buffersize;
|
|
|
|
bufferoffset = bufferused = 0;
|
2013-04-24 11:32:36 -04:00
|
|
|
anyreading = anywriting = true;
|
2014-04-30 17:14:20 -04:00
|
|
|
is_sigpipe_enabled = true;
|
2014-10-03 18:47:20 -04:00
|
|
|
sender_system_tid = 0;
|
|
|
|
receiver_system_tid = 0;
|
|
|
|
pledged_read = 0;
|
|
|
|
pledged_write = 0;
|
2015-10-08 19:40:55 -04:00
|
|
|
closers = 0;
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
PipeChannel::~PipeChannel()
|
|
|
|
{
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
void PipeChannel::CloseReading()
|
|
|
|
{
|
2015-10-08 19:40:55 -04:00
|
|
|
kthread_mutex_lock(&pipelock);
|
2012-08-07 18:19:44 -04:00
|
|
|
anyreading = false;
|
|
|
|
kthread_cond_broadcast(&writecond);
|
2015-10-08 19:40:55 -04:00
|
|
|
read_poll_channel.Signal(ReadPollEventStatus());
|
|
|
|
write_poll_channel.Signal(WritePollEventStatus());
|
|
|
|
kthread_mutex_unlock(&pipelock);
|
|
|
|
unsigned long count = InterlockedIncrement(&closers).n;
|
|
|
|
if ( count == 2 )
|
|
|
|
delete this;
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2012-03-01 08:31:12 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
void PipeChannel::CloseWriting()
|
|
|
|
{
|
2015-10-08 19:40:55 -04:00
|
|
|
kthread_mutex_lock(&pipelock);
|
2012-08-07 18:19:44 -04:00
|
|
|
anywriting = false;
|
|
|
|
kthread_cond_broadcast(&readcond);
|
2014-04-29 16:16:07 -04:00
|
|
|
read_poll_channel.Signal(ReadPollEventStatus());
|
|
|
|
write_poll_channel.Signal(WritePollEventStatus());
|
2012-08-07 18:19:44 -04:00
|
|
|
kthread_mutex_unlock(&pipelock);
|
2015-10-08 19:40:55 -04:00
|
|
|
unsigned long count = InterlockedIncrement(&closers).n;
|
|
|
|
if ( count == 2 )
|
2012-08-07 18:19:44 -04:00
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeChannel::recv(ioctx_t* ctx, uint8_t* buf, size_t count,
|
|
|
|
int flags)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
struct iovec iov;
|
|
|
|
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;
|
2017-04-22 16:26:56 -04:00
|
|
|
if ( !ctx->copy_from_src(iov, msg.msg_iov, iov_size) )
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
2014-10-03 18:47:20 -04:00
|
|
|
Thread* this_thread = CurrentThread();
|
|
|
|
this_thread->yield_to_tid = sender_system_tid;
|
2012-08-07 18:19:44 -04:00
|
|
|
ScopedLockSignal lock(&pipelock);
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( !lock.IsAcquired() )
|
|
|
|
return errno = EINTR, -1;
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t so_far = 0;
|
|
|
|
size_t peeked = 0;
|
2017-10-26 11:12:07 -04:00
|
|
|
if ( SSIZE_MAX < TruncateIOVec(msg->msg_iov, msg->msg_iovlen, SSIZE_MAX) )
|
|
|
|
return errno = EINVAL, -1;
|
2017-01-09 17:40:56 -05:00
|
|
|
int iov_i = 0;
|
|
|
|
size_t iov_offset = 0;
|
|
|
|
while ( iov_i < msg->msg_iovlen && so_far < SSIZE_MAX )
|
2011-11-16 02:37:29 -05:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
|
|
|
}
|
2014-10-03 18:47:20 -04:00
|
|
|
receiver_system_tid = this_thread->system_tid;
|
2017-01-09 17:40:56 -05:00
|
|
|
while ( anywriting && bufferused <= peeked )
|
2012-08-02 08:34:36 -04:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( (flags & MSG_PEEK) && so_far )
|
|
|
|
return so_far;
|
2014-10-03 18:47:20 -04:00
|
|
|
this_thread->yield_to_tid = sender_system_tid;
|
|
|
|
if ( pledged_read )
|
|
|
|
{
|
|
|
|
pledged_write++;
|
|
|
|
kthread_mutex_unlock(&pipelock);
|
|
|
|
kthread_yield();
|
|
|
|
kthread_mutex_lock(&pipelock);
|
|
|
|
pledged_write--;
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( !(flags & MSG_WAITALL) && so_far )
|
2014-10-03 18:47:20 -04:00
|
|
|
return so_far;
|
|
|
|
if ( ctx->dflags & O_NONBLOCK )
|
|
|
|
return errno = EWOULDBLOCK, -1;
|
|
|
|
pledged_write++;
|
|
|
|
bool interrupted = !kthread_cond_wait_signal(&readcond, &pipelock);
|
|
|
|
pledged_write--;
|
|
|
|
if ( interrupted )
|
2017-01-09 17:40:56 -05:00
|
|
|
return so_far ? so_far : (errno = EINTR, -1);
|
2012-08-02 08:34:36 -04:00
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
size_t used = bufferused - peeked;
|
|
|
|
if ( !used && !anywriting )
|
|
|
|
return so_far;
|
2014-10-03 18:47:20 -04:00
|
|
|
size_t amount = count;
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( used < amount )
|
|
|
|
amount = used;
|
|
|
|
size_t offset = bufferoffset;
|
|
|
|
if ( peeked )
|
|
|
|
offset = (bufferoffset + peeked) % buffersize;
|
|
|
|
size_t linear = buffersize - offset;
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( linear < amount )
|
|
|
|
amount = linear;
|
|
|
|
assert(amount);
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( !ctx->copy_to_dest(buf, buffer + offset, amount) )
|
|
|
|
return so_far ? so_far : -1;
|
2014-10-03 18:47:20 -04:00
|
|
|
so_far += amount;
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( flags & MSG_PEEK )
|
|
|
|
peeked += amount;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bufferoffset = (bufferoffset + amount) % buffersize;
|
|
|
|
bufferused -= amount;
|
|
|
|
kthread_cond_broadcast(&writecond);
|
|
|
|
read_poll_channel.Signal(ReadPollEventStatus());
|
|
|
|
write_poll_channel.Signal(WritePollEventStatus());
|
|
|
|
}
|
|
|
|
iov_offset += amount;
|
|
|
|
if ( iov_offset == iov->iov_len )
|
|
|
|
{
|
|
|
|
iov_i++;
|
|
|
|
iov_offset = 0;
|
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
return so_far;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t PipeChannel::send(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
struct iovec iov;
|
|
|
|
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);
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeChannel::sendmsg(ioctx_t* ctx, const struct msghdr* msg_ptr,
|
|
|
|
int flags)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
2017-04-22 16:26:56 -04:00
|
|
|
if ( !ctx->copy_from_src(iov, msg.msg_iov, iov_size) )
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
2014-10-03 18:47:20 -04:00
|
|
|
Thread* this_thread = CurrentThread();
|
|
|
|
this_thread->yield_to_tid = receiver_system_tid;
|
2012-08-07 18:19:44 -04:00
|
|
|
ScopedLockSignal lock(&pipelock);
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( !lock.IsAcquired() )
|
|
|
|
return errno = EINTR, -1;
|
|
|
|
sender_system_tid = this_thread->system_tid;
|
2017-10-26 11:12:07 -04:00
|
|
|
if ( SSIZE_MAX < TruncateIOVec(msg->msg_iov, msg->msg_iovlen, SSIZE_MAX) )
|
|
|
|
return errno = EINVAL, -1;
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t so_far = 0;
|
|
|
|
int iov_i = 0;
|
|
|
|
size_t iov_offset = 0;
|
|
|
|
while ( iov_i < msg->msg_iovlen && so_far < SSIZE_MAX )
|
2011-11-16 02:37:29 -05:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
|
|
|
}
|
2014-10-03 18:47:20 -04:00
|
|
|
sender_system_tid = this_thread->system_tid;
|
|
|
|
while ( anyreading && bufferused == buffersize )
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2014-10-03 18:47:20 -04:00
|
|
|
this_thread->yield_to_tid = receiver_system_tid;
|
|
|
|
if ( pledged_write )
|
|
|
|
{
|
|
|
|
pledged_read++;
|
|
|
|
kthread_mutex_unlock(&pipelock);
|
|
|
|
kthread_yield();
|
|
|
|
kthread_mutex_lock(&pipelock);
|
|
|
|
pledged_read--;
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
if ( so_far && !(flags & MSG_WAITALL) )
|
2014-10-03 18:47:20 -04:00
|
|
|
return so_far;
|
|
|
|
if ( ctx->dflags & O_NONBLOCK )
|
|
|
|
return errno = EWOULDBLOCK, -1;
|
|
|
|
pledged_read++;
|
|
|
|
bool interrupted = !kthread_cond_wait_signal(&writecond, &pipelock);
|
|
|
|
pledged_read--;
|
|
|
|
if ( interrupted )
|
|
|
|
return errno = EINTR, -1;
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( !anyreading )
|
|
|
|
{
|
|
|
|
if ( so_far )
|
2017-01-09 17:40:56 -05:00
|
|
|
return so_far;
|
|
|
|
if ( is_sigpipe_enabled && !(flags & MSG_NOSIGNAL) )
|
2014-10-03 18:47:20 -04:00
|
|
|
CurrentThread()->DeliverSignal(SIGPIPE);
|
|
|
|
return errno = EPIPE, -1;
|
|
|
|
}
|
|
|
|
size_t amount = count;
|
|
|
|
if ( buffersize - bufferused < amount )
|
|
|
|
amount = buffersize - bufferused;
|
|
|
|
size_t writeoffset = (bufferoffset + bufferused) % buffersize;
|
|
|
|
size_t linear = buffersize - writeoffset;
|
|
|
|
if ( linear < amount )
|
|
|
|
amount = linear;
|
|
|
|
assert(amount);
|
|
|
|
if ( !ctx->copy_from_src(buffer + writeoffset, buf, amount) )
|
2017-01-09 17:40:56 -05:00
|
|
|
return so_far ? so_far : -1;
|
2014-10-03 18:47:20 -04:00
|
|
|
bufferused += amount;
|
|
|
|
so_far += amount;
|
|
|
|
kthread_cond_broadcast(&readcond);
|
|
|
|
read_poll_channel.Signal(ReadPollEventStatus());
|
|
|
|
write_poll_channel.Signal(WritePollEventStatus());
|
2017-01-09 17:40:56 -05:00
|
|
|
iov_offset += amount;
|
|
|
|
if ( iov_offset == iov->iov_len )
|
|
|
|
{
|
|
|
|
iov_i++;
|
|
|
|
iov_offset = 0;
|
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
return so_far;
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2014-04-29 16:16:07 -04:00
|
|
|
short PipeChannel::ReadPollEventStatus()
|
2013-01-02 11:34:40 -05:00
|
|
|
{
|
|
|
|
short status = 0;
|
2014-04-29 16:16:07 -04:00
|
|
|
if ( !anywriting && !bufferused )
|
2013-01-02 11:34:40 -05:00
|
|
|
status |= POLLHUP;
|
|
|
|
if ( bufferused )
|
|
|
|
status |= POLLIN | POLLRDNORM;
|
2014-04-29 16:16:07 -04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
short PipeChannel::WritePollEventStatus()
|
|
|
|
{
|
|
|
|
short status = 0;
|
|
|
|
if ( !anyreading )
|
|
|
|
status |= POLLERR;
|
|
|
|
if ( anyreading && bufferused != buffersize )
|
2013-01-02 11:34:40 -05:00
|
|
|
status |= POLLOUT | POLLWRNORM;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2014-04-29 16:16:07 -04:00
|
|
|
int PipeChannel::read_poll(ioctx_t* /*ctx*/, PollNode* node)
|
2013-01-02 11:34:40 -05:00
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-29 16:16:07 -04:00
|
|
|
short ret_status = ReadPollEventStatus() & node->events;
|
2013-01-02 11:34:40 -05:00
|
|
|
if ( ret_status )
|
2014-04-29 16:16:07 -04:00
|
|
|
return node->master->revents |= ret_status, 0;
|
|
|
|
read_poll_channel.Register(node);
|
|
|
|
return errno = EAGAIN, -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PipeChannel::write_poll(ioctx_t* /*ctx*/, PollNode* node)
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-29 16:16:07 -04:00
|
|
|
short ret_status = WritePollEventStatus() & node->events;
|
|
|
|
if ( ret_status )
|
|
|
|
return node->master->revents |= ret_status, 0;
|
|
|
|
write_poll_channel.Register(node);
|
2013-01-02 11:34:40 -05:00
|
|
|
return errno = EAGAIN, -1;
|
|
|
|
}
|
|
|
|
|
2014-04-30 17:14:20 -04:00
|
|
|
bool PipeChannel::GetSIGPIPEDelivery()
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 17:14:20 -04:00
|
|
|
return is_sigpipe_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PipeChannel::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 17:14:20 -04:00
|
|
|
is_sigpipe_enabled = deliver_sigpipe;
|
|
|
|
}
|
|
|
|
|
2014-04-30 11:25:52 -04:00
|
|
|
size_t PipeChannel::ReadSize()
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 11:25:52 -04:00
|
|
|
return pretended_read_buffer_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t PipeChannel::WriteSize()
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 11:25:52 -04:00
|
|
|
return buffersize;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PipeChannel::ReadResize(size_t new_size)
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 11:25:52 -04:00
|
|
|
if ( !new_size )
|
|
|
|
return errno = EINVAL, false;
|
|
|
|
// The read and write end share the same buffer, so let the write end decide
|
|
|
|
// how big a buffer it wants and pretend the read end can decide too.
|
|
|
|
pretended_read_buffer_size = new_size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PipeChannel::WriteResize(size_t new_size)
|
|
|
|
{
|
2021-02-06 15:41:49 -05:00
|
|
|
ScopedLock lock(&pipelock);
|
2014-04-30 11:25:52 -04:00
|
|
|
if ( !new_size )
|
|
|
|
return errno = EINVAL, false;
|
|
|
|
|
|
|
|
size_t MAX_PIPE_SIZE = 2 * 1024 * 1024;
|
|
|
|
if ( MAX_PIPE_SIZE < new_size )
|
|
|
|
new_size = MAX_PIPE_SIZE;
|
|
|
|
|
|
|
|
// Refuse to lose data if the the new size would cause truncation.
|
|
|
|
if ( new_size < bufferused )
|
|
|
|
new_size = bufferused;
|
|
|
|
|
|
|
|
uint8_t* new_buffer = new uint8_t[new_size];
|
|
|
|
if ( !new_buffer )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for ( size_t i = 0; i < bufferused; i++ )
|
|
|
|
new_buffer[i] = buffer[(bufferoffset + i) % buffersize];
|
|
|
|
delete[] buffer;
|
|
|
|
buffer = new_buffer;
|
|
|
|
buffersize = new_size;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
PipeEndpoint::PipeEndpoint()
|
|
|
|
{
|
|
|
|
channel = NULL;
|
|
|
|
reading = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
PipeEndpoint::~PipeEndpoint()
|
|
|
|
{
|
|
|
|
if ( channel )
|
|
|
|
Disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PipeEndpoint::Connect(PipeEndpoint* destination)
|
|
|
|
{
|
|
|
|
assert(!channel);
|
|
|
|
assert(!destination->channel);
|
2014-04-30 10:16:43 -04:00
|
|
|
const size_t BUFFER_SIZE = 64 * 1024;
|
2013-04-24 11:32:36 -04:00
|
|
|
size_t size = BUFFER_SIZE;
|
|
|
|
uint8_t* buffer = new uint8_t[size];
|
|
|
|
if ( !buffer )
|
|
|
|
return false;
|
|
|
|
destination->reading = !(reading = false);
|
|
|
|
if ( !(destination->channel = channel = new PipeChannel(buffer, size)) )
|
|
|
|
{
|
|
|
|
delete[] buffer;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PipeEndpoint::Disconnect()
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return;
|
2013-04-24 11:32:36 -04:00
|
|
|
if ( reading )
|
|
|
|
channel->CloseReading();
|
|
|
|
else
|
|
|
|
channel->CloseWriting();
|
2015-10-08 19:40:55 -04:00
|
|
|
channel = NULL;
|
2013-04-24 11:32:36 -04:00
|
|
|
}
|
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeEndpoint::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
|
|
|
|
{
|
|
|
|
if ( !reading )
|
|
|
|
return errno = EBADF, -1;
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return 0;
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t result = channel->recv(ctx, buf, count, flags);
|
|
|
|
CurrentThread()->yield_to_tid = 0;
|
|
|
|
Scheduler::ScheduleTrueThread();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t PipeEndpoint::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
|
|
|
|
{
|
|
|
|
if ( !reading )
|
|
|
|
return errno = EBADF, -1;
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return 0;
|
2017-01-09 17:40:56 -05:00
|
|
|
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 )
|
|
|
|
return errno = EBADF, -1;
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
{
|
|
|
|
if ( !(flags & MSG_NOSIGNAL) )
|
|
|
|
CurrentThread()->DeliverSignal(SIGPIPE);
|
|
|
|
return errno = EPIPE, -1;
|
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
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;
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
{
|
|
|
|
if ( !(flags & MSG_NOSIGNAL) )
|
|
|
|
CurrentThread()->DeliverSignal(SIGPIPE);
|
|
|
|
return errno = EPIPE, -1;
|
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
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)
|
2013-04-24 11:32:36 -04:00
|
|
|
{
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( !reading )
|
|
|
|
return errno = EBADF, -1;
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t result = channel->readv(ctx, iov, iovcnt);
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return 0;
|
2014-10-03 18:47:20 -04:00
|
|
|
CurrentThread()->yield_to_tid = 0;
|
|
|
|
Scheduler::ScheduleTrueThread();
|
|
|
|
return result;
|
2013-04-24 11:32:36 -04:00
|
|
|
}
|
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeEndpoint::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
2013-04-24 11:32:36 -04:00
|
|
|
{
|
2014-10-03 18:47:20 -04:00
|
|
|
if ( reading )
|
|
|
|
return errno = EBADF, -1;
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
{
|
|
|
|
CurrentThread()->DeliverSignal(SIGPIPE);
|
|
|
|
return errno = EPIPE, -1;
|
|
|
|
}
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t result = channel->writev(ctx, iov, iovcnt);
|
2014-10-03 18:47:20 -04:00
|
|
|
CurrentThread()->yield_to_tid = 0;
|
|
|
|
Scheduler::ScheduleTrueThread();
|
|
|
|
return result;
|
2013-04-24 11:32:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int PipeEndpoint::poll(ioctx_t* ctx, PollNode* node)
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return 0;
|
2014-04-29 16:16:07 -04:00
|
|
|
return reading ? channel->read_poll(ctx, node)
|
|
|
|
: channel->write_poll(ctx, node);
|
2013-04-24 11:32:36 -04:00
|
|
|
}
|
|
|
|
|
2014-04-30 17:14:20 -04:00
|
|
|
bool PipeEndpoint::GetSIGPIPEDelivery()
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return errno = EINVAL, true;
|
2014-04-30 17:14:20 -04:00
|
|
|
return !reading ? channel->GetSIGPIPEDelivery() : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PipeEndpoint::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return errno = EINVAL, false;
|
2014-04-30 17:14:20 -04:00
|
|
|
if ( !reading )
|
|
|
|
channel->SetSIGPIPEDelivery(deliver_sigpipe);
|
|
|
|
else if ( reading && deliver_sigpipe != false )
|
|
|
|
return errno = EINVAL, false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-30 11:25:52 -04:00
|
|
|
size_t PipeEndpoint::Size()
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return errno = EINVAL, 0;
|
2014-04-30 11:25:52 -04:00
|
|
|
return reading ? channel->ReadSize()
|
|
|
|
: channel->WriteSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PipeEndpoint::Resize(size_t new_size)
|
|
|
|
{
|
2016-08-06 09:44:37 -04:00
|
|
|
if ( !channel )
|
|
|
|
return errno = EINVAL, false;
|
2014-04-30 11:25:52 -04:00
|
|
|
return reading ? channel->ReadResize(new_size)
|
|
|
|
: channel->WriteResize(new_size);
|
|
|
|
}
|
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
class PipeNode : public AbstractInode
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
|
|
|
public:
|
2013-04-24 11:32:36 -04:00
|
|
|
PipeNode(dev_t dev, uid_t owner, gid_t group, mode_t mode);
|
2015-05-09 15:58:53 -04:00
|
|
|
virtual ~PipeNode();
|
2017-01-09 17:40:56 -05:00
|
|
|
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
|
|
|
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
|
2013-01-02 11:34:40 -05:00
|
|
|
virtual int poll(ioctx_t* ctx, PollNode* node);
|
2012-08-07 18:19:44 -04:00
|
|
|
|
2015-05-09 15:58:53 -04:00
|
|
|
public:
|
|
|
|
bool Connect(PipeNode* destination);
|
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
private:
|
2013-04-24 11:32:36 -04:00
|
|
|
PipeEndpoint endpoint;
|
2012-08-07 18:19:44 -04:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
bool PipeNode::Connect(PipeNode* destination)
|
|
|
|
{
|
|
|
|
return endpoint.Connect(&destination->endpoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
PipeNode::PipeNode(dev_t dev, uid_t owner, gid_t group, mode_t mode)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
|
|
|
inode_type = INODE_TYPE_STREAM;
|
|
|
|
this->dev = dev;
|
|
|
|
this->ino = (ino_t) this;
|
|
|
|
this->stat_uid = owner;
|
|
|
|
this->stat_gid = group;
|
2021-07-15 18:38:57 -04:00
|
|
|
this->type = S_IFIFO;
|
2012-08-07 18:19:44 -04:00
|
|
|
this->stat_mode = (mode & S_SETABLE) | this->type;
|
2017-01-09 17:40:56 -05:00
|
|
|
supports_iovec = true;
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
PipeNode::~PipeNode()
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeNode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
return endpoint.readv(ctx, iov, iovcnt);
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2017-01-09 17:40:56 -05:00
|
|
|
ssize_t PipeNode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2017-01-09 17:40:56 -05:00
|
|
|
return endpoint.writev(ctx, iov, iovcnt);
|
2012-08-07 18:19:44 -04:00
|
|
|
}
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
int PipeNode::poll(ioctx_t* ctx, PollNode* node)
|
2013-01-02 11:34:40 -05:00
|
|
|
{
|
2013-04-24 11:32:36 -04:00
|
|
|
return endpoint.poll(ctx, node);
|
2013-01-02 11:34:40 -05:00
|
|
|
}
|
|
|
|
|
2015-01-22 18:29:04 -05:00
|
|
|
int sys_pipe2(int* pipefd, int flags)
|
2012-08-07 18:19:44 -04:00
|
|
|
{
|
2014-01-15 13:46:36 -05:00
|
|
|
int fdflags = 0;
|
|
|
|
if ( flags & O_CLOEXEC ) fdflags |= FD_CLOEXEC;
|
|
|
|
if ( flags & O_CLOFORK ) fdflags |= FD_CLOFORK;
|
|
|
|
flags &= ~(O_CLOEXEC | O_CLOFORK);
|
|
|
|
|
|
|
|
if ( flags & ~(O_NONBLOCK) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
Process* process = CurrentProcess();
|
|
|
|
uid_t uid = process->uid;
|
|
|
|
uid_t gid = process->gid;
|
|
|
|
mode_t mode = 0600;
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
Ref<PipeNode> recv_inode(new PipeNode(0, uid, gid, mode));
|
|
|
|
if ( !recv_inode ) return -1;
|
|
|
|
Ref<PipeNode> send_inode(new PipeNode(0, uid, gid, mode));
|
2012-08-07 18:19:44 -04:00
|
|
|
if ( !send_inode ) return -1;
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2013-04-24 11:32:36 -04:00
|
|
|
if ( !send_inode->Connect(recv_inode.Get()) )
|
|
|
|
return -1;
|
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
Ref<Vnode> recv_vnode(new Vnode(recv_inode, Ref<Vnode>(NULL), 0, 0));
|
|
|
|
Ref<Vnode> send_vnode(new Vnode(send_inode, Ref<Vnode>(NULL), 0, 0));
|
|
|
|
if ( !recv_vnode || !send_vnode ) return -1;
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2017-02-12 09:21:27 -05:00
|
|
|
Ref<Descriptor> recv_desc(new Descriptor(recv_vnode, O_READ | flags));
|
|
|
|
Ref<Descriptor> send_desc(new Descriptor(send_vnode, O_WRITE | flags));
|
2012-08-07 18:19:44 -04:00
|
|
|
if ( !recv_desc || !send_desc ) return -1;
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
Ref<DescriptorTable> dtable = process->GetDTable();
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
int recv_index, send_index;
|
2014-01-15 13:46:36 -05:00
|
|
|
if ( 0 <= (recv_index = dtable->Allocate(recv_desc, fdflags)) )
|
2011-11-16 02:37:29 -05:00
|
|
|
{
|
2014-01-15 13:46:36 -05:00
|
|
|
if ( 0 <= (send_index = dtable->Allocate(send_desc, fdflags)) )
|
2011-11-16 02:37:29 -05:00
|
|
|
{
|
2012-08-07 18:19:44 -04:00
|
|
|
int ret[2] = { recv_index, send_index };
|
|
|
|
if ( CopyToUser(pipefd, ret, sizeof(ret)) )
|
|
|
|
return 0;
|
2011-11-16 02:37:29 -05:00
|
|
|
|
2012-08-07 18:19:44 -04:00
|
|
|
dtable->Free(send_index);
|
2011-11-16 02:37:29 -05:00
|
|
|
}
|
2012-08-07 18:19:44 -04:00
|
|
|
dtable->Free(recv_index);
|
2011-11-16 02:37:29 -05:00
|
|
|
}
|
2012-08-07 18:19:44 -04:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Sortix
|