2#include "pedigree/kernel/process/Process.h"
3#include "pedigree/kernel/process/TerminationDeferral.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/ProcessorInformation.h"
8#include "pedigree/kernel/processor/VirtualAddressSpace.h"
9#include "pedigree/kernel/syscallError.h"
10#include "pedigree/kernel/utilities/Pointers.h"
11#include "pedigree/kernel/utilities/assert.h"
15#include "FileDescriptor.h"
16#include "PosixSubsystem.h"
17#include "modules/system/vfs/Pipe.h"
18#include "pipe-transfer-syscalls.h"
22constexpr unsigned KnownFlags = 0xf;
23constexpr unsigned Nonblock = 2;
24constexpr unsigned Gift = 8;
25constexpr size_t MaximumVectors = 1024;
26constexpr size_t MaximumTransfer = 0x7ffff000;
27using Status = PipeBuffer::Status;
29bool importVectors(
const struct iovec* user,
size_t count,
bool gift,
32 if (count > MaximumVectors) {
33 SYSCALL_ERROR(InvalidArgument);
40 SYSCALL_ERROR(OutOfMemory);
44 SYSCALL_ERROR(BadAddress);
49 for (
size_t i = 0; i < count; ++i) {
50 auto& vector = vectors.get()[i];
51 const uintptr_t base =
reinterpret_cast<uintptr_t
>(vector.iov_base);
52 if (vector.iov_len > (~
size_t(0) >> 1)) {
53 SYSCALL_ERROR(InvalidArgument);
57 const size_t checkedLength =
58 count == 1 && vector.iov_len > MaximumTransfer ? MaximumTransfer : vector.iov_len;
59 if (checkedLength - 1 > ~uintptr_t(0) - base || base < space.
getUserStart() ||
62 !space.
isAddressValid(
reinterpret_cast<void*
>(base + checkedLength - 1))) {
63 SYSCALL_ERROR(BadAddress);
66 if (gift && (base % pageSize || vector.iov_len % pageSize)) {
67 SYSCALL_ERROR(InvalidArgument);
71 if (vector.iov_len > MaximumTransfer - total)
72 vector.iov_len = MaximumTransfer - total;
73 total += vector.iov_len;
78ssize_t vmspliceCopy(
Thread* thread,
Pipe* pipe,
bool writing,
const struct iovec* vectors,
79 size_t vectorCount,
size_t maximum,
bool canBlock,
bool& pipeSignal) {
82 SYSCALL_ERROR(OutOfMemory);
86 for (
size_t i = 0; i < vectorCount && copied < maximum; ++i) {
87 if (!vectors[i].iov_len)
89 if (thread->getInterruptionReason() == Thread::InterruptedBySignal ||
91 SYSCALL_ERROR(Interrupted);
94 const size_t remaining = maximum - copied;
95 const size_t requested = vectors[i].iov_len < remaining ? vectors[i].iov_len : remaining;
98 const auto reserved = writing
99 ? pipe->reserveWrite(requested, canBlock && !copied, writeReservation)
100 : pipe->reserveRead(requested, canBlock && !copied, readReservation);
101 if (reserved.status != Status::Ready) {
102 switch (reserved.status) {
106 SYSCALL_ERROR(BrokenPipe);
109 case Status::WouldBlock:
110 SYSCALL_ERROR(NoMoreProcesses);
112 case Status::Interrupted:
113 SYSCALL_ERROR(Interrupted);
115 case Status::Invalid:
116 SYSCALL_ERROR(InvalidArgument);
124 const size_t amount = writing ? writeReservation.size() : readReservation.size();
125 assert(amount && amount <= requested);
130 readReservation.copyTo(scratch.get(), amount);
134 SYSCALL_ERROR(BadAddress);
138 if (thread->getInterruptionReason() == Thread::InterruptedBySignal ||
140 SYSCALL_ERROR(Interrupted);
143 const auto committed = writeReservation.commit(scratch.get(), amount);
144 if (committed.status != Status::Ready) {
145 if (committed.status == Status::Closed) {
147 SYSCALL_ERROR(BrokenPipe);
149 SYSCALL_ERROR(InvalidArgument);
153 assert(committed.count == amount);
155 readReservation.consume(amount);
159 if (amount < requested)
164 return static_cast<ssize_t
>(copied);
170ssize_t posix_vmsplice(
int fd,
const struct iovec* userVectors,
size_t vectorCount,
175 thread->clearInterruption();
177 if (flags & ~KnownFlags) {
178 SYSCALL_ERROR(InvalidArgument);
181 bool pipeSignal =
false;
182 const ssize_t result = [&]() -> ssize_t {
184 if (!subsystem || !subsystem->acquireFileDescriptor(fd, descriptor)) {
185 SYSCALL_ERROR(BadFileDescriptor);
189 const int mode = status & O_ACCMODE;
190 if ((status & O_PATH) || (mode != O_RDONLY && mode != O_WRONLY && mode != O_RDWR)) {
191 SYSCALL_ERROR(BadFileDescriptor);
194 const bool writing = mode != O_RDONLY;
197 if (!importVectors(userVectors, vectorCount, writing && (flags & Gift), vectors, total))
201 if (!descriptor->getFile() ||
202 !(descriptor->getFile()->
isPipe() || descriptor->getFile()->
isFifo())) {
203 SYSCALL_ERROR(BadFileDescriptor);
206 const size_t maximum = total < PipeBuffer::Capacity ? total : PipeBuffer::Capacity;
208 return vmspliceCopy(thread,
Pipe::fromFile(descriptor->getFile()), writing, vectors.get(),
209 vectorCount, maximum, !(flags & Nonblock), pipeSignal);
211 const size_t error = result < 0 ? thread->
getErrno() : 0;
212 thread->clearInterruption();
214 subsystem->threadException(thread, Subsystem::Pipe);
int getStatusFlags() const
Get current status flags.
virtual bool isFifo() const
virtual bool isPipe() const
static constexpr size_t getPageSize() PURE
static Pipe * fromFile(File *pF)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()
void setErrno(size_t err)
@ Continue
No unwind necessary, carry on as normal.
UnwindType getUnwindState()
Process * getParent() const
virtual uintptr_t getUserStart() const =0
virtual uintptr_t getKernelStart() const =0
virtual bool isAddressValid(void *virtualAddress)=0