mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
chore: cherry-pick cf64617c1cc5 from chromium (#34053)
This commit is contained in:
@@ -133,3 +133,4 @@ cherry-pick-5ff02e4d7368.patch
|
||||
cherry-pick-5361d836aeb1.patch
|
||||
cherry-pick-5be8e065f43e.patch
|
||||
cherry-pick-12ba78f3fa7a.patch
|
||||
fsa_pass_file_ownership_to_worker_for_async_fsarfd_file_operations.patch
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Austin Sullivan <asully@chromium.org>
|
||||
Date: Fri, 11 Mar 2022 10:08:55 +0000
|
||||
Subject: FSA: Pass File ownership to worker for async FSARFD file operations
|
||||
|
||||
We cannot access the backing file as a member of the
|
||||
FileSystemAccessRegularFileDelegate since WrapCrossThreadPersistent
|
||||
does NOT cancel the task posted to the worker pool if delegate is
|
||||
destroyed. Passing ownership to the worker task ensures the file must
|
||||
be alive when used. After the operation, ownership of the file is
|
||||
passed back to the delegate.
|
||||
|
||||
This pattern was already used for the SetLength operation on old Macs.
|
||||
|
||||
Bug: 1299743
|
||||
Change-Id: Ie00c09e8f77dc353f280af726a68ed6c572b750b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3498864
|
||||
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
|
||||
Commit-Queue: Austin Sullivan <asully@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#980167}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
|
||||
index bf5d3bdaace198e4da56cab27aef9d1cfa178136..a1f346c5afd6c2f3f41069a6dda4744179b1af05 100644
|
||||
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
|
||||
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.cc
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/functional.h"
|
||||
+#include "third_party/blink/renderer/platform/wtf/wtf.h"
|
||||
|
||||
#if defined(OS_MAC)
|
||||
#include "base/mac/mac_util.h"
|
||||
@@ -64,6 +65,8 @@ FileSystemAccessRegularFileDelegate::FileSystemAccessRegularFileDelegate(
|
||||
base::FileErrorOr<int> FileSystemAccessRegularFileDelegate::Read(
|
||||
int64_t offset,
|
||||
base::span<uint8_t> data) {
|
||||
+ DCHECK_GE(offset, 0);
|
||||
+
|
||||
int size = base::checked_cast<int>(data.size());
|
||||
int result =
|
||||
backing_file_.Read(offset, reinterpret_cast<char*>(data.data()), size);
|
||||
@@ -74,13 +77,14 @@ base::FileErrorOr<int> FileSystemAccessRegularFileDelegate::Read(
|
||||
}
|
||||
|
||||
base::FileErrorOr<int> FileSystemAccessRegularFileDelegate::Write(
|
||||
- int64_t write_offset,
|
||||
+ int64_t offset,
|
||||
const base::span<uint8_t> data) {
|
||||
+ DCHECK_GE(offset, 0);
|
||||
+
|
||||
int write_size = base::checked_cast<int>(data.size());
|
||||
|
||||
int64_t write_end_offset;
|
||||
- if (!base::CheckAdd(write_offset, write_size)
|
||||
- .AssignIfValid(&write_end_offset)) {
|
||||
+ if (!base::CheckAdd(offset, write_size).AssignIfValid(&write_end_offset)) {
|
||||
return base::File::FILE_ERROR_NO_SPACE;
|
||||
}
|
||||
|
||||
@@ -88,8 +92,8 @@ base::FileErrorOr<int> FileSystemAccessRegularFileDelegate::Write(
|
||||
return base::File::FILE_ERROR_NO_SPACE;
|
||||
}
|
||||
|
||||
- int result = backing_file_.Write(
|
||||
- write_offset, reinterpret_cast<char*>(data.data()), write_size);
|
||||
+ int result = backing_file_.Write(offset, reinterpret_cast<char*>(data.data()),
|
||||
+ write_size);
|
||||
if (write_size == result) {
|
||||
capacity_tracker_->CommitFileSizeChange(write_end_offset);
|
||||
return result;
|
||||
@@ -112,16 +116,19 @@ void FileSystemAccessRegularFileDelegate::GetLength(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DoGetLength,
|
||||
WrapCrossThreadPersistent(this),
|
||||
- std::move(wrapped_callback), task_runner_));
|
||||
+ std::move(wrapped_callback), std::move(backing_file_),
|
||||
+ task_runner_));
|
||||
}
|
||||
|
||||
// static
|
||||
void FileSystemAccessRegularFileDelegate::DoGetLength(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- WTF::CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)>
|
||||
- wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
||||
- int64_t length = delegate->backing_file_.GetLength();
|
||||
+ DCHECK(!IsMainThread());
|
||||
+
|
||||
+ int64_t length = file.GetLength();
|
||||
|
||||
// If the length is negative, the file operation failed. Get the last error
|
||||
// now before another file operation might run.
|
||||
@@ -130,7 +137,19 @@ void FileSystemAccessRegularFileDelegate::DoGetLength(
|
||||
|
||||
PostCrossThreadTask(
|
||||
*task_runner, FROM_HERE,
|
||||
- CrossThreadBindOnce(std::move(wrapped_callback), std::move(result)));
|
||||
+ CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DidGetLength,
|
||||
+ std::move(delegate), std::move(callback),
|
||||
+ std::move(file), std::move(result)));
|
||||
+}
|
||||
+
|
||||
+void FileSystemAccessRegularFileDelegate::DidGetLength(
|
||||
+ CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)> callback,
|
||||
+ base::File file,
|
||||
+ base::FileErrorOr<int64_t> error_or_length) {
|
||||
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
+ backing_file_ = std::move(file);
|
||||
+
|
||||
+ std::move(callback).Run(std::move(error_or_length));
|
||||
}
|
||||
|
||||
void FileSystemAccessRegularFileDelegate::SetLength(
|
||||
@@ -161,6 +180,9 @@ void FileSystemAccessRegularFileDelegate::DidCheckSetLengthCapacity(
|
||||
return;
|
||||
}
|
||||
|
||||
+ auto wrapped_callback =
|
||||
+ CrossThreadOnceFunction<void(bool)>(std::move(callback));
|
||||
+
|
||||
#if defined(OS_MAC)
|
||||
// On macOS < 10.15, a sandboxing limitation causes failures in ftruncate()
|
||||
// syscalls issued from renderers. For this reason, base::File::SetLength()
|
||||
@@ -173,81 +195,57 @@ void FileSystemAccessRegularFileDelegate::DidCheckSetLengthCapacity(
|
||||
}
|
||||
file_utilities_host_->SetLength(
|
||||
std::move(backing_file_), new_length,
|
||||
- WTF::Bind(&FileSystemAccessRegularFileDelegate::DidSetLengthIPC,
|
||||
- WrapPersistent(this), std::move(callback), new_length));
|
||||
+ WTF::Bind(&FileSystemAccessRegularFileDelegate::DidSetLength,
|
||||
+ WrapPersistent(this), std::move(wrapped_callback),
|
||||
+ new_length));
|
||||
return;
|
||||
}
|
||||
#endif // defined(OS_MAC)
|
||||
|
||||
- auto wrapped_callback =
|
||||
- CrossThreadOnceFunction<void(bool)>(std::move(callback));
|
||||
-
|
||||
// Truncate file on a worker thread and reply back to this sequence.
|
||||
worker_pool::PostTask(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DoSetLength,
|
||||
WrapCrossThreadPersistent(this),
|
||||
- std::move(wrapped_callback), task_runner_,
|
||||
- new_length));
|
||||
+ std::move(wrapped_callback), std::move(backing_file_),
|
||||
+ task_runner_, new_length));
|
||||
}
|
||||
|
||||
// static
|
||||
void FileSystemAccessRegularFileDelegate::DoSetLength(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceFunction<void(bool)> wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
int64_t length) {
|
||||
- bool result = delegate->backing_file_.SetLength(length);
|
||||
-
|
||||
- if (!result) {
|
||||
- // If the operation failed, the previously requested capacity is not
|
||||
- // returned and no change in file size is recorded. This assumes that
|
||||
- // setLength operations either succeed or do not change the file's length,
|
||||
- // which is consistent with the way other file operations are implemented in
|
||||
- // File System Access.
|
||||
- PostCrossThreadTask(
|
||||
- *task_runner, FROM_HERE,
|
||||
- CrossThreadBindOnce(std::move(wrapped_callback), std::move(result)));
|
||||
- return;
|
||||
- }
|
||||
+ DCHECK(!IsMainThread());
|
||||
+
|
||||
+ bool success = file.SetLength(length);
|
||||
+
|
||||
PostCrossThreadTask(
|
||||
*task_runner, FROM_HERE,
|
||||
- CrossThreadBindOnce(
|
||||
- &FileSystemAccessRegularFileDelegate::DidSuccessfulSetLength,
|
||||
- std::move(delegate), length, std::move(wrapped_callback)));
|
||||
-}
|
||||
-
|
||||
-void FileSystemAccessRegularFileDelegate::DidSuccessfulSetLength(
|
||||
- int64_t new_length,
|
||||
- CrossThreadOnceFunction<void(bool)> callback) {
|
||||
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
- capacity_tracker_->CommitFileSizeChange(new_length);
|
||||
- std::move(callback).Run(true);
|
||||
+ CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DidSetLength,
|
||||
+ std::move(delegate), std::move(callback), length,
|
||||
+ std::move(file), success));
|
||||
}
|
||||
|
||||
-#if defined(OS_MAC)
|
||||
-void FileSystemAccessRegularFileDelegate::DidSetLengthIPC(
|
||||
- base::OnceCallback<void(bool)> callback,
|
||||
+void FileSystemAccessRegularFileDelegate::DidSetLength(
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
int64_t new_length,
|
||||
base::File file,
|
||||
bool success) {
|
||||
DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
backing_file_ = std::move(file);
|
||||
|
||||
- if (!success) {
|
||||
- // If the operation failed, the previously requested capacity is not
|
||||
- // returned and no change in file size is recorded. This assumes that
|
||||
- // setLength operations either succeed or do not change the file's length,
|
||||
- // which is consistent with the way other file operations are implemented in
|
||||
- // File System Access.
|
||||
- std::move(callback).Run(success);
|
||||
- return;
|
||||
- }
|
||||
- auto wrapped_callback =
|
||||
- CrossThreadOnceFunction<void(bool)>(std::move(callback));
|
||||
- DidSuccessfulSetLength(new_length, std::move(wrapped_callback));
|
||||
+ // If the operation failed, no change in file size is recorded. This assumes
|
||||
+ // that setLength operations either succeed or do not change the file's
|
||||
+ // length, which is consistent with the way other file operations are
|
||||
+ // implemented in File System Access.
|
||||
+ if (success)
|
||||
+ capacity_tracker_->CommitFileSizeChange(new_length);
|
||||
+
|
||||
+ std::move(callback).Run(success);
|
||||
}
|
||||
-#endif // defined(OS_MAC)
|
||||
|
||||
void FileSystemAccessRegularFileDelegate::Flush(
|
||||
base::OnceCallback<void(bool)> callback) {
|
||||
@@ -259,17 +257,34 @@ void FileSystemAccessRegularFileDelegate::Flush(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DoFlush,
|
||||
WrapCrossThreadPersistent(this),
|
||||
- std::move(wrapped_callback), task_runner_));
|
||||
+ std::move(wrapped_callback), std::move(backing_file_),
|
||||
+ task_runner_));
|
||||
}
|
||||
|
||||
// static
|
||||
void FileSystemAccessRegularFileDelegate::DoFlush(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceFunction<void(bool)> wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
||||
- bool result = delegate->backing_file_.Flush();
|
||||
- PostCrossThreadTask(*task_runner, FROM_HERE,
|
||||
- CrossThreadBindOnce(std::move(wrapped_callback), result));
|
||||
+ DCHECK(!IsMainThread());
|
||||
+
|
||||
+ bool success = file.Flush();
|
||||
+ PostCrossThreadTask(
|
||||
+ *task_runner, FROM_HERE,
|
||||
+ CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DidFlush,
|
||||
+ std::move(delegate), std::move(callback),
|
||||
+ std::move(file), success));
|
||||
+}
|
||||
+
|
||||
+void FileSystemAccessRegularFileDelegate::DidFlush(
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
+ bool success) {
|
||||
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
+ backing_file_ = std::move(file);
|
||||
+
|
||||
+ std::move(callback).Run(success);
|
||||
}
|
||||
|
||||
void FileSystemAccessRegularFileDelegate::Close(base::OnceClosure callback) {
|
||||
@@ -280,16 +295,33 @@ void FileSystemAccessRegularFileDelegate::Close(base::OnceClosure callback) {
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DoClose,
|
||||
WrapCrossThreadPersistent(this),
|
||||
- std::move(wrapped_callback), task_runner_));
|
||||
+ std::move(wrapped_callback), std::move(backing_file_),
|
||||
+ task_runner_));
|
||||
}
|
||||
|
||||
// static
|
||||
void FileSystemAccessRegularFileDelegate::DoClose(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceClosure wrapped_callback,
|
||||
+ CrossThreadOnceClosure callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
||||
- delegate->backing_file_.Close();
|
||||
- PostCrossThreadTask(*task_runner, FROM_HERE, std::move(wrapped_callback));
|
||||
+ DCHECK(!IsMainThread());
|
||||
+
|
||||
+ file.Close();
|
||||
+ PostCrossThreadTask(
|
||||
+ *task_runner, FROM_HERE,
|
||||
+ CrossThreadBindOnce(&FileSystemAccessRegularFileDelegate::DidClose,
|
||||
+ std::move(delegate), std::move(callback),
|
||||
+ std::move(file)));
|
||||
+}
|
||||
+
|
||||
+void FileSystemAccessRegularFileDelegate::DidClose(
|
||||
+ CrossThreadOnceClosure callback,
|
||||
+ base::File file) {
|
||||
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
|
||||
+ backing_file_ = std::move(file);
|
||||
+
|
||||
+ std::move(callback).Run();
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
|
||||
index 6ecde8f42f4f8ee623d0b79b361dab3d2801021d..f1267ef98e083feaa472e6d1b14c8e1bb8df7b96 100644
|
||||
--- a/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
|
||||
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_access_regular_file_delegate.h
|
||||
@@ -28,6 +28,11 @@ namespace blink {
|
||||
|
||||
// Non-incognito implementation of the FileSystemAccessFileDelegate. This class
|
||||
// is a thin wrapper around an OS-level file descriptor.
|
||||
+//
|
||||
+// For async file operations, ownership of the file descriptor is passed to
|
||||
+// `task_runner_` to ensure it stays alive while being used. Ownership is passed
|
||||
+// back to the delegate once the operation completes. The delegate must not be
|
||||
+// used while there is an in-progress operation.
|
||||
class FileSystemAccessRegularFileDelegate final
|
||||
: public FileSystemAccessFileDelegate {
|
||||
public:
|
||||
@@ -71,24 +76,55 @@ class FileSystemAccessRegularFileDelegate final
|
||||
bool IsValid() const override { return backing_file_.IsValid(); }
|
||||
|
||||
private:
|
||||
+ // All async file operations perform I/O via a worker pool, off the main
|
||||
+ // thread. To keep `backing_file_` from being garbage-collected, ownership is
|
||||
+ // passed to the worker thread during the file operation. Concurrent file
|
||||
+ // operations is NOT supported.
|
||||
+
|
||||
+ // Performs the file I/O part of getSize(), off the main thread.
|
||||
static void DoGetLength(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)>
|
||||
- wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
|
||||
+ // Performs the post file I/O part of getSize(), on the main thread.
|
||||
+ void DidGetLength(
|
||||
+ CrossThreadOnceFunction<void(base::FileErrorOr<int64_t>)> callback,
|
||||
+ base::File file,
|
||||
+ base::FileErrorOr<int64_t> error_or_length);
|
||||
+
|
||||
+ // Performs the file I/O part of truncate(), off the main thread.
|
||||
static void DoSetLength(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceFunction<void(bool)> wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
int64_t length);
|
||||
+ // Performs the post file I/O part of truncate(), on the main thread.
|
||||
+ void DidSetLength(CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ int64_t new_length,
|
||||
+ base::File file,
|
||||
+ bool success);
|
||||
+
|
||||
+ // Performs the file I/O part of flush(), off the main thread.
|
||||
static void DoFlush(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceFunction<void(bool)> wrapped_callback,
|
||||
+ CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner);
|
||||
+ // Performs the post file I/O part of flush(), on the main thread.
|
||||
+ void DidFlush(CrossThreadOnceFunction<void(bool)> callback,
|
||||
+ base::File file,
|
||||
+ bool success);
|
||||
+
|
||||
+ // Performs the file I/O part of close(), off the main thread.
|
||||
static void DoClose(
|
||||
CrossThreadPersistent<FileSystemAccessRegularFileDelegate> delegate,
|
||||
- CrossThreadOnceClosure wrapped_callback,
|
||||
+ CrossThreadOnceClosure callback,
|
||||
+ base::File file,
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner);
|
||||
+ // Performs the post file I/O part of close(), on the main thread.
|
||||
+ void DidClose(CrossThreadOnceClosure callback, base::File file);
|
||||
|
||||
// Called after preconditions for SetLength, including the requesting
|
||||
// additional capacity (if needed), have been performed.
|
||||
@@ -98,16 +134,7 @@ class FileSystemAccessRegularFileDelegate final
|
||||
int64_t new_length,
|
||||
bool request_capacity_result);
|
||||
|
||||
- // Called after SetLength was successfully performed.
|
||||
- void DidSuccessfulSetLength(int64_t new_length,
|
||||
- CrossThreadOnceFunction<void(bool)> callback);
|
||||
-
|
||||
#if defined(OS_MAC)
|
||||
- void DidSetLengthIPC(base::OnceCallback<void(bool)> callback,
|
||||
- int64_t new_length,
|
||||
- base::File file,
|
||||
- bool result);
|
||||
-
|
||||
// We need the FileUtilitiesHost only on Mac, where we have to execute
|
||||
// base::File::SetLength on the browser process, see crbug.com/1084565.
|
||||
// We need the context_ to create the instance of FileUtilitiesHost lazily.
|
||||
Reference in New Issue
Block a user