SimpleKernel 1.17.0
Loading...
Searching...
No Matches
file_descriptor.cpp
Go to the documentation of this file.
1
5#include "file_descriptor.hpp"
6
7#include "kernel_log.hpp"
8
9namespace filesystem {
10
12 : table_{}, open_count_(0), lock_{"fd_table"} {}
13
15 CloseAll().or_else([](auto&& err) {
16 klog::Warn("Failed to close all files in destructor: {}", err.message());
17 return Expected<void>{};
18 });
19}
20
22 : open_count_(other.open_count_), lock_{"fd_table"} {
23 LockGuard guard(other.lock_);
24
25 for (int i = 0; i < kMaxFd; ++i) {
26 table_[i] = other.table_[i];
27 other.table_[i] = nullptr;
28 }
29
30 other.open_count_ = 0;
31}
32
35 if (this != &other) {
36 // 先关闭当前的所有文件
37 CloseAll().or_else([](auto&& err) {
38 klog::Warn("Failed to close all files in move assignment: {}",
39 err.message());
40 return Expected<void>{};
41 });
42
43 // 使用地址确定加锁顺序,避免死锁
44 auto* first_lock = (this < &other) ? &lock_ : &other.lock_;
45 auto* second_lock = (this < &other) ? &other.lock_ : &lock_;
46 LockGuard guard1(*first_lock);
47 LockGuard guard2(*second_lock);
48
49 for (int i = 0; i < kMaxFd; ++i) {
50 table_[i] = other.table_[i];
51 other.table_[i] = nullptr;
52 }
53
54 open_count_ = other.open_count_;
55 other.open_count_ = 0;
56 }
57
58 return *this;
59}
60
62 if (file == nullptr) {
63 return std::unexpected(Error(ErrorCode::kInvalidArgument));
64 }
65
66 LockGuard guard(lock_);
67
68 // 从 3 开始查找(0/1/2 预留给标准流)
69 for (int fd = 3; fd < kMaxFd; ++fd) {
70 if (table_[fd] == nullptr) {
71 table_[fd] = file;
72 ++open_count_;
73 return fd;
74 }
75 }
76
77 return std::unexpected(Error(ErrorCode::kFsFdTableFull));
78}
79
81 if (fd < 0 || fd >= kMaxFd) {
82 return nullptr;
83 }
84
85 LockGuard guard(lock_);
86 return table_[fd];
87}
88
90 if (fd < 0 || fd >= kMaxFd) {
91 return std::unexpected(Error(ErrorCode::kFsInvalidFd));
92 }
93
94 LockGuard guard(lock_);
95
96 if (table_[fd] == nullptr) {
97 return std::unexpected(Error(ErrorCode::kFsInvalidFd));
98 }
99
100 table_[fd] = nullptr;
101 --open_count_;
102
103 return {};
104}
105
106auto FileDescriptorTable::Dup(int old_fd, int new_fd) -> Expected<int> {
107 if (old_fd < 0 || old_fd >= kMaxFd) {
108 return std::unexpected(Error(ErrorCode::kFsInvalidFd));
109 }
110
111 LockGuard guard(lock_);
112
113 vfs::File* file = table_[old_fd];
114 if (file == nullptr) {
115 return std::unexpected(Error(ErrorCode::kFsInvalidFd));
116 }
117
118 if (new_fd >= 0 && new_fd < kMaxFd) {
119 // 关闭目标 fd 如果已打开
120 if (table_[new_fd] != nullptr) {
121 table_[new_fd] = nullptr;
122 --open_count_;
123 }
124
125 table_[new_fd] = file;
126 ++open_count_;
127 return new_fd;
128 }
129
130 // 分配新的 fd
131 if (new_fd == -1) {
132 for (int fd = kStderrFd + 1; fd < kMaxFd; ++fd) {
133 if (table_[fd] == nullptr) {
134 table_[fd] = file;
135 ++open_count_;
136 return fd;
137 }
138 }
139 }
140
141 return std::unexpected(Error(ErrorCode::kFsFdTableFull));
142}
143
145 LockGuard guard(lock_);
146
147 for (int fd = 0; fd < kMaxFd; ++fd) {
148 if (table_[fd] != nullptr) {
149 // 注意:这里不调用 VFS Close,因为 File 对象可能在其他地方共享
150 // 实际关闭操作由调用者负责
151 table_[fd] = nullptr;
152 }
153 }
154
155 open_count_ = 0;
156 return {};
157}
158
160 vfs::File* stdout_file,
161 vfs::File* stderr_file)
162 -> Expected<void> {
163 LockGuard guard(lock_);
164
165 // 仅对之前未占用的槽位增加计数
166 if (table_[kStdinFd] == nullptr && stdin_file != nullptr) {
167 ++open_count_;
168 }
169 if (table_[kStdoutFd] == nullptr && stdout_file != nullptr) {
170 ++open_count_;
171 }
172 if (table_[kStderrFd] == nullptr && stderr_file != nullptr) {
173 ++open_count_;
174 }
175
176 table_[kStdinFd] = stdin_file;
177 table_[kStdoutFd] = stdout_file;
178 table_[kStderrFd] = stderr_file;
179
180 return {};
181}
182
183auto FileDescriptorTable::GetOpenCount() const -> int { return open_count_; }
184
185} // namespace filesystem
RAII 风格的锁守卫模板类
Definition spinlock.hpp:131
进程级文件描述符表
auto SetupStandardFiles(vfs::File *stdin_file, vfs::File *stdout_file, vfs::File *stderr_file) -> Expected< void >
设置标准文件描述符
auto CloseAll() -> Expected< void >
关闭所有文件描述符
auto GetOpenCount() const -> int
获取已打开文件描述符数量
auto Alloc(vfs::File *file) -> Expected< int >
分配一个最小可用 fd 并关联 File
auto Get(int fd) -> vfs::File *
获取 fd 对应的 File 对象
auto operator=(const FileDescriptorTable &) -> FileDescriptorTable &=delete
auto Dup(int old_fd, int new_fd=-1) -> Expected< int >
复制文件描述符(用于 dup/dup2)
auto Free(int fd) -> Expected< void >
释放 fd
static constexpr int kMaxFd
最大文件描述符数
std::array< vfs::File *, kMaxFd > table_
@ kInvalidArgument
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
auto Warn(etl::format_string< Args... > fmt, Args &&... args) -> void
以 WARN 级别记录日志
错误类型,用于 std::expected
Definition expected.hpp:343
File — 打开的文件实例(每次 open 产生一个)
Definition vfs.hpp:65