libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::ReadPort Class Reference

ReadPort class for handling read operations. More...

#include <read_port.hpp>

Inheritance diagram for LibXR::ReadPort:
[legend]
Collaboration diagram for LibXR::ReadPort:
[legend]

Public Types

enum class  BusyState : uint32_t {
  IDLE = 0 , PENDING = 1 , CLEARING = 2 , BLOCK_CLAIMED = 3 ,
  BLOCK_DETACHED = 4 , EVENT = UINT32_MAX
}
 

Public Member Functions

 ReadPort (size_t buffer_size=128)
 Constructs a ReadPort with queue sizes.
 
size_t EmptySize ()
 获取队列的剩余可用空间。 Gets the remaining available space in the queue.
 
size_t Size ()
 获取当前队列的已使用大小。 Gets the currently used size of the queue.
 
bool Readable ()
 Checks if read operations are supported.
 
ReadPortoperator= (ReadFun fun)
 赋值运算符重载,用于设置读取函数。 Overloaded assignment operator to set the read function.
 
void Finish (bool in_isr, ErrorCode ans, ReadInfoBlock &info)
 完成已由队列路径认领的读取操作。 Completes a read operation already claimed by the queue path.
 
void MarkAsRunning (ReadInfoBlock &info)
 标记读取操作为运行中。 Marks the read operation as running.
 
ErrorCode operator() (RawData data, ReadOperation &op, bool in_isr=false)
 读取操作符重载,用于执行读取操作。 Overloaded function call operator to perform a read operation.
 
virtual void OnRxDequeue (bool)
 RX 数据从软件队列成功出队后的通知。 Notification after bytes are popped from RX data queue.
 
ErrorCode ClearQueuedData (bool in_isr=false)
 清空当前已排队的 RX 字节。
 
void ProcessPendingReads (bool in_isr)
 Processes pending reads.
 
void FailAndClearAll (ErrorCode reason, bool in_isr)
 失败完成并清空当前所有挂起读操作。
 

Data Fields

ReadFun read_fun_ = nullptr
 Driver/backend read notification entry. 底层驱动或后端读取通知入口。
 
LockFreeQueue< uint8_t > * queue_data_ = nullptr
 RX payload queue. 接收数据字节队列。
 
ReadInfoBlock info_ {}
 In-flight read request metadata. 当前在途读取请求的元数据。
 
std::atomic< BusyStatebusy_ {BusyState::IDLE}
 Shared read-progress handoff state. 共享的读进度交接状态。
 
ErrorCode block_result_ = ErrorCode::OK
 Final status for the current BLOCK read.
 

Detailed Description

ReadPort class for handling read operations.

处理读取操作的ReadPort类。

Definition at line 17 of file read_port.hpp.

Member Enumeration Documentation

◆ BusyState

enum class LibXR::ReadPort::BusyState : uint32_t
strong
Enumerator
IDLE 

No active waiter and no pending completion. 无等待者、无挂起完成。

PENDING 

Driver accepted the request; completion still owns progress. 请求已交给底层推进。

CLEARING 

ClearQueuedData() owns software dequeue progress. ClearQueuedData() 占有软件出队进度。

BLOCK_CLAIMED 

BLOCK wakeup already belongs to the current waiter. 当前 BLOCK 唤醒已被本次等待者认领。

BLOCK_DETACHED 

Timeout detached the waiter; completion must stay silent. 超时已分离等待者,完成侧不得再唤醒。

EVENT 

Data arrived before a waiter was armed; next caller must re-check queue. 数据先到,后续调用者要重查队列。

Definition at line 38 of file read_port.hpp.

39 {
40 IDLE = 0,
41 PENDING = 1,
43 CLEARING = 2,
45 BLOCK_CLAIMED = 3,
47 BLOCK_DETACHED = 4,
49 EVENT = UINT32_MAX
51 };
@ IDLE
No active waiter and no pending completion. 无等待者、无挂起完成。

Constructor & Destructor Documentation

◆ ReadPort()

ReadPort::ReadPort ( size_t buffer_size = 128)

Constructs a ReadPort with queue sizes.

以指定队列大小构造ReadPort。

Parameters
buffer_sizeSize of the RX byte queue. 接收字节队列的容量。
Note
包含动态内存分配。 Contains dynamic memory allocation.

Definition at line 7 of file read_port.cpp.

8 : queue_data_(buffer_size > 0 ? new (std::align_val_t(LibXR::CACHE_LINE_SIZE))
9 LockFreeQueue<uint8_t>(buffer_size)
10 : nullptr)
11{
12}
无锁队列实现 / Lock-free queue implementation
LockFreeQueue< uint8_t > * queue_data_
RX payload queue. 接收数据字节队列。
Definition read_port.hpp:54
constexpr size_t CACHE_LINE_SIZE
缓存行大小 / Cache line size
Definition libxr_def.hpp:56

Member Function Documentation

◆ ClearQueuedData()

ErrorCode ReadPort::ClearQueuedData ( bool in_isr = false)
nodiscard

清空当前已排队的 RX 字节。

Discards the RX bytes currently queued in software.

该接口只丢弃当前 queue_data_ 中已经排队的字节,不参与 backend teardown,也不会 失败完成挂起读请求。若存在正在推进的读请求,则返回 BUSY。 This API only discards the bytes already queued in queue_data_. It does not participate in backend teardown and does not fail-complete an in-flight read. Returns BUSY when a read request is currently in progress.

Note
After this call claims CLEARING, ordinary reads can no longer consume the current software-queue snapshot. Bytes that arrive after the snapshot may remain queued for a later reader/clear call.
本次调用 claim CLEARING 之后,普通读不会再消费当前软件队列快照;在快照 之后新到达的字节,可以留给后续读取或下次清队列。
Parameters
in_isr是否在 ISR 上下文 / Whether running in ISR context
Returns
OK 表示本次清队列成功完成;BUSY 表示当前有读请求占有该端口。 OK means the clear operation completed; BUSY means an active read still owns this port.

Definition at line 257 of file read_port.cpp.

258{
259 ASSERT(queue_data_ != nullptr);
260
261 while (true)
262 {
263 auto state = busy_.load(std::memory_order_acquire);
264 if (state != BusyState::IDLE && state != BusyState::EVENT)
265 {
266 return ErrorCode::BUSY;
267 }
268
269 BusyState expected = state;
270 if (!busy_.compare_exchange_strong(expected, BusyState::CLEARING,
271 std::memory_order_acq_rel,
272 std::memory_order_acquire))
273 {
274 if (expected != BusyState::IDLE && expected != BusyState::EVENT)
275 {
276 return ErrorCode::BUSY;
277 }
278 continue;
279 }
280
281 const size_t queued_size = queue_data_->Size();
282 if (queued_size == 0)
283 {
284 busy_.store(BusyState::IDLE, std::memory_order_release);
285 return ErrorCode::OK;
286 }
287
288 const ErrorCode pop_ans = queue_data_->PopBatch(nullptr, queued_size);
289 if (pop_ans == ErrorCode::OK)
290 {
291 OnRxDequeue(in_isr);
292 }
293 else
294 {
295 // With CLEARING, ordinary reads cannot race this pop. EMPTY here means a
296 // stronger path such as FailAndClearAll() reset the queue concurrently.
297 // 有了 CLEARING 之后,普通读不会再与本次 Pop 竞争。这里如果是 EMPTY,
298 // 说明是 FailAndClearAll() 之类更强的路径并发 reset 了队列。
299 ASSERT(pop_ans == ErrorCode::EMPTY);
300 }
301
303 std::memory_order_release);
304 return ErrorCode::OK;
305 }
306}
size_t Size() const
获取当前队列中的元素数量 / Returns the number of elements currently in the queue
ErrorCode PopBatch(Data *data, size_t size)
批量弹出数据 / Pops multiple elements from the queue
std::atomic< BusyState > busy_
Shared read-progress handoff state. 共享的读进度交接状态。
Definition read_port.hpp:56
virtual void OnRxDequeue(bool)
RX 数据从软件队列成功出队后的通知。 Notification after bytes are popped from RX data queue.
ErrorCode
定义错误码枚举
@ BUSY
忙碌 | Busy
@ EMPTY
为空 | Empty
@ OK
操作成功 | Operation successful

◆ EmptySize()

size_t ReadPort::EmptySize ( )

获取队列的剩余可用空间。 Gets the remaining available space in the queue.

该函数返回 queue_data_ 中当前可用的空闲空间大小。 This function returns the size of the available empty space in queue_data_.

Returns
返回队列的空闲大小(单位:字节)。 Returns the empty size of the queue (in bytes).

Definition at line 14 of file read_port.cpp.

15{
16 ASSERT(queue_data_ != nullptr);
17 return queue_data_->EmptySize();
18}
size_t EmptySize()
计算队列剩余可用空间 / Calculates the remaining available space in the queue

◆ FailAndClearAll()

void ReadPort::FailAndClearAll ( ErrorCode reason,
bool in_isr )

失败完成并清空当前所有挂起读操作。

Fail-complete and clear all currently pending read operations.

Note
Driver-only: call this only after the backend is known to be unavailable.
仅供驱动层在后端已明确不可用后调用。
The surrounding driver must already guarantee that no new front-end submissions or back-end completion/data events can still arrive for this port.
外围驱动还必须先保证:这条端口后续不会再收到新的前端提交,也不会再收到 新的后端完成或数据事件。
Parameters
reason最终失败原因 / Final failure reason
in_isr是否在 ISR 上下文 / Whether running in ISR context

Definition at line 308 of file read_port.cpp.

309{
310 ASSERT(queue_data_ != nullptr);
312
313 auto state = busy_.load(std::memory_order_acquire);
314 if (state == BusyState::PENDING)
315 {
316 if (info_.op.type == ReadOperation::OperationType::BLOCK)
317 {
318 // Backend is already unavailable. Claim the waiter and complete it with
319 // the requested failure reason instead of leaving it to timeout.
320 // 后端已经不可用。这里直接 claim waiter,并用指定错误收口,
321 // 而不是让它继续超时等待。
322 BusyState expected = BusyState::PENDING;
323 if (busy_.compare_exchange_strong(expected, BusyState::BLOCK_CLAIMED,
324 std::memory_order_acq_rel,
325 std::memory_order_acquire))
326 {
327 Finish(in_isr, reason, info_);
328 return;
329 }
330 state = expected;
331 }
332 else
333 {
334 busy_.store(BusyState::IDLE, std::memory_order_release);
335 info_.op.UpdateStatus(in_isr, reason);
336 return;
337 }
338 }
339
341 {
342 return;
343 }
344
346 busy_.store(BusyState::IDLE, std::memory_order_release);
347}
void Reset()
重置队列 / Resets the queue
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
OperationType type
void Finish(bool in_isr, ErrorCode ans, ReadInfoBlock &info)
完成已由队列路径认领的读取操作。 Completes a read operation already claimed by the queue path.
Definition read_port.cpp:34
ErrorCode block_result_
Final status for the current BLOCK read.
Definition read_port.hpp:57
ReadInfoBlock info_
In-flight read request metadata. 当前在途读取请求的元数据。
Definition read_port.hpp:55
ReadOperation op
Read operation instance. 读取操作实例。

◆ Finish()

void ReadPort::Finish ( bool in_isr,
ErrorCode ans,
ReadInfoBlock & info )

完成已由队列路径认领的读取操作。 Completes a read operation already claimed by the queue path.

Parameters
in_isr指示是否在中断上下文中执行。 Indicates whether the operation is executed in an interrupt context.
ans错误码,用于指示操作的结果。 Error code indicating the result of the operation.
info需要更新状态的 ReadInfoBlock 引用。 Reference to the ReadInfoBlock whose status needs to be updated.

Definition at line 34 of file read_port.cpp.

35{
36 if (info.op.type == ReadOperation::OperationType::BLOCK)
37 {
38 // Read completion is queue-driven. ProcessPendingReads() must claim the
39 // BLOCK waiter before data is copied and Finish() is called.
40 // 读完成只走队列路径。ProcessPendingReads() 必须先 claim BLOCK waiter,
41 // 再拷贝数据并调用 Finish()。
42 ASSERT(busy_.load(std::memory_order_acquire) == BusyState::BLOCK_CLAIMED);
43 block_result_ = ans;
44 info.op.data.sem_info.sem->PostFromCallback(in_isr);
45 return;
46 }
47
48 busy_.store(BusyState::IDLE, std::memory_order_release);
49 info.op.UpdateStatus(in_isr, ans);
50}
union LibXR::Operation::@5 data
void PostFromCallback(bool in_isr)
从中断回调中释放(增加)信号量 Releases (increments) the semaphore from an ISR (Interrupt Service Routine)

◆ MarkAsRunning()

void ReadPort::MarkAsRunning ( ReadInfoBlock & info)

标记读取操作为运行中。 Marks the read operation as running.

该函数用于将 info.op_ 标记为运行状态,以指示当前正在进行读取操作。 This function marks info.op_ as running to indicate an ongoing read operation.

Parameters
info需要更新状态的 ReadInfoBlock 引用。 Reference to the ReadInfoBlock whose status needs to be updated.

Definition at line 52 of file read_port.cpp.

52{ info.op.MarkAsRunning(); }
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.

◆ OnRxDequeue()

virtual void LibXR::ReadPort::OnRxDequeue ( bool )
inlinevirtual

RX 数据从软件队列成功出队后的通知。 Notification after bytes are popped from RX data queue.

Parameters
in_isr指示是否在中断上下文中执行。 Indicates whether the operation is executed in an interrupt context.

Reimplemented in LibXR::USB::CDCUartReadPort.

Definition at line 171 of file read_port.hpp.

171{}

◆ operator()()

ErrorCode ReadPort::operator() ( RawData data,
ReadOperation & op,
bool in_isr = false )

读取操作符重载,用于执行读取操作。 Overloaded function call operator to perform a read operation.

该函数检查端口是否可读,并根据 data.size_ 和 op 的类型执行不同的操作。 This function checks if the port is readable and performs different actions based on data.size_ and the type of op.

Parameters
data包含要读取的数据。 Contains the data to be read.
Note
data.size_ == 0 is a readiness read: it completes when the RX queue is non-empty, does not consume bytes, and does not call OnRxDequeue().
data.size_ == 0 表示可读通知:RX 队列非空即完成,不消费字节,也不调用 OnRxDequeue()
Parameters
op读取操作对象,包含操作类型和同步机制。 Read operation object containing the operation type and synchronization mechanism.
in_isr指示是否在中断上下文中执行。 Indicates whether the operation is executed in an interrupt context.
Returns
返回操作的 ErrorCode,指示操作结果。 Returns an ErrorCode indicating the result of the operation.

Definition at line 54 of file read_port.cpp.

55{
56 if (Readable())
57 {
58 BusyState is_busy = busy_.load(std::memory_order_acquire);
59
60 if (is_busy != BusyState::IDLE && is_busy != BusyState::EVENT)
61 {
62 return ErrorCode::BUSY;
63 }
64
65 while (true)
66 {
67 busy_.store(BusyState::IDLE, std::memory_order_release);
68
69 auto readable_size = queue_data_->Size();
70
71 if (readable_size >= data.size_ && readable_size != 0)
72 {
73 if (data.size_ > 0)
74 {
75 auto ans =
76 queue_data_->PopBatch(reinterpret_cast<uint8_t*>(data.addr_), data.size_);
77 ASSERT(ans == ErrorCode::OK);
78 OnRxDequeue(in_isr);
79 }
80
81 if (op.type != ReadOperation::OperationType::BLOCK)
82 {
83 op.UpdateStatus(in_isr, ErrorCode::OK);
84 }
85 return ErrorCode::OK;
86 }
87
88 info_ = ReadInfoBlock{data, op};
89
90 op.MarkAsRunning();
91
92 BusyState expected = BusyState::IDLE;
93 if (!busy_.compare_exchange_strong(expected, BusyState::PENDING,
94 std::memory_order_acq_rel,
95 std::memory_order_acquire))
96 {
97 ASSERT(expected == BusyState::EVENT);
98 continue;
99 }
100
101 auto ans = read_fun_(*this, in_isr);
102 if (static_cast<int8_t>(ans) >= 0)
103 {
104 break;
105 }
106
107 // read_fun_ failed while arming/notifying the backend. Roll back only if no
108 // producer has completed this pending read concurrently.
109 // read_fun_ 挂起/通知底层失败;只有未被 producer 并发完成时,才回滚 pending。
110 expected = BusyState::PENDING;
111 if (busy_.compare_exchange_strong(expected, BusyState::IDLE,
112 std::memory_order_acq_rel,
113 std::memory_order_acquire))
114 {
115 if (op.type != ReadOperation::OperationType::BLOCK)
116 {
117 op.UpdateStatus(in_isr, ans);
118 }
119 return ans;
120 }
121
122 if (expected == BusyState::BLOCK_DETACHED)
123 {
124 return ErrorCode::TIMEOUT;
125 }
126 if (expected == BusyState::IDLE)
127 {
128 // A non-BLOCK read may have completed through ProcessPendingReads() before the
129 // arm failure returned.
130 // 非 BLOCK 读可能在挂起失败返回前,已经通过 ProcessPendingReads() 完成。
131 ASSERT(op.type != ReadOperation::OperationType::BLOCK);
132 return ErrorCode::OK;
133 }
134 ASSERT(expected == BusyState::BLOCK_CLAIMED);
135 break;
136 }
137
138 if (op.type == ReadOperation::OperationType::BLOCK)
139 {
140 ASSERT(!in_isr);
141 auto wait_ans = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
142 if (wait_ans == ErrorCode::OK)
143 {
144 // BLOCK_CLAIMED is always released by the waiter itself.
145 // BLOCK_CLAIMED 始终由 waiter 自己释放。
146#ifdef LIBXR_DEBUG_BUILD
147 auto state = busy_.load(std::memory_order_acquire);
148 ASSERT(state == BusyState::BLOCK_CLAIMED);
149#endif
150 busy_.store(BusyState::IDLE, std::memory_order_release);
151 return block_result_;
152 }
153
154 // BLOCK wait timed out after the backend had accepted the read. Cancel only if
155 // completion has not claimed this waiter.
156 // 底层已接受读请求后,BLOCK 等待超时;只有完成侧尚未 claim 当前 waiter 时才取消。
157 BusyState expected = BusyState::PENDING;
158 if (busy_.compare_exchange_strong(expected, BusyState::IDLE,
159 std::memory_order_acq_rel,
160 std::memory_order_acquire))
161 {
162 return ErrorCode::TIMEOUT;
163 }
164
165 if (expected == BusyState::BLOCK_DETACHED)
166 {
167 // The waiter had already detached before the timeout-side cancel won.
168 // 当前 waiter 已经先分离;超时侧负责把端口收回 IDLE。
169 busy_.store(BusyState::IDLE, std::memory_order_release);
170 return ErrorCode::TIMEOUT;
171 }
172
173 ASSERT(expected == BusyState::BLOCK_CLAIMED);
174
175 // Timeout lost after completion had already claimed the waiter.
176 // 超时发生得太晚,完成侧已经 claim 了当前 waiter。
177 auto finish_wait_ans = op.data.sem_info.sem->Wait(UINT32_MAX);
178 UNUSED(finish_wait_ans);
179 ASSERT(finish_wait_ans == ErrorCode::OK);
180 busy_.store(BusyState::IDLE, std::memory_order_release);
181 return block_result_;
182 }
183 else
184 {
185 return ErrorCode::OK;
186 }
187 }
188 else
189 {
191 }
192}
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
bool Readable()
Checks if read operations are supported.
Definition read_port.cpp:26
ReadFun read_fun_
Driver/backend read notification entry. 底层驱动或后端读取通知入口。
Definition read_port.hpp:53
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:53
@ TIMEOUT
超时 | Timeout
@ NOT_SUPPORT
不支持 | Not supported
Read information block structure.

◆ operator=()

ReadPort & ReadPort::operator= ( ReadFun fun)

赋值运算符重载,用于设置读取函数。 Overloaded assignment operator to set the read function.

该函数允许使用 ReadFun 类型的函数对象赋值给 ReadPort,从而设置 read_fun_。 This function allows assigning a ReadFun function object to ReadPort, setting read_fun_.

Parameters
fun要分配的读取函数。 The read function to be assigned.
Returns
返回自身的引用,以支持链式调用。 Returns a reference to itself for chaining.

Definition at line 28 of file read_port.cpp.

29{
30 read_fun_ = fun;
31 return *this;
32}

◆ ProcessPendingReads()

void ReadPort::ProcessPendingReads ( bool in_isr)

Processes pending reads.

处理挂起的读取请求。

Parameters
in_isr指示是否在中断上下文中执行。 Indicates whether the operation is executed in an interrupt context.

Definition at line 194 of file read_port.cpp.

195{
196 ASSERT(queue_data_ != nullptr);
197
198 while (true)
199 {
200 auto is_busy = busy_.load(std::memory_order_acquire);
201
202 if (is_busy == BusyState::PENDING)
203 {
204 auto size = queue_data_->Size();
205 if (size > 0 && size >= info_.data.size_)
206 {
207 if (info_.op.type == ReadOperation::OperationType::BLOCK)
208 {
209 // Read BLOCK completion is claimed here before copying data.
210 // BLOCK 读完成在这里先 claim,再拷数据。
211 BusyState expected = BusyState::PENDING;
212 if (!busy_.compare_exchange_strong(expected, BusyState::BLOCK_CLAIMED,
213 std::memory_order_acq_rel,
214 std::memory_order_acquire))
215 {
216 continue;
217 }
218 }
219
220 if (info_.data.size_ > 0)
221 {
222 auto ans = queue_data_->PopBatch(reinterpret_cast<uint8_t*>(info_.data.addr_),
224 UNUSED(ans);
225 ASSERT(ans == ErrorCode::OK);
226 Finish(in_isr, ErrorCode::OK, info_);
227 OnRxDequeue(in_isr);
228 }
229 else
230 {
231 Finish(in_isr, ErrorCode::OK, info_);
232 }
233 }
234 return;
235 }
236
237 if (is_busy == BusyState::IDLE)
238 {
239 // Data arrived before a waiter was armed. This must be a CAS: a reader may
240 // publish PENDING after the load above, and EVENT must not overwrite it.
241 // 数据先于 waiter 到达。这里必须用 CAS:读线程可能在上面的 load 之后发布
242 // PENDING,EVENT 不能覆盖它。
243 BusyState expected = BusyState::IDLE;
244 if (busy_.compare_exchange_strong(expected, BusyState::EVENT,
245 std::memory_order_acq_rel,
246 std::memory_order_acquire))
247 {
248 return;
249 }
250 continue;
251 }
252
253 return;
254 }
255}
RawData data
Data buffer. 数据缓冲区。

◆ Readable()

bool ReadPort::Readable ( )

Checks if read operations are supported.

检查是否支持读取操作。

Definition at line 26 of file read_port.cpp.

26{ return read_fun_ != nullptr; }

◆ Size()

size_t ReadPort::Size ( )

获取当前队列的已使用大小。 Gets the currently used size of the queue.

该函数返回 queue_data_ 当前已占用的空间大小。 This function returns the size of the space currently used in queue_data_.

Returns
返回队列的已使用大小(单位:字节)。 Returns the used size of the queue (in bytes).

Definition at line 20 of file read_port.cpp.

21{
22 ASSERT(queue_data_ != nullptr);
23 return queue_data_->Size();
24}

Field Documentation

◆ block_result_

ErrorCode LibXR::ReadPort::block_result_ = ErrorCode::OK

Final status for the current BLOCK read.

Definition at line 57 of file read_port.hpp.

◆ busy_

std::atomic<BusyState> LibXR::ReadPort::busy_ {BusyState::IDLE}

Shared read-progress handoff state. 共享的读进度交接状态。

Definition at line 56 of file read_port.hpp.

◆ info_

ReadInfoBlock LibXR::ReadPort::info_ {}

In-flight read request metadata. 当前在途读取请求的元数据。

Definition at line 55 of file read_port.hpp.

55{};

◆ queue_data_

LockFreeQueue<uint8_t>* LibXR::ReadPort::queue_data_ = nullptr

RX payload queue. 接收数据字节队列。

Definition at line 54 of file read_port.hpp.

◆ read_fun_

ReadFun LibXR::ReadPort::read_fun_ = nullptr

Driver/backend read notification entry. 底层驱动或后端读取通知入口。

Definition at line 53 of file read_port.hpp.


The documentation for this class was generated from the following files: