summaryrefslogtreecommitdiffstats
path: root/dom/file/ipc/RemoteLazyInputStreamStorage.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/file/ipc/RemoteLazyInputStreamStorage.cpp243
1 files changed, 243 insertions, 0 deletions
diff --git a/dom/file/ipc/RemoteLazyInputStreamStorage.cpp b/dom/file/ipc/RemoteLazyInputStreamStorage.cpp
new file mode 100644
index 0000000000..8ce2c22657
--- /dev/null
+++ b/dom/file/ipc/RemoteLazyInputStreamStorage.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/SlicedInputStream.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIPropertyBag2.h"
+#include "nsStreamUtils.h"
+#include "RemoteLazyInputStreamParent.h"
+#include "RemoteLazyInputStreamStorage.h"
+
+namespace mozilla {
+
+using namespace hal;
+
+extern mozilla::LazyLogModule gRemoteLazyStreamLog;
+
+namespace {
+StaticMutex gMutex;
+StaticRefPtr<RemoteLazyInputStreamStorage> gStorage;
+} // namespace
+
+NS_INTERFACE_MAP_BEGIN(RemoteLazyInputStreamStorage)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(RemoteLazyInputStreamStorage)
+NS_IMPL_RELEASE(RemoteLazyInputStreamStorage)
+
+/* static */
+Result<RefPtr<RemoteLazyInputStreamStorage>, nsresult>
+RemoteLazyInputStreamStorage::Get() {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ if (gStorage) {
+ RefPtr<RemoteLazyInputStreamStorage> storage = gStorage;
+ return storage;
+ }
+
+ return Err(NS_ERROR_NOT_INITIALIZED);
+}
+
+/* static */
+void RemoteLazyInputStreamStorage::Initialize() {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ MOZ_ASSERT(!gStorage);
+
+ gStorage = new RemoteLazyInputStreamStorage();
+
+ MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
+ "RemoteLazyInputStreamStorage", getter_AddRefs(gStorage->mTaskQueue)));
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->AddObserver(gStorage, "xpcom-shutdown", false);
+ }
+}
+
+NS_IMETHODIMP
+RemoteLazyInputStreamStorage::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) {
+ MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->RemoveObserver(this, "xpcom-shutdown");
+ }
+
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ gStorage = nullptr;
+ return NS_OK;
+}
+
+void RemoteLazyInputStreamStorage::AddStream(nsIInputStream* aInputStream,
+ const nsID& aID) {
+ MOZ_ASSERT(aInputStream);
+
+ MOZ_LOG(
+ gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::AddStream(%s) = %p", nsIDToCString(aID).get(), aInputStream));
+
+ UniquePtr<StreamData> data = MakeUnique<StreamData>();
+ data->mInputStream = aInputStream;
+
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ mStorage.InsertOrUpdate(aID, std::move(data));
+}
+
+nsCOMPtr<nsIInputStream> RemoteLazyInputStreamStorage::ForgetStream(
+ const nsID& aID) {
+ MOZ_LOG(gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::ForgetStream(%s)", nsIDToCString(aID).get()));
+
+ UniquePtr<StreamData> entry;
+
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ mStorage.Remove(aID, &entry);
+
+ if (!entry) {
+ return nullptr;
+ }
+
+ return std::move(entry->mInputStream);
+}
+
+bool RemoteLazyInputStreamStorage::HasStream(const nsID& aID) {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ return !!data;
+}
+
+void RemoteLazyInputStreamStorage::GetStream(const nsID& aID, uint64_t aStart,
+ uint64_t aLength,
+ nsIInputStream** aInputStream) {
+ *aInputStream = nullptr;
+
+ MOZ_LOG(gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::GetStream(%s, %" PRIu64 " %" PRIu64 ")",
+ nsIDToCString(aID).get(), aStart, aLength));
+
+ nsCOMPtr<nsIInputStream> inputStream;
+
+ // NS_CloneInputStream cannot be called when the mutex is locked because it
+ // can, recursively call GetStream() in case the child actor lives on the
+ // parent process.
+ {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ if (!data) {
+ return;
+ }
+
+ inputStream = data->mInputStream;
+ }
+
+ MOZ_ASSERT(inputStream);
+
+ // We cannot return always the same inputStream because not all of them are
+ // able to be reused. Better to clone them.
+
+ nsCOMPtr<nsIInputStream> clonedStream;
+ nsCOMPtr<nsIInputStream> replacementStream;
+
+ nsresult rv = NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
+ getter_AddRefs(replacementStream));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
+
+ if (replacementStream) {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ // data can be gone in the meantime.
+ if (!data) {
+ return;
+ }
+
+ data->mInputStream = replacementStream;
+ }
+
+ // Now it's the right time to apply a slice if needed.
+ if (aStart > 0 || aLength < UINT64_MAX) {
+ clonedStream =
+ new SlicedInputStream(clonedStream.forget(), aStart, aLength);
+ }
+
+ clonedStream.forget(aInputStream);
+}
+
+void RemoteLazyInputStreamStorage::StoreCallback(
+ const nsID& aID, RemoteLazyInputStreamParentCallback* aCallback) {
+ MOZ_ASSERT(aCallback);
+
+ MOZ_LOG(
+ gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::StoreCallback(%s, %p)", nsIDToCString(aID).get(), aCallback));
+
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ if (data) {
+ MOZ_ASSERT(!data->mCallback);
+ data->mCallback = aCallback;
+ }
+}
+
+already_AddRefed<RemoteLazyInputStreamParentCallback>
+RemoteLazyInputStreamStorage::TakeCallback(const nsID& aID) {
+ MOZ_LOG(gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::TakeCallback(%s)", nsIDToCString(aID).get()));
+
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ if (!data) {
+ return nullptr;
+ }
+
+ RefPtr<RemoteLazyInputStreamParentCallback> callback;
+ data->mCallback.swap(callback);
+ return callback.forget();
+}
+
+void RemoteLazyInputStreamStorage::ActorCreated(const nsID& aID) {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ if (!data) {
+ return;
+ }
+
+ size_t count = ++data->mActorCount;
+
+ MOZ_LOG(gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::ActorCreated(%s) = %zu", nsIDToCString(aID).get(), count));
+}
+
+void RemoteLazyInputStreamStorage::ActorDestroyed(const nsID& aID) {
+ UniquePtr<StreamData> entry;
+ {
+ mozilla::StaticMutexAutoLock lock(gMutex);
+ StreamData* data = mStorage.Get(aID);
+ if (!data) {
+ return;
+ }
+
+ auto newCount = --data->mActorCount;
+ MOZ_LOG(gRemoteLazyStreamLog, LogLevel::Verbose,
+ ("Storage::ActorDestroyed(%s) = %zu (cb=%p)",
+ nsIDToCString(aID).get(), newCount, data->mCallback.get()));
+
+ if (newCount == 0) {
+ mStorage.Remove(aID, &entry);
+ }
+ }
+
+ if (entry && entry->mCallback) {
+ entry->mCallback->ActorDestroyed(aID);
+ }
+}
+
+} // namespace mozilla