mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
Kernel+LibC+Profiler: Replace readv syscall with preadv
We already use pwritev to implement writev, so let's do the same for readv. This resolves the awkward situation of having pwritev but not preadv, which affects Zig for instance.
This commit is contained in:
1 parent
ab742eefcb
commit
2a9154e77c
16 files changed
+88
-45
No files matched your search
@@ -145,8 +145,8 @@ enum class NeedsBigProcessLock {
|
||||
S(purge, NeedsBigProcessLock::Yes) \
|
||||
S(read, NeedsBigProcessLock::Yes) \
|
||||
S(pread, NeedsBigProcessLock::Yes) \
|
||||
S(preadv, NeedsBigProcessLock::Yes) \
|
||||
S(readlink, NeedsBigProcessLock::No) \
|
||||
S(readv, NeedsBigProcessLock::Yes) \
|
||||
S(realpath, NeedsBigProcessLock::No) \
|
||||
S(recvfd, NeedsBigProcessLock::No) \
|
||||
S(recvmsg, NeedsBigProcessLock::Yes) \
|
||||
|
||||
@@ -130,7 +130,7 @@ ErrorOr<FlatPtr> Process::sys$close(int fd)
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count)
|
||||
ErrorOr<FlatPtr> Process::sys$preadv(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t offset)
|
||||
{
|
||||
Optional<MonotonicTime> start_timestamp = {};
|
||||
|
||||
@@ -139,7 +139,7 @@ ErrorOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov,
|
||||
start_timestamp = TimeManagement::the().monotonic_time(TimePrecision::Precise);
|
||||
}
|
||||
|
||||
auto result = readv_impl(fd, iov, iov_count);
|
||||
auto result = preadv_impl(fd, iov, iov_count, offset);
|
||||
|
||||
if (!profiling_enabled_at_entry || Thread::current()->is_profiling_suppressed())
|
||||
return result;
|
||||
@@ -155,9 +155,10 @@ ErrorOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov,
|
||||
auto const duration = end_timestamp - start_timestamp.value();
|
||||
|
||||
FilesystemEvent data;
|
||||
data.type = FilesystemEventType::Readv;
|
||||
data.type = FilesystemEventType::Preadv;
|
||||
data.durationNs = static_cast<u64>(duration.to_nanoseconds());
|
||||
data.data.readv.fd = fd;
|
||||
data.data.preadv.fd = fd;
|
||||
data.data.preadv.offset = offset;
|
||||
|
||||
if (result.is_error()) {
|
||||
data.result.is_error = true;
|
||||
@@ -171,7 +172,7 @@ ErrorOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov,
|
||||
if (maybe_path_index.is_error())
|
||||
return result;
|
||||
|
||||
data.data.readv.filename_index = maybe_path_index.value();
|
||||
data.data.preadv.filename_index = maybe_path_index.value();
|
||||
|
||||
(void)event_buffer->append(PERF_EVENT_FILESYSTEM, 0, 0, {}, Thread::current(), data);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static ErrorOr<void> check_blocked_read(OpenFileDescription* description)
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::readv_impl(int fd, Userspace<const struct iovec*> iov, int iov_count)
|
||||
ErrorOr<FlatPtr> Process::preadv_impl(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t base_offset)
|
||||
{
|
||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
||||
TRY(require_promise(Pledge::stdio));
|
||||
@@ -59,13 +59,20 @@ ErrorOr<FlatPtr> Process::readv_impl(int fd, Userspace<const struct iovec*> iov,
|
||||
}
|
||||
|
||||
auto description = TRY(open_readable_file_description(fds(), fd));
|
||||
// NOTE: Negative offset means "operate like readv" which seeks the file.
|
||||
if (base_offset >= 0 && !description->file().is_seekable())
|
||||
return EINVAL;
|
||||
|
||||
int nread = 0;
|
||||
off_t current_offset = base_offset;
|
||||
for (auto& vec : vecs) {
|
||||
TRY(check_blocked_read(description));
|
||||
auto buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len));
|
||||
auto nread_here = TRY(description->read(buffer, vec.iov_len));
|
||||
auto nread_here = base_offset >= 0
|
||||
? TRY(description->read(buffer, current_offset, vec.iov_len))
|
||||
: TRY(description->read(buffer, vec.iov_len));
|
||||
nread += nread_here;
|
||||
current_offset += nread_here;
|
||||
}
|
||||
|
||||
return nread;
|
||||
|
||||
@@ -319,11 +319,12 @@ ErrorOr<void> PerformanceEventBuffer::to_json_impl(Serializer& object) const
|
||||
TRY(event_object.add("filename_index"sv, close.filename_index));
|
||||
break;
|
||||
}
|
||||
case FilesystemEventType::Readv: {
|
||||
auto const& readv = event.data.filesystem.data.readv;
|
||||
TRY(event_object.add("fs_event_type"sv, "readv"sv));
|
||||
TRY(event_object.add("fd"sv, readv.fd));
|
||||
TRY(event_object.add("filename_index"sv, readv.filename_index));
|
||||
case FilesystemEventType::Preadv: {
|
||||
auto const& preadv = event.data.filesystem.data.preadv;
|
||||
TRY(event_object.add("fs_event_type"sv, "preadv"sv));
|
||||
TRY(event_object.add("fd"sv, preadv.fd));
|
||||
TRY(event_object.add("filename_index"sv, preadv.filename_index));
|
||||
TRY(event_object.add("offset"sv, preadv.offset));
|
||||
break;
|
||||
}
|
||||
case FilesystemEventType::Read: {
|
||||
|
||||
@@ -80,7 +80,7 @@ struct [[gnu::packed]] ReadPerformanceEvent {
|
||||
enum class FilesystemEventType : u8 {
|
||||
Open,
|
||||
Close,
|
||||
Readv,
|
||||
Preadv,
|
||||
Read,
|
||||
Pread
|
||||
};
|
||||
@@ -97,11 +97,12 @@ struct [[gnu::packed]] CloseEventData {
|
||||
size_t filename_index;
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] ReadvEventData {
|
||||
struct [[gnu::packed]] PreadvEventData {
|
||||
int fd;
|
||||
size_t filename_index;
|
||||
// struct iovec* iov; // TODO: Implement
|
||||
// int iov_count; // TODO: Implement
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] ReadEventData {
|
||||
@@ -131,7 +132,7 @@ struct [[gnu::packed]] FilesystemEvent {
|
||||
union {
|
||||
OpenEventData open;
|
||||
CloseEventData close;
|
||||
ReadvEventData readv;
|
||||
PreadvEventData preadv;
|
||||
ReadEventData read;
|
||||
PreadEventData pread;
|
||||
} data;
|
||||
|
||||
@@ -376,7 +376,7 @@ public:
|
||||
ErrorOr<FlatPtr> sys$close(int fd);
|
||||
ErrorOr<FlatPtr> sys$read(int fd, Userspace<u8*>, size_t);
|
||||
ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, off_t);
|
||||
ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count);
|
||||
ErrorOr<FlatPtr> sys$preadv(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t);
|
||||
ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t);
|
||||
ErrorOr<FlatPtr> sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t);
|
||||
ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>);
|
||||
@@ -747,7 +747,7 @@ private:
|
||||
ErrorOr<FlatPtr> close_impl(int fd);
|
||||
ErrorOr<FlatPtr> read_impl(int fd, Userspace<u8*> buffer, size_t size);
|
||||
ErrorOr<FlatPtr> pread_impl(int fd, Userspace<u8*>, size_t, off_t);
|
||||
ErrorOr<FlatPtr> readv_impl(int fd, Userspace<const struct iovec*> iov, int iov_count);
|
||||
ErrorOr<FlatPtr> preadv_impl(int fd, Userspace<const struct iovec*> iov, int iov_count, off_t);
|
||||
|
||||
public:
|
||||
ErrorOr<void> traverse_as_directory(FileSystemID, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const;
|
||||
|
||||
@@ -40,7 +40,7 @@ static bool is_bad_idea(int fn, size_t const* direct_sc_args, size_t const* fake
|
||||
// This would mess with future tests or crash the fuzzer.
|
||||
return direct_sc_args[0] == (size_t)fake_sc_params || direct_sc_args[0] == (size_t)some_string;
|
||||
case SC_read:
|
||||
case SC_readv:
|
||||
case SC_preadv:
|
||||
// FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328
|
||||
return direct_sc_args[0] == 1;
|
||||
case SC_write:
|
||||
|
||||
@@ -419,6 +419,31 @@ TEST_CASE(rmdir_while_inside_dir)
|
||||
VERIFY(rc == 0);
|
||||
}
|
||||
|
||||
TEST_CASE(readv)
|
||||
{
|
||||
int pipefds[2];
|
||||
int rc = pipe(pipefds);
|
||||
EXPECT(rc == 0);
|
||||
|
||||
int nwritten = write(pipefds[1], "HelloFriends", 12);
|
||||
EXPECT_EQ(nwritten, 12);
|
||||
|
||||
char buffer0[6] {};
|
||||
char buffer1[8] {};
|
||||
iovec iov[2];
|
||||
iov[0].iov_base = buffer0;
|
||||
iov[0].iov_len = sizeof(buffer0) - 1;
|
||||
iov[1].iov_base = buffer1;
|
||||
iov[1].iov_len = sizeof(buffer1) - 1;
|
||||
int nread = readv(pipefds[0], iov, 2);
|
||||
EXPECT_EQ(nread, 12);
|
||||
EXPECT_EQ(buffer0, "Hello"sv);
|
||||
EXPECT_EQ(buffer1, "Friends"sv);
|
||||
|
||||
close(pipefds[0]);
|
||||
close(pipefds[1]);
|
||||
}
|
||||
|
||||
TEST_CASE(writev)
|
||||
{
|
||||
int pipefds[2];
|
||||
|
||||
@@ -168,10 +168,10 @@ ErrorOr<String> FileEventModel::column_name(int column) const
|
||||
return "Close Count"_string;
|
||||
case Column::CloseDuration:
|
||||
return "Close Duration [ms]"_string;
|
||||
case Column::ReadvCount:
|
||||
return "Readv Count"_string;
|
||||
case Column::ReadvDuration:
|
||||
return "Readv Duration [ms]"_string;
|
||||
case Column::PreadvCount:
|
||||
return "Preadv Count"_string;
|
||||
case Column::PreadvDuration:
|
||||
return "Preadv Duration [ms]"_string;
|
||||
case Column::ReadCount:
|
||||
return "Read Count"_string;
|
||||
case Column::ReadDuration:
|
||||
@@ -211,10 +211,10 @@ GUI::Variant FileEventModel::data(GUI::ModelIndex const& index, GUI::ModelRole r
|
||||
return node->close().count;
|
||||
case Column::CloseDuration:
|
||||
return static_cast<f32>(node->close().duration.to_nanoseconds()) / 1'000'000;
|
||||
case Column::ReadvCount:
|
||||
return node->readv().count;
|
||||
case Column::ReadvDuration:
|
||||
return static_cast<f32>(node->readv().duration.to_nanoseconds()) / 1'000'000;
|
||||
case Column::PreadvCount:
|
||||
return node->preadv().count;
|
||||
case Column::PreadvDuration:
|
||||
return static_cast<f32>(node->preadv().duration.to_nanoseconds()) / 1'000'000;
|
||||
case Column::ReadCount:
|
||||
return node->read().count;
|
||||
case Column::ReadDuration:
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
|
||||
FileEventType& open() { return m_open; }
|
||||
FileEventType& close() { return m_close; }
|
||||
FileEventType& readv() { return m_readv; }
|
||||
FileEventType& preadv() { return m_readv; }
|
||||
FileEventType& read() { return m_read; }
|
||||
FileEventType& pread() { return m_pread; }
|
||||
|
||||
@@ -84,8 +84,8 @@ public:
|
||||
OpenDuration,
|
||||
CloseCount,
|
||||
CloseDuration,
|
||||
ReadvCount,
|
||||
ReadvDuration,
|
||||
PreadvCount,
|
||||
PreadvDuration,
|
||||
ReadCount,
|
||||
ReadDuration,
|
||||
PreadCount,
|
||||
|
||||
@@ -216,7 +216,7 @@ void Profile::rebuild_tree()
|
||||
[&](Event::CloseEventData const& data) {
|
||||
return data.path;
|
||||
},
|
||||
[&](Event::ReadvEventData const& data) {
|
||||
[&](Event::PreadvEventData const& data) {
|
||||
return data.path;
|
||||
},
|
||||
[&](Event::ReadEventData const& data) {
|
||||
@@ -240,9 +240,9 @@ void Profile::rebuild_tree()
|
||||
node.close().duration += duration;
|
||||
node.close().count++;
|
||||
},
|
||||
[&](Event::ReadvEventData const&) {
|
||||
node.readv().duration += duration;
|
||||
node.readv().count++;
|
||||
[&](Event::PreadvEventData const&) {
|
||||
node.preadv().duration += duration;
|
||||
node.preadv().count++;
|
||||
},
|
||||
[&](Event::ReadEventData const&) {
|
||||
node.read().duration += duration;
|
||||
@@ -440,12 +440,13 @@ ErrorOr<NonnullOwnPtr<Profile>> Profile::load_from_perfcore_file(StringView path
|
||||
.fd = perf_event.get_integer<int>("fd"sv).value_or(0),
|
||||
.path = filename,
|
||||
};
|
||||
} else if (filesystem_event_type == "readv"sv) {
|
||||
} else if (filesystem_event_type == "preadv"sv) {
|
||||
auto const string_index = perf_event.get_addr("filename_index"sv).value_or(0);
|
||||
auto const filename = profile_strings.get(string_index).value();
|
||||
fsdata.data = Event::ReadvEventData {
|
||||
fsdata.data = Event::PreadvEventData {
|
||||
.fd = perf_event.get_integer<int>("fd"sv).value_or(0),
|
||||
.path = filename,
|
||||
.offset = perf_event.get_integer<off_t>("offset"sv).value_or(0),
|
||||
};
|
||||
} else if (filesystem_event_type == "read"sv) {
|
||||
auto const string_index = perf_event.get_addr("filename_index"sv).value_or(0);
|
||||
|
||||
@@ -237,11 +237,12 @@ public:
|
||||
ByteString path;
|
||||
};
|
||||
|
||||
struct ReadvEventData {
|
||||
struct PreadvEventData {
|
||||
int fd;
|
||||
ByteString path;
|
||||
// struct iovec* iov; // TODO: Implement
|
||||
// int iov_count; // TODO: Implement
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
struct ReadEventData {
|
||||
@@ -259,7 +260,7 @@ public:
|
||||
|
||||
struct FilesystemEventData {
|
||||
Duration duration;
|
||||
Variant<OpenEventData, CloseEventData, ReadvEventData, ReadEventData, PreadEventData> data;
|
||||
Variant<OpenEventData, CloseEventData, PreadvEventData, ReadEventData, PreadEventData> data;
|
||||
};
|
||||
|
||||
Variant<nullptr_t, SampleData, MallocData, FreeData, SignpostData, MmapData, MunmapData, ProcessCreateData, ProcessExecData, ThreadCreateData, FilesystemEventData> data { nullptr };
|
||||
|
||||
@@ -99,7 +99,7 @@ GUI::Variant SamplesModel::data(GUI::ModelIndex const& index, GUI::ModelRole rol
|
||||
[&](Profile::Event::CloseEventData const& data) {
|
||||
return data.path;
|
||||
},
|
||||
[&](Profile::Event::ReadvEventData const& data) {
|
||||
[&](Profile::Event::PreadvEventData const& data) {
|
||||
return data.path;
|
||||
},
|
||||
[&](Profile::Event::ReadEventData const& data) {
|
||||
|
||||
@@ -268,7 +268,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
filesystem_events_tree_view.set_model(profile->file_event_model());
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::OpenDuration, false);
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::CloseDuration, false);
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::ReadvDuration, false);
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::PreadvDuration, false);
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::ReadDuration, false);
|
||||
filesystem_events_tree_view.set_column_visible(FileEventModel::Column::PreadDuration, false);
|
||||
|
||||
|
||||
@@ -11,19 +11,24 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
ssize_t writev(int fd, const struct iovec* iov, int iov_count)
|
||||
ssize_t readv(int fd, const struct iovec* iov, int iov_count)
|
||||
{
|
||||
return pwritev(fd, iov, iov_count, -1);
|
||||
return preadv(fd, iov, iov_count, -1);
|
||||
}
|
||||
|
||||
ssize_t readv(int fd, const struct iovec* iov, int iov_count)
|
||||
ssize_t preadv(int fd, const struct iovec* iov, int iov_count, off_t offset)
|
||||
{
|
||||
__pthread_maybe_cancel();
|
||||
|
||||
int rc = syscall(SC_readv, fd, iov, iov_count);
|
||||
int rc = syscall(SC_preadv, fd, iov, iov_count, offset);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
ssize_t writev(int fd, const struct iovec* iov, int iov_count)
|
||||
{
|
||||
return pwritev(fd, iov, iov_count, -1);
|
||||
}
|
||||
|
||||
ssize_t pwritev(int fd, struct iovec const* iov, int iov_count, off_t offset)
|
||||
{
|
||||
__pthread_maybe_cancel();
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
ssize_t writev(int fd, const struct iovec*, int iov_count);
|
||||
ssize_t readv(int fd, const struct iovec*, int iov_count);
|
||||
ssize_t preadv(int fd, const struct iovec*, int iov_count, off_t);
|
||||
ssize_t writev(int fd, const struct iovec*, int iov_count);
|
||||
ssize_t pwritev(int fd, const struct iovec*, int iov_count, off_t);
|
||||
|
||||
__END_DECLS
|
||||
Reference in new issue
Block a user