[libc-commits] [libc] 75d70b7 - [libc] Make close function of the internal File class cleanup the file object.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Tue Jun 20 22:05:13 PDT 2023
Author: Siva Chandra Reddy
Date: 2023-06-21T05:05:04Z
New Revision: 75d70b73063fb5abd12643207c6dda867d955df6
URL: https://github.com/llvm/llvm-project/commit/75d70b73063fb5abd12643207c6dda867d955df6
DIFF: https://github.com/llvm/llvm-project/commit/75d70b73063fb5abd12643207c6dda867d955df6.diff
LOG: [libc] Make close function of the internal File class cleanup the file object.
Before this change, a separate static method named cleanup was used to
cleanup the file. Instead, now the close method cleans up the full file
object using the platform's close function.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D153377
Added:
Modified:
libc/src/__support/File/file.h
libc/src/__support/File/gpu/file.cpp
libc/src/__support/File/linux/file.cpp
libc/src/stdio/fclose.cpp
libc/src/stdio/fopencookie.cpp
libc/test/src/__support/File/file_test.cpp
libc/test/src/__support/File/platform_file_test.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 3a4bc89a7b311..97dc5ff66f1ca 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -56,16 +56,6 @@ class File {
// file position indicator.
using SeekFunc = ErrorOr<long>(File *, long, int);
using CloseFunc = int(File *);
- // CleanupFunc is a function which does the equivalent of this:
- //
- // void my_file_cleanup(File *f) {
- // MyFile *file = reinterpret_cast<MyFile *>(f);
- // delete file;
- // }
- //
- // Essentially, it a function which calls the delete operator on the
- // platform file object to cleanup resources held by it.
- using CleanupFunc = void(File *);
using ModeFlags = uint32_t;
@@ -102,7 +92,6 @@ class File {
ReadFunc *platform_read;
SeekFunc *platform_seek;
CloseFunc *platform_close;
- CleanupFunc *platform_cleanup;
Mutex mutex;
@@ -150,26 +139,6 @@ class File {
FileLock(FileLock &&) = delete;
};
- // This is private function and is not to be called by the users of
- // File and its derived classes. The correct way to close a file is
- // to call the File::cleanup function.
- int close() {
- {
- FileLock lock(this);
- if (prev_op == FileOp::WRITE && pos > 0) {
- auto buf_result = platform_write(this, buf, pos);
- if (buf_result.has_error() || buf_result.value < pos) {
- err = true;
- return buf_result.error;
- }
- }
- int result = platform_close(this);
- if (result != 0)
- return result;
- }
- return 0;
- }
-
protected:
constexpr bool write_allowed() const {
return mode & (static_cast<ModeFlags>(OpenMode::WRITE) |
@@ -200,28 +169,17 @@ class File {
// is zero. This way, we will not have to employ the semantics of
// the set_buffer method and allocate a buffer.
constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf,
- CleanupFunc *clf, uint8_t *buffer, size_t buffer_size,
- int buffer_mode, bool owned, ModeFlags modeflags)
+ uint8_t *buffer, size_t buffer_size, int buffer_mode,
+ bool owned, ModeFlags modeflags)
: platform_write(wf), platform_read(rf), platform_seek(sf),
- platform_close(cf), platform_cleanup(clf), mutex(false, false, false),
- ungetc_buf(0), buf(buffer), bufsize(buffer_size), bufmode(buffer_mode),
- own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE),
- read_limit(0), eof(false), err(false) {
+ platform_close(cf), mutex(false, false, false), ungetc_buf(0),
+ buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned),
+ mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0),
+ eof(false), err(false) {
if constexpr (ENABLE_BUFFER)
adjust_buf();
}
- // Close |f| and cleanup resources held by it.
- // Returns the non-zero error value if an error occurs when closing the
- // file.
- static int cleanup(File *f) {
- int close_result = f->close();
- if (close_result != 0)
- return close_result;
- f->platform_cleanup(f);
- return 0;
- }
-
// Buffered write of |len| bytes from |data| without the file lock.
FileIOResult write_unlocked(const void *data, size_t len);
@@ -261,6 +219,28 @@ class File {
return ungetc_unlocked(c);
}
+ // Does the following:
+ // 1. If in write mode, Write out any data present in the buffer.
+ // 2. Call platform_close.
+ // platform_close is expected to cleanup the complete file object.
+ int close() {
+ {
+ FileLock lock(this);
+ if (prev_op == FileOp::WRITE && pos > 0) {
+ auto buf_result = platform_write(this, buf, pos);
+ if (buf_result.has_error() || buf_result.value < pos) {
+ err = true;
+ return buf_result.error;
+ }
+ }
+ }
+ // Platform close is expected to cleanup the file data structure which
+ // includes the file mutex. Hence, we call platform_close after releasing
+ // the file lock. Another thread doing file operations while a thread is
+ // closing the file is undefined behavior as per POSIX.
+ return platform_close(this);
+ }
+
// Sets the internal buffer to |buffer| with buffering mode |mode|.
// |size| is the size of |buffer|. If |size| is non-zero, but |buffer|
// is nullptr, then a buffer owned by this file will be allocated.
@@ -331,15 +311,6 @@ class File {
}
};
-// Platform specific file implementations can simply pass a pointer to a
-// a specialization of this function as the CleanupFunc argument to the
-// File constructor. The template type argument FileType should replaced
-// with the type of the platform specific file implementation.
-template <typename FileType> void cleanup_file(File *f) {
- auto *file = reinterpret_cast<FileType *>(f);
- delete file;
-}
-
// The implementaiton of this function is provided by the platfrom_file
// library.
ErrorOr<File *> openfile(const char *path, const char *mode);
diff --git a/libc/src/__support/File/gpu/file.cpp b/libc/src/__support/File/gpu/file.cpp
index e2a0c1579ffa3..11554e692578e 100644
--- a/libc/src/__support/File/gpu/file.cpp
+++ b/libc/src/__support/File/gpu/file.cpp
@@ -26,8 +26,8 @@ class GPUFile : public File {
public:
constexpr GPUFile(uintptr_t file, File::ModeFlags modeflags)
- : File(&write_func, nullptr, nullptr, nullptr, nullptr, nullptr, 0,
- _IONBF, false, modeflags),
+ : File(&write_func, nullptr, nullptr, nullptr, nullptr, 0, _IONBF, false,
+ modeflags),
file(file) {}
uintptr_t get_file() const { return file; }
diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 704bbd0d6035e..caa7bae36a9eb 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -33,9 +33,8 @@ class LinuxFile : public File {
public:
constexpr LinuxFile(int file_descriptor, uint8_t *buffer, size_t buffer_size,
int buffer_mode, bool owned, File::ModeFlags modeflags)
- : File(&write_func, &read_func, &seek_func, &close_func,
- &cleanup_file<LinuxFile>, buffer, buffer_size, buffer_mode, owned,
- modeflags),
+ : File(&write_func, &read_func, &seek_func, &close_func, buffer,
+ buffer_size, buffer_mode, owned, modeflags),
fd(file_descriptor) {}
int get_fd() const { return fd; }
@@ -87,6 +86,7 @@ int close_func(File *f) {
if (ret < 0) {
return -ret;
}
+ delete lf;
return 0;
}
diff --git a/libc/src/stdio/fclose.cpp b/libc/src/stdio/fclose.cpp
index 1d53974fe439d..da75e9bc1fdf7 100644
--- a/libc/src/stdio/fclose.cpp
+++ b/libc/src/stdio/fclose.cpp
@@ -15,8 +15,7 @@
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, fclose, (::FILE * stream)) {
- auto *file = reinterpret_cast<__llvm_libc::File *>(stream);
- int result = File::cleanup(file);
+ int result = reinterpret_cast<__llvm_libc::File *>(stream)->close();
if (result != 0) {
libc_errno = result;
return EOF;
diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index 4c8dbe2e796a7..7a4479ccae025 100644
--- a/libc/src/stdio/fopencookie.cpp
+++ b/libc/src/stdio/fopencookie.cpp
@@ -31,8 +31,8 @@ class CookieFile : public __llvm_libc::File {
CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer,
size_t bufsize, File::ModeFlags mode)
: File(&cookie_write, &cookie_read, &CookieFile::cookie_seek,
- &cookie_close, &cleanup_file<CookieFile>, buffer, bufsize,
- 0 /* default buffering mode */, true /* File owns buffer */, mode),
+ &cookie_close, buffer, bufsize, 0 /* default buffering mode */,
+ true /* File owns buffer */, mode),
cookie(c), ops(cops) {}
};
@@ -69,7 +69,11 @@ int CookieFile::cookie_close(File *f) {
auto cookie_file = reinterpret_cast<CookieFile *>(f);
if (cookie_file->ops.close == nullptr)
return 0;
- return cookie_file->ops.close(cookie_file->cookie);
+ int retval = cookie_file->ops.close(cookie_file->cookie);
+ if (retval != 0)
+ return retval;
+ delete cookie_file;
+ return 0;
}
} // anonymous namespace
diff --git a/libc/test/src/__support/File/file_test.cpp b/libc/test/src/__support/File/file_test.cpp
index 1446f66a01598..1a67ebdd50154 100644
--- a/libc/test/src/__support/File/file_test.cpp
+++ b/libc/test/src/__support/File/file_test.cpp
@@ -32,13 +32,15 @@ class StringFile : public File {
static FileIOResult str_write(__llvm_libc::File *f, const void *data,
size_t len);
static ErrorOr<long> str_seek(__llvm_libc::File *f, long offset, int whence);
- static int str_close(__llvm_libc::File *f) { return 0; }
+ static int str_close(__llvm_libc::File *f) {
+ delete reinterpret_cast<StringFile *>(f);
+ return 0;
+ }
public:
explicit StringFile(char *buffer, size_t buflen, int bufmode, bool owned,
ModeFlags modeflags)
: __llvm_libc::File(&str_write, &str_read, &str_seek, &str_close,
- &__llvm_libc::cleanup_file<StringFile>,
reinterpret_cast<uint8_t *>(buffer), buflen, bufmode,
owned, modeflags),
pos(0), eof_marker(0), write_append(false) {
@@ -145,7 +147,7 @@ TEST(LlvmLibcFileTest, WriteOnly) {
EXPECT_TRUE(result.has_error());
}
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, WriteLineBuffered) {
@@ -204,8 +206,8 @@ TEST(LlvmLibcFileTest, WriteLineBuffered) {
EXPECT_MEM_EQ(src3, dst_line_final);
EXPECT_MEM_EQ(src3, dst_full_final);
- ASSERT_EQ(File::cleanup(f_line), 0);
- ASSERT_EQ(File::cleanup(f_full), 0);
+ ASSERT_EQ(f_line->close(), 0);
+ ASSERT_EQ(f_full->close(), 0);
}
TEST(LlvmLibcFileTest, WriteUnbuffered) {
@@ -220,7 +222,7 @@ TEST(LlvmLibcFileTest, WriteUnbuffered) {
sizeof(data)); // no buffering means this is written immediately.
EXPECT_STREQ(f->get_str(), data);
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, ReadOnly) {
@@ -273,7 +275,7 @@ TEST(LlvmLibcFileTest, ReadOnly) {
EXPECT_TRUE(result.has_error());
}
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, ReadSeekCurAndRead) {
@@ -295,7 +297,7 @@ TEST(LlvmLibcFileTest, ReadSeekCurAndRead) {
ASSERT_EQ(f->seek(-5, SEEK_CUR).value(), 0);
ASSERT_EQ(f->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
ASSERT_STREQ(data, "9098");
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, AppendOnly) {
@@ -325,7 +327,7 @@ TEST(LlvmLibcFileTest, AppendOnly) {
EXPECT_EQ(f->flush(), int(0));
EXPECT_EQ(f->get_pos(), sizeof(write_data) + sizeof(initial_content));
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, WriteUpdate) {
@@ -345,7 +347,7 @@ TEST(LlvmLibcFileTest, WriteUpdate) {
ASSERT_EQ(f->read(read_data, sizeof(data)).value, sizeof(data));
EXPECT_STREQ(read_data, data);
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, ReadUpdate) {
@@ -378,7 +380,7 @@ TEST(LlvmLibcFileTest, ReadUpdate) {
src2(write_data, sizeof(write_data));
EXPECT_MEM_EQ(src2, dst2);
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, AppendUpdate) {
@@ -420,7 +422,7 @@ TEST(LlvmLibcFileTest, AppendUpdate) {
MemoryView src4(initial_content, READ_SIZE), dst4(read_data, READ_SIZE);
EXPECT_MEM_EQ(src4, dst4);
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, SmallBuffer) {
@@ -437,7 +439,7 @@ TEST(LlvmLibcFileTest, SmallBuffer) {
EXPECT_EQ(f->get_pos(), sizeof(WRITE_DATA));
ASSERT_STREQ(f->get_str(), WRITE_DATA);
- ASSERT_EQ(File::cleanup(f), 0);
+ ASSERT_EQ(f->close(), 0);
}
TEST(LlvmLibcFileTest, ZeroLengthBuffer) {
@@ -459,9 +461,9 @@ TEST(LlvmLibcFileTest, ZeroLengthBuffer) {
ASSERT_STREQ(f_lbf->get_str(), WRITE_DATA);
ASSERT_STREQ(f_nbf->get_str(), WRITE_DATA);
- ASSERT_EQ(File::cleanup(f_fbf), 0);
- ASSERT_EQ(File::cleanup(f_lbf), 0);
- ASSERT_EQ(File::cleanup(f_nbf), 0);
+ ASSERT_EQ(f_fbf->close(), 0);
+ ASSERT_EQ(f_lbf->close(), 0);
+ ASSERT_EQ(f_nbf->close(), 0);
}
TEST(LlvmLibcFileTest, WriteNothing) {
@@ -486,7 +488,7 @@ TEST(LlvmLibcFileTest, WriteNothing) {
ASSERT_FALSE(f_lbf->error_unlocked());
ASSERT_FALSE(f_nbf->error_unlocked());
- ASSERT_EQ(File::cleanup(f_fbf), 0);
- ASSERT_EQ(File::cleanup(f_lbf), 0);
- ASSERT_EQ(File::cleanup(f_nbf), 0);
+ ASSERT_EQ(f_fbf->close(), 0);
+ ASSERT_EQ(f_lbf->close(), 0);
+ ASSERT_EQ(f_nbf->close(), 0);
}
diff --git a/libc/test/src/__support/File/platform_file_test.cpp b/libc/test/src/__support/File/platform_file_test.cpp
index 55ab4855a98cf..a4f26c5ccbd1b 100644
--- a/libc/test/src/__support/File/platform_file_test.cpp
+++ b/libc/test/src/__support/File/platform_file_test.cpp
@@ -25,7 +25,7 @@ TEST(LlvmLibcPlatformFileTest, CreateWriteCloseAndReadBack) {
File *file = openfile(FILENAME, "w");
ASSERT_FALSE(file == nullptr);
ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "r");
ASSERT_FALSE(file == nullptr);
@@ -38,7 +38,7 @@ TEST(LlvmLibcPlatformFileTest, CreateWriteCloseAndReadBack) {
ASSERT_EQ(file->read(data, TEXT_SIZE).value, size_t(0));
ASSERT_TRUE(file->iseof());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, CreateWriteSeekAndReadBack) {
@@ -58,7 +58,7 @@ TEST(LlvmLibcPlatformFileTest, CreateWriteSeekAndReadBack) {
ASSERT_EQ(file->read(data, TEXT_SIZE).value, size_t(0));
ASSERT_TRUE(file->iseof());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, CreateAppendCloseAndReadBack) {
@@ -66,14 +66,14 @@ TEST(LlvmLibcPlatformFileTest, CreateAppendCloseAndReadBack) {
File *file = openfile(FILENAME, "w");
ASSERT_FALSE(file == nullptr);
ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "a");
ASSERT_FALSE(file == nullptr);
constexpr char APPEND_TEXT[] = " Append Text";
constexpr size_t APPEND_TEXT_SIZE = sizeof(APPEND_TEXT) - 1;
ASSERT_EQ(file->write(APPEND_TEXT, APPEND_TEXT_SIZE).value, APPEND_TEXT_SIZE);
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "r");
ASSERT_FALSE(file == nullptr);
@@ -87,7 +87,7 @@ TEST(LlvmLibcPlatformFileTest, CreateAppendCloseAndReadBack) {
ASSERT_EQ(file->read(data, READ_SIZE).value, size_t(0));
ASSERT_TRUE(file->iseof());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, CreateAppendSeekAndReadBack) {
@@ -95,7 +95,7 @@ TEST(LlvmLibcPlatformFileTest, CreateAppendSeekAndReadBack) {
File *file = openfile(FILENAME, "w");
ASSERT_FALSE(file == nullptr);
ASSERT_EQ(file->write(TEXT, TEXT_SIZE).value, TEXT_SIZE);
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "a+");
ASSERT_FALSE(file == nullptr);
@@ -113,7 +113,7 @@ TEST(LlvmLibcPlatformFileTest, CreateAppendSeekAndReadBack) {
ASSERT_EQ(file->read(data, APPEND_TEXT_SIZE).value, size_t(0));
ASSERT_TRUE(file->iseof());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, LargeFile) {
@@ -131,7 +131,7 @@ TEST(LlvmLibcPlatformFileTest, LargeFile) {
for (int i = 0; i < REPEAT; ++i) {
ASSERT_EQ(file->write(write_data, DATA_SIZE).value, DATA_SIZE);
}
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "r");
ASSERT_FALSE(file == nullptr);
@@ -146,7 +146,7 @@ TEST(LlvmLibcPlatformFileTest, LargeFile) {
ASSERT_EQ(file->read(data, 1).value, size_t(0));
ASSERT_TRUE(file->iseof());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) {
@@ -156,7 +156,7 @@ TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) {
constexpr char CONTENT[] = "1234567890987654321";
ASSERT_EQ(sizeof(CONTENT) - 1,
file->write(CONTENT, sizeof(CONTENT) - 1).value);
- ASSERT_EQ(0, File::cleanup(file));
+ ASSERT_EQ(0, file->close());
file = openfile(FILENAME, "r");
ASSERT_FALSE(file == nullptr);
@@ -173,7 +173,7 @@ TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) {
ASSERT_EQ(file->read(data, READ_SIZE - 1).value, READ_SIZE - 1);
ASSERT_STREQ(data, "9098");
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, IncorrectOperation) {
@@ -185,21 +185,21 @@ TEST(LlvmLibcPlatformFileTest, IncorrectOperation) {
ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
ASSERT_FALSE(file->iseof());
ASSERT_TRUE(file->error());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "r");
ASSERT_FALSE(file == nullptr);
ASSERT_EQ(file->write(data, 1).value, size_t(0)); // Cannot write
ASSERT_FALSE(file->iseof());
ASSERT_TRUE(file->error());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
file = openfile(FILENAME, "a");
ASSERT_FALSE(file == nullptr);
ASSERT_EQ(file->read(data, 1).value, size_t(0)); // Cannot read
ASSERT_FALSE(file->iseof());
ASSERT_TRUE(file->error());
- ASSERT_EQ(File::cleanup(file), 0);
+ ASSERT_EQ(file->close(), 0);
}
TEST(LlvmLibcPlatformFileTest, StdOutStdErrSmokeTest) {
More information about the libc-commits
mailing list