The Pedigree Project 0.1
FileDescriptor-transfer.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/utilities/assert.h"
10
11#include "FileDescriptor.h"
12
13namespace {
14void acquireTransferLock(Mutex& lock) {
15#if THREADS && !defined(STANDALONE_MUTEXES)
16 const bool acquired = lock.acquireForCompletion();
17#else
18 const bool acquired = lock.acquire();
19#endif
20 if (!acquired) {
21 FATAL("TransferPositionGuard could not acquire its mutex");
22 }
23}
24} // namespace
25
26FileDescriptor::TransferPositionGuard::TransferPositionGuard(const OpenFileDescriptionLease& input,
27 const OpenFileDescriptionLease& output,
28 bool lockInput, bool lockOutput)
29 : m_Input(input),
30 m_Output(output),
31 m_First(nullptr),
32 m_Second(nullptr),
33 m_InputFlags(0),
34 m_OutputFlags(0) {
35 assert(m_Input && m_Output);
36 if (lockInput) {
37 m_First = m_Input.get();
38 }
39 if (lockOutput && m_Output.get() != m_First) {
40 if (m_First) {
41 m_Second = m_Output.get();
42 } else {
43 m_First = m_Output.get();
44 }
45 }
46 if (m_Second && reinterpret_cast<uintptr_t>(m_First) > reinterpret_cast<uintptr_t>(m_Second)) {
47 OpenFileDescription* temporary = m_First;
48 m_First = m_Second;
49 m_Second = temporary;
50 }
51
52 const bool inputLocked = m_Input.get() == m_First || m_Input.get() == m_Second;
53 const bool outputLocked = m_Output.get() == m_First || m_Output.get() == m_Second;
54 // Ephemeral flag reads precede the ordered pair so they cannot invert it.
55 if (!inputLocked) {
56 LockGuard<Mutex> guard(m_Input->lock);
57 m_InputFlags = m_Input->statusFlags;
58 }
59 if (!outputLocked) {
60 if (sameDescription()) {
61 m_OutputFlags = m_InputFlags;
62 } else {
63 LockGuard<Mutex> guard(m_Output->lock);
64 m_OutputFlags = m_Output->statusFlags;
65 }
66 }
67
68 if (m_First) {
69 acquireTransferLock(m_First->lock);
70 }
71 if (m_Second) {
72 acquireTransferLock(m_Second->lock);
73 }
74 if (inputLocked) {
75 m_InputFlags = m_Input->statusFlags;
76 }
77 if (outputLocked) {
78 m_OutputFlags = m_Output->statusFlags;
79 }
80}
81
82FileDescriptor::TransferPositionGuard::~TransferPositionGuard() {
83 // Final description release can retire backing state and take other locks.
84 if (m_Second) {
85 m_Second->lock.release();
86 }
87 if (m_First) {
88 m_First->lock.release();
89 }
90}
91
92int FileDescriptor::TransferPositionGuard::statusFlags(Endpoint endpoint) const {
93 assert(endpoint == Endpoint::Input || endpoint == Endpoint::Output);
94 return endpoint == Endpoint::Input ? m_InputFlags : m_OutputFlags;
95}
96
97FileDescriptor::OpenFileDescription& FileDescriptor::TransferPositionGuard::lockedDescription(
98 Endpoint endpoint) const {
99 assert(endpoint == Endpoint::Input || endpoint == Endpoint::Output);
100 OpenFileDescription* description = endpoint == Endpoint::Input ? m_Input.get() : m_Output.get();
101 assert(description == m_First || description == m_Second);
102 return *description;
103}
104
105uint64_t FileDescriptor::TransferPositionGuard::offset(Endpoint endpoint) const {
106 return lockedDescription(endpoint).offset;
107}
108
109void FileDescriptor::TransferPositionGuard::commitOffset(Endpoint endpoint, uint64_t finalOffset) {
110 lockedDescription(endpoint).offset = finalOffset;
111}
112
113bool FileDescriptor::TransferPositionGuard::sameDescription() const {
114 return m_Input.get() == m_Output.get();
115}
Definition Mutex.h:56
void release(size_t n=1)
Definition Semaphore.cc:546
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:369
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:352