Skip to content

Commit c6b7bd4

Browse files
authored
[libc] Support _IONBF buffering for read_unlocked (llvm#120677)
Support _IONBF buffering for read_unlocked. Add the functions read_unlocked_nbf() and read_unlocked_fbf(). Fixes: llvm#120155
1 parent 783dc59 commit c6b7bd4

File tree

2 files changed

+59
-13
lines changed

2 files changed

+59
-13
lines changed

libc/src/__support/File/file.cpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) {
4242
if (pos > 0) { // If the buffer is not empty
4343
// Flush the buffer
4444
const size_t write_size = pos;
45-
auto write_result = platform_write(this, buf, write_size);
45+
FileIOResult write_result = platform_write(this, buf, write_size);
4646
pos = 0; // Buffer is now empty so reset pos to the beginning.
4747
// If less bytes were written than expected, then an error occurred.
4848
if (write_result < write_size) {
@@ -52,7 +52,7 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) {
5252
}
5353
}
5454

55-
auto write_result = platform_write(this, data, len);
55+
FileIOResult write_result = platform_write(this, data, len);
5656
if (write_result < len)
5757
err = true;
5858
return write_result;
@@ -99,7 +99,7 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) {
9999
// is full.
100100
const size_t write_size = pos;
101101

102-
auto buf_result = platform_write(this, buf, write_size);
102+
FileIOResult buf_result = platform_write(this, buf, write_size);
103103
size_t bytes_written = buf_result.value;
104104

105105
pos = 0; // Buffer is now empty so reset pos to the beginning.
@@ -121,7 +121,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) {
121121
pos = remainder.size();
122122
} else {
123123

124-
auto result = platform_write(this, remainder.data(), remainder.size());
124+
FileIOResult result =
125+
platform_write(this, remainder.data(), remainder.size());
125126
size_t bytes_written = buf_result.value;
126127

127128
// If less bytes were written than expected, then an error occurred. Return
@@ -190,6 +191,17 @@ FileIOResult File::read_unlocked(void *data, size_t len) {
190191

191192
prev_op = FileOp::READ;
192193

194+
if (bufmode == _IONBF) { // unbuffered.
195+
return read_unlocked_nbf(static_cast<uint8_t *>(data), len);
196+
} else if (bufmode == _IOFBF) { // fully buffered
197+
return read_unlocked_fbf(static_cast<uint8_t *>(data), len);
198+
} else /*if (bufmode == _IOLBF) */ { // line buffered
199+
// There is no line buffered mode for read. Use fully buffered instead.
200+
return read_unlocked_fbf(static_cast<uint8_t *>(data), len);
201+
}
202+
}
203+
204+
size_t File::copy_data_from_buf(uint8_t *data, size_t len) {
193205
cpp::span<uint8_t> bufref(static_cast<uint8_t *>(buf), bufsize);
194206
cpp::span<uint8_t> dataref(static_cast<uint8_t *>(data), len);
195207

@@ -209,32 +221,42 @@ FileIOResult File::read_unlocked(void *data, size_t len) {
209221
for (size_t i = 0; i < available_data; ++i)
210222
dataref[i] = bufref[i + pos];
211223
read_limit = pos = 0; // Reset the pointers.
224+
225+
return available_data;
226+
}
227+
228+
FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) {
229+
// Read data from the buffer first.
230+
size_t available_data = copy_data_from_buf(data, len);
231+
if (available_data == len)
232+
return available_data;
233+
212234
// Update the dataref to reflect that fact that we have already
213235
// copied |available_data| into |data|.
214-
dataref = cpp::span<uint8_t>(dataref.data() + available_data,
215-
dataref.size() - available_data);
216-
217236
size_t to_fetch = len - available_data;
237+
cpp::span<uint8_t> dataref(static_cast<uint8_t *>(data) + available_data,
238+
to_fetch);
239+
218240
if (to_fetch > bufsize) {
219-
auto result = platform_read(this, dataref.data(), to_fetch);
241+
FileIOResult result = platform_read(this, dataref.data(), to_fetch);
220242
size_t fetched_size = result.value;
221243
if (result.has_error() || fetched_size < to_fetch) {
222244
if (!result.has_error())
223245
eof = true;
224246
else
225247
err = true;
226-
return {available_data + fetched_size, result.has_error()};
248+
return {available_data + fetched_size, result.error};
227249
}
228250
return len;
229251
}
230252

231253
// Fetch and buffer another buffer worth of data.
232-
auto result = platform_read(this, buf, bufsize);
254+
FileIOResult result = platform_read(this, buf, bufsize);
233255
size_t fetched_size = result.value;
234256
read_limit += fetched_size;
235257
size_t transfer_size = fetched_size >= to_fetch ? to_fetch : fetched_size;
236258
for (size_t i = 0; i < transfer_size; ++i)
237-
dataref[i] = bufref[i];
259+
dataref[i] = buf[i];
238260
pos += transfer_size;
239261
if (result.has_error() || fetched_size < to_fetch) {
240262
if (!result.has_error())
@@ -245,6 +267,26 @@ FileIOResult File::read_unlocked(void *data, size_t len) {
245267
return {transfer_size + available_data, result.error};
246268
}
247269

270+
FileIOResult File::read_unlocked_nbf(uint8_t *data, size_t len) {
271+
// Check whether there is a character in the ungetc buffer.
272+
size_t available_data = copy_data_from_buf(data, len);
273+
if (available_data == len)
274+
return available_data;
275+
276+
// Directly copy the data into |data|.
277+
cpp::span<uint8_t> dataref(static_cast<uint8_t *>(data) + available_data,
278+
len - available_data);
279+
FileIOResult result = platform_read(this, dataref.data(), dataref.size());
280+
281+
if (result.has_error() || result < dataref.size()) {
282+
if (!result.has_error())
283+
eof = true;
284+
else
285+
err = true;
286+
}
287+
return {result + available_data, result.error};
288+
}
289+
248290
int File::ungetc_unlocked(int c) {
249291
// There is no meaning to unget if:
250292
// 1. You are trying to push back EOF.
@@ -287,7 +329,7 @@ ErrorOr<int> File::seek(off_t offset, int whence) {
287329
FileLock lock(this);
288330
if (prev_op == FileOp::WRITE && pos > 0) {
289331

290-
auto buf_result = platform_write(this, buf, pos);
332+
FileIOResult buf_result = platform_write(this, buf, pos);
291333
if (buf_result.has_error() || buf_result.value < pos) {
292334
err = true;
293335
return Error(buf_result.error);
@@ -325,7 +367,7 @@ ErrorOr<off_t> File::tell() {
325367

326368
int File::flush_unlocked() {
327369
if (prev_op == FileOp::WRITE && pos > 0) {
328-
auto buf_result = platform_write(this, buf, pos);
370+
FileIOResult buf_result = platform_write(this, buf, pos);
329371
if (buf_result.has_error() || buf_result.value < pos) {
330372
err = true;
331373
return buf_result.error;

libc/src/__support/File/file.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,10 @@ class File {
280280
FileIOResult write_unlocked_fbf(const uint8_t *data, size_t len);
281281
FileIOResult write_unlocked_nbf(const uint8_t *data, size_t len);
282282

283+
FileIOResult read_unlocked_fbf(uint8_t *data, size_t len);
284+
FileIOResult read_unlocked_nbf(uint8_t *data, size_t len);
285+
size_t copy_data_from_buf(uint8_t *data, size_t len);
286+
283287
constexpr void adjust_buf() {
284288
if (read_allowed() && (buf == nullptr || bufsize == 0)) {
285289
// We should allow atleast one ungetc operation.

0 commit comments

Comments
 (0)