20#include "FileDescriptor.h"
24#include "modules/subsys/posix/IoEvent.h"
25#include "modules/subsys/posix/epoll-syscalls.h"
26#include "modules/subsys/posix/eventfd-syscalls.h"
27#include "modules/subsys/posix/fanotify-syscalls.h"
28#include "modules/subsys/posix/inotify-syscalls.h"
29#include "modules/subsys/posix/mqueue-syscalls.h"
30#include "modules/subsys/posix/signalfd-syscalls.h"
31#include "modules/subsys/posix/timerfd-syscalls.h"
32#include "modules/system/console/Console.h"
33#include "modules/system/vfs/File.h"
34#include "net-syscalls.h"
37constexpr int MutableStatusFlags = O_APPEND | O_NONBLOCK;
39bool isReadWrite(
int flags) {
40 return (flags & O_ACCMODE) == O_RDWR;
43void increaseFileReferences(
File* file,
int flags) {
44 if (!file || (flags & O_PATH)) {
48 const bool writer = (flags & O_ACCMODE) != O_RDONLY;
49 file->increaseRefCount(writer);
53 if (isReadWrite(flags) && (file->
isPipe() || file->
isFifo())) {
54 file->increaseRefCount(
false);
58void decreaseFileReferences(
File* file,
int flags) {
59 if (!file || (flags & O_PATH)) {
63 const bool writer = (flags & O_ACCMODE) != O_RDONLY;
64 file->decreaseRefCount(writer);
65 if (isReadWrite(flags) && (file->
isPipe() || file->
isFifo())) {
66 file->decreaseRefCount(
false);
86 networkImpl->unmonitor(retiring);
91FileDescriptor::OpenFileDescription::OpenFileDescription(
File* newFile, uint64_t initialOffset,
92 int initialStatusFlags)
96 anonymousFile(newFile),
101 consoleEpoch(newFile && !(initialStatusFlags & O_PATH) &&
103 ? static_cast<
ConsoleFile*>(newFile)->captureOpenEpoch()
105 offset(initialOffset),
106 accessFlags(initialStatusFlags & (O_PATH | O_ACCMODE)),
107 statusFlags(initialStatusFlags),
109 vfsLease(newFile && newFile->retainVfsReference()) {
111 increaseFileReferences(getFile(), statusFlags);
114FileDescriptor::OpenFileDescription::OpenFileDescription(
const FilesystemPathRef& opening,
115 uint64_t initialOffset,
116 int initialStatusFlags)
117 : OpenFileDescription(static_cast<
File*>(nullptr), initialOffset, initialStatusFlags) {
118 assert(
static_cast<bool>(opening));
120 File* node = getFile();
121 if (!(initialStatusFlags & O_PATH) && ConsoleManager::instance().isConsole(node))
122 consoleEpoch =
static_cast<ConsoleFile*
>(node)->captureOpenEpoch();
123 increaseFileReferences(node, initialStatusFlags);
133FileDescriptor::OpenFileDescription::~OpenFileDescription() {
134 assert(!descriptorOwners);
135 posix_advisory_owner_closed(m_AdvisoryOwner);
142 bool waitForReopen)
const {
143 if (getFile() && ConsoleManager::instance().isMasterConsole(getFile()))
144 return static_cast<ConsoleFile*
>(getFile())->captureOpenEpoch(waitForReopen);
148ReadyMask FileDescriptor::OpenFileDescription::queryFileReady(
bool reading,
bool writing)
const {
149 if (getFile() && ConsoleManager::instance().isConsole(getFile()))
150 return static_cast<ConsoleFile*
>(getFile())->queryEpoch(terminalEpoch(
false), reading, writing);
151 return getFile() ? getFile()->
queryReady(reading, writing) : ReadyInvalid;
155 if (getFile() && ConsoleManager::instance().isConsole(getFile()))
156 return static_cast<ConsoleFile*
>(getFile())->epochGenerations(terminalEpoch(
false));
160FileDescriptor::TerminalOperation::TerminalOperation() =
default;
161FileDescriptor::TerminalOperation::~TerminalOperation() =
default;
164 return m_OpenFile->terminalEpoch(waitForReopen);
167bool FileDescriptor::terminalHungUp()
const {
168 if (!getFile() || !ConsoleManager::instance().isConsole(getFile()))
170 auto epoch = terminalEpoch();
171 return !epoch || epoch->revoked();
174bool FileDescriptor::terminalAvailable()
const {
176 !ConsoleManager::instance().isConsole(getFile()) ||
static_cast<bool>(terminalEpoch());
179bool FileDescriptor::acquireTerminalOperation(TerminalOperation& operation)
const {
180 if (!getFile() || !ConsoleManager::instance().isConsole(getFile()))
182 operation.state = terminalEpoch();
183 return operation.state && operation.state->operations.tryAcquire(operation.operation) &&
184 !operation.state->revoked();
187uint64_t FileDescriptor::readFile(uint64_t location, uint64_t size, uintptr_t buffer,
189 if (getFile() && ConsoleManager::instance().isConsole(getFile()))
190 return static_cast<ConsoleFile*
>(getFile())->readEpoch(terminalEpoch(), size, buffer, canBlock);
191 return getFile() ? getFile()->
read(location, size, buffer, canBlock) : 0;
194uint64_t FileDescriptor::writeFile(uint64_t location, uint64_t size, uintptr_t buffer,
196 if (getFile() && ConsoleManager::instance().isConsole(getFile()))
197 return static_cast<ConsoleFile*
>(getFile())->writeEpoch(terminalEpoch(), size, buffer,
199 return getFile() ? getFile()->
write(location, size, buffer, canBlock) : 0;
226size_t FileDescriptor::OpenFileDescription::descriptorOwnerCount()
const {
228 return descriptorOwners;
231void FileDescriptor::OpenFileDescription::addDescriptorOwner() {
233 assert(descriptorOwners);
237void FileDescriptor::OpenFileDescription::removeDescriptorOwner() {
238 bool closeEndpoint =
false;
245 assert(descriptorOwners);
247 closeEndpoint = descriptorOwners == 0;
251 closingInotify = inotifyImpl;
252 closingFanotify = fanotifyImpl;
256 decreaseFileReferences(getFile(), flags);
257 if (getFile() && !(flags & O_PATH)) {
258 getFile()->
publishEvent((flags & O_ACCMODE) == O_RDONLY ? FileEvents::CloseNoWrite
259 : FileEvents::CloseWrite);
261 if (closingNetwork) {
262 closingNetwork->lastDescriptorClosed();
264 if (closingInotify) {
265 closingInotify->lastDescriptorClosed();
267 if (closingFanotify) {
268 closingFanotify->lastDescriptorClosed();
273void FileDescriptor::OpenFileDescription::ensureVfsLease() {
275 if (!path && !vfsLease && getFile()) {
295 networkImpl(nullptr),
298 fdflags(fdFlags | ((flFlags & O_CLOEXEC) ? FD_CLOEXEC : 0)),
300 m_NetworkPublished(false),
301 m_EventFdPublished(false) {
306 int fdFlags,
int flFlags)
308 networkImpl(nullptr),
311 fdflags(fdFlags | ((flFlags & O_CLOEXEC) ? FD_CLOEXEC : 0)),
312 m_OpenFile(new OpenFileDescription(path, newOffset, flFlags & ~O_CLOEXEC)),
313 m_NetworkPublished(false),
314 m_EventFdPublished(false) {}
319 networkImpl(desc.networkImpl),
320 epollImpl(desc.epollImpl),
322 fdflags(desc.fdflags),
323 m_OpenFile(desc.m_OpenFile),
324 m_NetworkPublished(false),
325 m_EventFdPublished(false) {
337 m_TimerFdPublished = timerFd->addDescriptorOwner();
339 auto signalFd =
m_OpenFile->getSignalFdImpl();
341 m_SignalFdPublished = signalFd->addDescriptorOwner();
354 networkImpl(nullptr),
359 m_NetworkPublished(false),
360 m_EventFdPublished(false) {
382 m_TimerFdPublished = timerFd->addDescriptorOwner();
384 auto signalFd =
m_OpenFile->getSignalFdImpl();
386 m_SignalFdPublished = signalFd->addDescriptorOwner();
426 (
m_OpenFile->statusFlags & ~MutableStatusFlags) | (newFlags & MutableStatusFlags);
429 bool nonblock = (
m_OpenFile->statusFlags & O_NONBLOCK) == O_NONBLOCK;
430 m_OpenFile->networkImpl->setBlocking(!nonblock);
436 m_OpenFile->statusFlags |= newFlag & MutableStatusFlags;
444 m_OpenFile->statusFlags &= ~(flag & MutableStatusFlags);
467 if (implementation) {
471 implementation->retainDescriptorLifetime(implementation);
488 if (implementation) {
509 if (implementation) {
510 m_TimerFdPublished = implementation->addDescriptorOwner();
511 assert(m_TimerFdPublished);
519bool FileDescriptor::timerFdPublished()
const {
520 return m_TimerFdPublished;
530 if (implementation) {
531 m_SignalFdPublished = implementation->addDescriptorOwner();
532 assert(m_SignalFdPublished);
540bool FileDescriptor::signalFdPublished()
const {
541 return m_SignalFdPublished;
582 if (m_TimerFdPublished) {
583 m_TimerFdPublished =
false;
586 timerFd->removeDescriptorOwner();
589 if (m_SignalFdPublished) {
590 m_SignalFdPublished =
false;
591 auto signalFd =
m_OpenFile->getSignalFdImpl();
593 signalFd->removeDescriptorOwner();
607 eventFd->removeDescriptorOwner();
613 : m_Description(description), m_Guard(m_Description->lock) {}
621 return position.offset();
626 position.setOffset(offset);
633 if (!getFile()->isSeekable()) {
634 return readFile(0, size, buffer, canBlock && !(
getStatusFlags() & O_NONBLOCK));
638 const bool shouldBlock = canBlock && !(
m_OpenFile->statusFlags & O_NONBLOCK);
639 uint64_t amount = getFile()->
read(
m_OpenFile->offset, size, buffer, shouldBlock);
648 if (!getFile()->isSeekable()) {
649 return writeFile(0, size, buffer, canBlock && !(
getStatusFlags() & O_NONBLOCK));
653 const bool shouldBlock = canBlock && !(
m_OpenFile->statusFlags & O_NONBLOCK);
655 const uint64_t amount = (
m_OpenFile->statusFlags & O_APPEND)
656 ? getFile()->
append(size, buffer, location, shouldBlock)
657 : getFile()->
write(location, size, buffer, shouldBlock);
void beginRetirement(Retirement &retirement)
SharedPointer< EpollInstance > epollImpl
Epoll implementation for this descriptor (if it is an epoll object).
void setNetworkImpl(const SharedPointer< NetworkSyscalls > &implementation)
OpenFileDescriptionLease acquireOpenFileDescription() const
int fdflags
File descriptor flags (fcntl)
void setFlags(int newFlags)
Set flags, distributing any associated changes as needed.
OpenFileDescriptionLease m_OpenFile
void setEventFdImpl(const SharedPointer< EventFd > &implementation)
bool eventFdPublished() const
void addFlag(int newFlag)
Helper to add a single flag to the descriptor flags.
void setOffset(uint64_t offset)
void removeStatusFlag(int flag)
Helper to remove a single flag from the status flags.
IoEvent * ioevent
IO event for reporting changes to files.
SharedPointer< InotifyInstance > getInotifyImpl() const
PositionGuard lockPosition() const
SharedPointer< EventFd > getEventFdImpl() const
int getFlags() const
Get current descriptor flags.
int getStatusFlags() const
Get current status flags.
void addStatusFlag(int newFlag)
Helper to add a single flag to the status flags.
void setStatusFlags(int newFlags)
Set status flags, distributing any associated changes as needed.
SharedPointer< NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it's a socket).
virtual ~FileDescriptor()
Destructor - decreases file reference count.
size_t fd
Descriptor number.
uint64_t write(uint64_t size, uintptr_t buffer, bool canBlock=true)
bool networkPublished() const
uint64_t read(uint64_t size, uintptr_t buffer, bool canBlock=true)
FileDescriptor()
Default constructor.
void setInotifyImpl(const SharedPointer< InotifyInstance > &implementation)
uint64_t getOffset() const
virtual bool retainVfsReference()
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
void cullMonitorTargets(Thread *pThread)
uint64_t append(uint64_t size, uintptr_t buffer, uint64_t &location, bool bCanBlock=true)
virtual void releaseVfsReference()
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
virtual bool isDirectory()
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)
virtual bool isFifo() const
virtual bool isPipe() const
virtual ReadyMask queryReady(bool reading, bool writing)
MUST_USE_RESULT bool addDescriptorOwner()
virtual ReadinessGenerations readinessGenerations()