Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  FileSystemSyncAccessHandle.cpp   Sprache: C

 
/* -*- 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 "FileSystemSyncAccessHandle.h"

#include "fs/FileSystemAsyncCopy.h"
#include "fs/FileSystemRequestHandler.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/FixedBufferOutputStream.h"
#include "mozilla/MozPromise.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/dom/FileSystemAccessHandleChild.h"
#include "mozilla/dom/FileSystemAccessHandleControlChild.h"
#include "mozilla/dom/FileSystemHandleBinding.h"
#include "mozilla/dom/FileSystemLog.h"
#include "mozilla/dom/FileSystemManager.h"
#include "mozilla/dom/FileSystemManagerChild.h"
#include "mozilla/dom/FileSystemSyncAccessHandleBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/fs/IPCRejectReporter.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/dom/quota/ResultExtensions.h"
#include "mozilla/dom/quota/TargetPtrHolder.h"
#include "mozilla/ipc/RandomAccessStreamUtils.h"
#include "nsNetCID.h"
#include "nsStringStream.h"

namespace mozilla::dom {

namespace {

using SizePromise = Int64Promise;
const auto CreateAndRejectSizePromise = CreateAndRejectInt64Promise;

}  // namespace

FileSystemSyncAccessHandle::FileSystemSyncAccessHandle(
    nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
    mozilla::ipc::RandomAccessStreamParams&& aStreamParams,
    RefPtr<FileSystemAccessHandleChild> aActor,
    RefPtr<FileSystemAccessHandleControlChild> aControlActor,
    RefPtr<TaskQueue> aIOTaskQueue,
    const fs::FileSystemEntryMetadata& aMetadata)
    : mGlobal(aGlobal),
      mManager(aManager),
      mActor(std::move(aActor)),
      mControlActor(std::move(aControlActor)),
      mIOTaskQueue(std::move(aIOTaskQueue)),
      mStreamParams(std::move(aStreamParams)),
      mMetadata(aMetadata),
      mState(State::Initial) {
  LOG(("Created SyncAccessHandle %p"this));

  // Connect with the actor directly in the constructor. This way the actor
  // can call `FileSystemSyncAccessHandle::ClearActor` when we call
  // `PFileSystemAccessHandleChild::Send__delete__` even when
  // FileSystemSyncAccessHandle::Create fails, in which case the not yet
  // fully constructed FileSystemSyncAccessHandle is being destroyed.
  mActor->SetAccessHandle(this);

  mControlActor->SetAccessHandle(this);
}

FileSystemSyncAccessHandle::~FileSystemSyncAccessHandle() {
  MOZ_ASSERT(!mActor);
  MOZ_ASSERT(IsClosed());
}

// static
Result<RefPtr<FileSystemSyncAccessHandle>, nsresult>
FileSystemSyncAccessHandle::Create(
    nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
    mozilla::ipc::RandomAccessStreamParams&& aStreamParams,
    mozilla::ipc::ManagedEndpoint<PFileSystemAccessHandleChild>&&
        aAccessHandleChildEndpoint,
    mozilla::ipc::Endpoint<PFileSystemAccessHandleControlChild>&&
        aAccessHandleControlChildEndpoint,
    const fs::FileSystemEntryMetadata& aMetadata) {
  WorkerPrivate* const workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  auto accessHandleChild = MakeRefPtr<FileSystemAccessHandleChild>();

  QM_TRY(MOZ_TO_RESULT(
      aManager->ActorStrongRef()->BindPFileSystemAccessHandleEndpoint(
          std::move(aAccessHandleChildEndpoint), accessHandleChild)));

  auto accessHandleControlChild =
      MakeRefPtr<FileSystemAccessHandleControlChild>();

  aAccessHandleControlChildEndpoint.Bind(accessHandleControlChild,
                                         workerPrivate->ControlEventTarget());

  QM_TRY_UNWRAP(auto streamTransportService,
                MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIEventTarget>,
                                        MOZ_SELECT_OVERLOAD(do_GetService),
                                        NS_STREAMTRANSPORTSERVICE_CONTRACTID));

  RefPtr<TaskQueue> ioTaskQueue = TaskQueue::Create(
      streamTransportService.forget(), "FileSystemSyncAccessHandle");
  QM_TRY(MOZ_TO_RESULT(ioTaskQueue));

  RefPtr<FileSystemSyncAccessHandle> result = new FileSystemSyncAccessHandle(
      aGlobal, aManager, std::move(aStreamParams), std::move(accessHandleChild),
      std::move(accessHandleControlChild), std::move(ioTaskQueue), aMetadata);

  auto autoClose = MakeScopeExit([result] {
    MOZ_ASSERT(result->mState == State::Initial);
    result->mState = State::Closed;
    result->mActor->SendClose();
  });

  workerPrivate->AssertIsOnWorkerThread();

  RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
      workerPrivate, "FileSystemSyncAccessHandle", [result]() {
        if (result->IsOpen()) {
          // We don't need to use the result, we just need to begin the closing
          // process.
          Unused << result->BeginClose();
        }
      });
  QM_TRY(MOZ_TO_RESULT(workerRef));

  autoClose.release();

  result->mWorkerRef = std::move(workerRef);
  result->mState = State::Open;

  return result;
}

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemSyncAccessHandle)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemSyncAccessHandle)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FileSystemSyncAccessHandle,
                                                   LastRelease())

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FileSystemSyncAccessHandle)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FileSystemSyncAccessHandle)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
  // Don't unlink mManager!
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  if (tmp->IsOpen()) {
    // We don't need to use the result, we just need to begin the closing
    // process.
    Unused << tmp->BeginClose();
  }
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FileSystemSyncAccessHandle)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

void FileSystemSyncAccessHandle::LastRelease() {
  // We can't call `FileSystemSyncAccessHandle::Close` here because it may need
  // to keep FileSystemSyncAccessHandle object alive which isn't possible when
  // the object is about to be deleted. There are other mechanisms which ensure
  // that the object is correctly closed before destruction. For example the
  // object unlinking and the worker shutdown (we get notified about it via the
  // callback passed to `StrongWorkerRef`) are used to close the object if it
  // hasn't been closed yet.

  if (mActor) {
    PFileSystemAccessHandleChild::Send__delete__(mActor);

    // `PFileSystemAccessHandleChild::Send__delete__` is supposed to call
    // `FileSystemAccessHandleChild::ActorDestroy` which in turn calls
    // `FileSystemSyncAccessHandle::ClearActor`, so `mActor` should be be null
    // at this point.
    MOZ_ASSERT(!mActor);
  }

  if (mControlActor) {
    mControlActor->Close();

    // `FileSystemAccessHandleControlChild::Close` is supposed to call
    // `FileSystemAccessHandleControlChild::ActorDestroy` which in turn calls
    // `FileSystemSyncAccessHandle::ClearControlActor`, so `mControlActor`
    // should be be null at this point.
    MOZ_ASSERT(!mControlActor);
  }
}

void FileSystemSyncAccessHandle::ClearActor() {
  MOZ_ASSERT(mActor);

  mActor = nullptr;
}

void FileSystemSyncAccessHandle::ClearControlActor() {
  // `mControlActor` is initialized in the constructor and this method is
  // supposed to be called only once.
  MOZ_ASSERT(mControlActor);

  mControlActor = nullptr;
}

bool FileSystemSyncAccessHandle::IsOpen() const {
  MOZ_ASSERT(mState != State::Initial);

  return mState == State::Open;
}

bool FileSystemSyncAccessHandle::IsClosing() const {
  MOZ_ASSERT(mState != State::Initial);

  return mState == State::Closing;
}

bool FileSystemSyncAccessHandle::IsClosed() const {
  MOZ_ASSERT(mState != State::Initial);

  return mState == State::Closed;
}

RefPtr<BoolPromise> FileSystemSyncAccessHandle::BeginClose() {
  MOZ_ASSERT(IsOpen());

  mState = State::Closing;

  InvokeAsync(mIOTaskQueue, __func__,
              [selfHolder = quota::TargetPtrHolder(this)]() {
                if (selfHolder->mStream) {
                  LOG(("%p: Closing", selfHolder->mStream.get()));

                  selfHolder->mStream->OutputStream()->Close();
                  selfHolder->mStream = nullptr;
                } else {
                  LOG(("Closing (no stream)"));

                  // If the stream was not deserialized, `mStreamParams` still
                  // contains a pre-opened file descriptor which needs to be
                  // closed here by moving `mStreamParams` to a local variable
                  // (the file descriptor will be closed for real when
                  // `streamParams` goes out of scope).

                  mozilla::ipc::RandomAccessStreamParams streamParams(
                      std::move(selfHolder->mStreamParams));
                }

                return BoolPromise::CreateAndResolve(true, __func__);
              })
      ->Then(mWorkerRef->Private()->ControlEventTarget(), __func__,
             [self = RefPtr(this)](const BoolPromise::ResolveOrRejectValue&) {
               return self->mIOTaskQueue->BeginShutdown();
             })
      ->Then(
          mWorkerRef->Private()->ControlEventTarget(), __func__,
          [self = RefPtr(this)](const ShutdownPromise::ResolveOrRejectValue&) {
            if (self->mControlActor) {
              RefPtr<BoolPromise::Private> promise =
                  new BoolPromise::Private(__func__);

              self->mControlActor->SendClose(
                  [promise](void_t&&) { promise->Resolve(true, __func__); },
                  [promise](const mozilla::ipc::ResponseRejectReason& aReason) {
                    fs::IPCRejectReporter(aReason);

                    promise->Reject(NS_ERROR_FAILURE, __func__);
                  });

              return RefPtr<BoolPromise>(promise);
            }

            return BoolPromise::CreateAndResolve(true, __func__);
          })
      ->Then(mWorkerRef->Private()->ControlEventTarget(), __func__,
             [self = RefPtr(this)](const BoolPromise::ResolveOrRejectValue&) {
               self->mWorkerRef = nullptr;

               self->mState = State::Closed;

               self->mClosePromiseHolder.ResolveIfExists(true, __func__);
             });

  return OnClose();
}

RefPtr<BoolPromise> FileSystemSyncAccessHandle::OnClose() {
  MOZ_ASSERT(mState == State::Closing);

  return mClosePromiseHolder.Ensure(__func__);
}

// WebIDL Boilerplate

nsIGlobalObject* FileSystemSyncAccessHandle::GetParentObject() const {
  return mGlobal;
}

JSObject* FileSystemSyncAccessHandle::WrapObject(
    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
  return FileSystemSyncAccessHandle_Binding::Wrap(aCx, this, aGivenProto);
}

// WebIDL Interface

uint64_t FileSystemSyncAccessHandle::Read(
    const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aBuffer,
    const FileSystemReadWriteOptions& aOptions, ErrorResult& aRv) {
  return ReadOrWrite(aBuffer, aOptions, /* aRead */ true, aRv);
}

uint64_t FileSystemSyncAccessHandle::Write(
    const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aBuffer,
    const FileSystemReadWriteOptions& aOptions, ErrorResult& aRv) {
  return ReadOrWrite(aBuffer, aOptions, /* aRead */ false, aRv);
}

void FileSystemSyncAccessHandle::Truncate(uint64_t aSize, ErrorResult& aError) {
  if (!IsOpen()) {
    aError.ThrowInvalidStateError("SyncAccessHandle is closed");
    return;
  }

  MOZ_ASSERT(mWorkerRef);

  AutoSyncLoopHolder syncLoop(mWorkerRef->Private(), Canceling);

  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
      syncLoop.GetSerialEventTarget();
  QM_TRY(MOZ_TO_RESULT(syncLoopTarget), [&aError](nsresult) {
    aError.ThrowInvalidStateError("Worker is shutting down");
  });

  InvokeAsync(
      mIOTaskQueue, __func__,
      [selfHolder = quota::TargetPtrHolder(this), aSize]() {
        QM_TRY(MOZ_TO_RESULT(selfHolder->EnsureStream()),
               CreateAndRejectBoolPromise);

        LOG(("%p: Truncate to %" PRIu64, selfHolder->mStream.get(), aSize));
        int64_t offset = 0;
        QM_TRY(MOZ_TO_RESULT(selfHolder->mStream->Tell(&offset)),
               CreateAndRejectBoolPromise);
        QM_TRY(MOZ_TO_RESULT(selfHolder->mStream->Seek(
                   nsISeekableStream::NS_SEEK_SET, aSize)),
               CreateAndRejectBoolPromise);

        QM_TRY(MOZ_TO_RESULT(selfHolder->mStream->SetEOF()),
               CreateAndRejectBoolPromise);
        // restore cursor position (clamp to end of file)
        QM_TRY(MOZ_TO_RESULT(selfHolder->mStream->Seek(
                   nsISeekableStream::NS_SEEK_SET,
                   std::min((uint64_t)offset, aSize))),
               CreateAndRejectBoolPromise);

        return BoolPromise::CreateAndResolve(true, __func__);
      })
      ->Then(syncLoopTarget, __func__,
             [this, &syncLoopTarget](
                 const BoolPromise::ResolveOrRejectValue& aValue) {
               MOZ_ASSERT(mWorkerRef);

               mWorkerRef->Private()->AssertIsOnWorkerThread();

               mWorkerRef->Private()->StopSyncLoop(
                   syncLoopTarget,
                   aValue.IsResolve() ? NS_OK : aValue.RejectValue());
             });

  QM_TRY(MOZ_TO_RESULT(syncLoop.Run()),
         [&aError](const nsresult rv) { aError.Throw(rv); });
}

uint64_t FileSystemSyncAccessHandle::GetSize(ErrorResult& aError) {
  if (!IsOpen()) {
    aError.ThrowInvalidStateError("SyncAccessHandle is closed");
    return 0;
  }

  MOZ_ASSERT(mWorkerRef);

  AutoSyncLoopHolder syncLoop(mWorkerRef->Private(), Canceling);

  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
      syncLoop.GetSerialEventTarget();
  QM_TRY(MOZ_TO_RESULT(syncLoopTarget), [&aError](nsresult) {
    aError.ThrowInvalidStateError("Worker is shutting down");
    return 0;
  });

  // XXX Could we somehow pass the size to `StopSyncLoop` and then get it via
  // `QM_TRY_INSPECT(const auto& size, syncLoop.Run)` ?
  // Could we use Result<UniquePtr<...>, nsresult> for that ?
  int64_t size;

  InvokeAsync(mIOTaskQueue, __func__,
              [selfHolder = quota::TargetPtrHolder(this)]() {
                QM_TRY(MOZ_TO_RESULT(selfHolder->EnsureStream()),
                       CreateAndRejectSizePromise);

                nsCOMPtr<nsIFileMetadata> fileMetadata =
                    do_QueryInterface(selfHolder->mStream);
                MOZ_ASSERT(fileMetadata);

                QM_TRY_INSPECT(
                    const auto& size,
                    MOZ_TO_RESULT_INVOKE_MEMBER(fileMetadata, GetSize),
                    CreateAndRejectSizePromise);

                LOG(("%p: GetSize %" PRIu64, selfHolder->mStream.get(), size));

                return SizePromise::CreateAndResolve(size, __func__);
              })
      ->Then(syncLoopTarget, __func__,
             [this, &syncLoopTarget,
              &size](const Int64Promise::ResolveOrRejectValue& aValue) {
               MOZ_ASSERT(mWorkerRef);

               mWorkerRef->Private()->AssertIsOnWorkerThread();

               if (aValue.IsResolve()) {
                 size = aValue.ResolveValue();

                 mWorkerRef->Private()->StopSyncLoop(syncLoopTarget, NS_OK);
               } else {
                 mWorkerRef->Private()->StopSyncLoop(syncLoopTarget,
                                                     aValue.RejectValue());
               }
             });

  QM_TRY(MOZ_TO_RESULT(syncLoop.Run()), [&aError](const nsresult rv) {
    aError.Throw(rv);
    return 0;
  });

  return size;
}

void FileSystemSyncAccessHandle::Flush(ErrorResult& aError) {
  if (!IsOpen()) {
    aError.ThrowInvalidStateError("SyncAccessHandle is closed");
    return;
  }

  MOZ_ASSERT(mWorkerRef);

  AutoSyncLoopHolder syncLoop(mWorkerRef->Private(), Canceling);

  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
      syncLoop.GetSerialEventTarget();
  QM_TRY(MOZ_TO_RESULT(syncLoopTarget), [&aError](nsresult) {
    aError.ThrowInvalidStateError("Worker is shutting down");
  });

  InvokeAsync(mIOTaskQueue, __func__,
              [selfHolder = quota::TargetPtrHolder(this)]() {
                QM_TRY(MOZ_TO_RESULT(selfHolder->EnsureStream()),
                       CreateAndRejectBoolPromise);

                LOG(("%p: Flush", selfHolder->mStream.get()));

                QM_TRY(
                    MOZ_TO_RESULT(selfHolder->mStream->OutputStream()->Flush()),
                    CreateAndRejectBoolPromise);

                return BoolPromise::CreateAndResolve(true, __func__);
              })
      ->Then(syncLoopTarget, __func__,
             [this, &syncLoopTarget](
                 const BoolPromise::ResolveOrRejectValue& aValue) {
               MOZ_ASSERT(mWorkerRef);

               mWorkerRef->Private()->AssertIsOnWorkerThread();

               mWorkerRef->Private()->StopSyncLoop(
                   syncLoopTarget,
                   aValue.IsResolve() ? NS_OK : aValue.RejectValue());
             });

  QM_TRY(MOZ_TO_RESULT(syncLoop.Run()),
         [&aError](const nsresult rv) { aError.Throw(rv); });
}

void FileSystemSyncAccessHandle::Close() {
  if (!(IsOpen() || IsClosing())) {
    return;
  }

  MOZ_ASSERT(mWorkerRef);

  // Normally mWorkerRef can be used directly for stopping the sync loop, but
  // the async close is special because mWorkerRef is cleared as part of the
  // operation. That's why we need to use this extra strong ref to the
  // `StrongWorkerRef`.
  RefPtr<StrongWorkerRef> workerRef = mWorkerRef;

  AutoSyncLoopHolder syncLoop(workerRef->Private(), Killing);

  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
      syncLoop.GetSerialEventTarget();
  MOZ_ASSERT(syncLoopTarget);

  InvokeAsync(syncLoopTarget, __func__, [self = RefPtr(this)]() {
    if (self->IsOpen()) {
      return self->BeginClose();
    }
    return self->OnClose();
  })->Then(syncLoopTarget, __func__, [&workerRef, &syncLoopTarget]() {
    MOZ_ASSERT(workerRef);

    workerRef->Private()->AssertIsOnWorkerThread();

    workerRef->Private()->StopSyncLoop(syncLoopTarget, NS_OK);
  });

  MOZ_ALWAYS_SUCCEEDS(syncLoop.Run());
}

uint64_t FileSystemSyncAccessHandle::ReadOrWrite(
    const MaybeSharedArrayBufferViewOrMaybeSharedArrayBuffer& aBuffer,
    const FileSystemReadWriteOptions& aOptions, const bool aRead,
    ErrorResult& aRv) {
  if (!IsOpen()) {
    aRv.ThrowInvalidStateError("SyncAccessHandle is closed");
    return 0;
  }

  MOZ_ASSERT(mWorkerRef);

  auto throwAndReturn = [&aRv](const nsresult rv) {
    aRv.Throw(rv);
    return 0;
  };

  // Handle seek before read ('at')
  const auto at = [&aOptions]() -> uint64_t {
    if (aOptions.mAt.WasPassed()) {
      return aOptions.mAt.Value();
    }
    // Spec says default for at is 0 (2.6)
    return 0;
  }();

  const auto offset = CheckedInt<int64_t>(at);
  QM_TRY(MOZ_TO_RESULT(offset.isValid()), throwAndReturn);

  AutoSyncLoopHolder syncLoop(mWorkerRef->Private(), Canceling);

  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
      syncLoop.GetSerialEventTarget();
  QM_TRY(MOZ_TO_RESULT(syncLoopTarget), [&aRv](nsresult) {
    aRv.ThrowInvalidStateError("Worker is shutting down");
    return 0;
  });

  uint64_t totalCount = 0;

  ProcessTypedArraysFixed(aBuffer, [&](const Span<uint8_t> aData) {
    InvokeAsync(
        mIOTaskQueue, __func__,
        [selfHolder = quota::TargetPtrHolder(this), aData,
         use_offset = aOptions.mAt.WasPassed(), offset, aRead, syncLoopTarget,
         &totalCount]() {
          QM_TRY(MOZ_TO_RESULT(selfHolder->EnsureStream()),
                 CreateAndRejectBoolPromise);
          if (use_offset) {
            LOG_VERBOSE(("%p: Seeking to %" PRIu64, selfHolder->mStream.get(),
                         offset.value()));

            QM_TRY(MOZ_TO_RESULT(selfHolder->mStream->Seek(
                       nsISeekableStream::NS_SEEK_SET, offset.value())),
                   CreateAndRejectBoolPromise);
          }

          nsCOMPtr<nsIInputStream> inputStream;
          nsCOMPtr<nsIOutputStream> outputStream;

          if (aRead) {
            LOG_VERBOSE(("%p: Reading %zu bytes", selfHolder->mStream.get(),
                         aData.Length()));

            inputStream = selfHolder->mStream->InputStream();
            outputStream =
                FixedBufferOutputStream::Create(AsWritableChars(aData));
          } else {
            LOG_VERBOSE(("%p: Writing %zu bytes", selfHolder->mStream.get(),
                         aData.Length()));

            QM_TRY(MOZ_TO_RESULT(NS_NewByteInputStream(
                       getter_AddRefs(inputStream), AsChars(aData),
                       NS_ASSIGNMENT_DEPEND)),
                   CreateAndRejectBoolPromise);

            outputStream = selfHolder->mStream->OutputStream();
          }

          auto promiseHolder = MakeUnique<MozPromiseHolder<BoolPromise>>();
          RefPtr<BoolPromise> promise = promiseHolder->Ensure(__func__);

          QM_TRY(MOZ_TO_RESULT(fs::AsyncCopy(
                     inputStream, outputStream, GetCurrentSerialEventTarget(),
                     aRead ? NS_ASYNCCOPY_VIA_WRITESEGMENTS
                           : NS_ASYNCCOPY_VIA_READSEGMENTS,
                     /* aCloseSource */ !aRead, /* aCloseSink */ aRead,
                     [&totalCount](uint32_t count) { totalCount += count; },
                     [promiseHolder = std::move(promiseHolder)](nsresult rv) {
                       promiseHolder->ResolveIfExists(true, __func__);
                     })),
                 CreateAndRejectBoolPromise);

          return promise;
        })
        ->Then(syncLoopTarget, __func__,
               [this, &syncLoopTarget](
                   const BoolPromise::ResolveOrRejectValue& aValue) {
                 MOZ_ASSERT(mWorkerRef);

                 mWorkerRef->Private()->AssertIsOnWorkerThread();

                 mWorkerRef->Private()->StopSyncLoop(syncLoopTarget, NS_OK);
               });

    MOZ_ALWAYS_SUCCEEDS(syncLoop.Run());
  });

  return totalCount;
}

nsresult FileSystemSyncAccessHandle::EnsureStream() {
  if (!mStream) {
    QM_TRY_UNWRAP(mStream, DeserializeRandomAccessStream(mStreamParams),
                  NS_ERROR_FAILURE);

    mozilla::ipc::RandomAccessStreamParams streamParams(
        std::move(mStreamParams));
  }

  return NS_OK;
}

}  // namespace mozilla::dom

Messung V0.5
C=88 H=93 G=90

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge