зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1672431 - Provide a shutdown client for IOUtils r=xpcom-reviewers,nika
IOUtils now provides a shutdown client for clients to register IO jobs with that need to run before shutdown finishes. This allows IO jobs to run during the profileBeforeChange phase. IOUtils' event queuing has been refactored into a singleton EventQueue class, which is responsible for running tasks and setting up shutdown blockers. It is now guarded behind a StaticDataMutex so that is more explicitly clear what is and is not re-entrant. (The atomic sShutdownFinished cannot be placed behind the mutex because we need to keep track of that state even when we do not have an EventQueue.) Differential Revision: https://phabricator.services.mozilla.com/D103973
This commit is contained in:
Родитель
3ba0fd279a
Коммит
ca179d4005
|
@ -206,6 +206,12 @@ namespace IOUtils {
|
|||
Promise<boolean> exists(DOMString path);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
partial namespace IOUtils {
|
||||
[Throws]
|
||||
readonly attribute any profileBeforeChange;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to be passed to the |IOUtils.readUTF8| method.
|
||||
*/
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -14,12 +14,14 @@
|
|||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/IOUtilsBinding.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "nsIAsyncShutdown.h"
|
||||
#include "nsISerialEventTarget.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -119,6 +121,10 @@ class IOUtils final {
|
|||
static already_AddRefed<Promise> Exists(GlobalObject& aGlobal,
|
||||
const nsAString& aPath);
|
||||
|
||||
static void GetProfileBeforeChange(GlobalObject& aGlobal,
|
||||
JS::MutableHandle<JS::Value>,
|
||||
ErrorResult& aRv);
|
||||
|
||||
class JsBuffer;
|
||||
|
||||
/**
|
||||
|
@ -142,23 +148,20 @@ class IOUtils final {
|
|||
struct InternalFileInfo;
|
||||
struct InternalWriteOpts;
|
||||
class MozLZ4;
|
||||
class EventQueue;
|
||||
class State;
|
||||
|
||||
static StaticDataMutex<StaticRefPtr<nsISerialEventTarget>>
|
||||
sBackgroundEventTarget;
|
||||
static StaticRefPtr<nsIAsyncShutdownClient> sBarrier;
|
||||
static Atomic<bool> sShutdownStarted;
|
||||
|
||||
static already_AddRefed<nsIAsyncShutdownClient> GetShutdownBarrier();
|
||||
|
||||
static already_AddRefed<nsISerialEventTarget> GetBackgroundEventTarget();
|
||||
|
||||
static void SetShutdownHooks();
|
||||
|
||||
/**
|
||||
* Dispatch a task on the event queue and resolve or reject the associated
|
||||
* promise based on the result.
|
||||
*
|
||||
* @param aPromise The promise corresponding to the task running on the event
|
||||
* queue.
|
||||
* @param aFunc The task to run.
|
||||
*/
|
||||
template <typename OkT, typename Fn>
|
||||
static RefPtr<IOPromise<OkT>> RunOnBackgroundThread(Fn aFunc);
|
||||
|
||||
template <typename OkT, typename Fn>
|
||||
static void RunOnBackgroundThreadAndResolve(Promise* aPromise, Fn aFunc);
|
||||
static void DispatchAndResolve(EventQueue* aQueue, Promise* aPromise,
|
||||
Fn aFunc);
|
||||
|
||||
/**
|
||||
* Creates a new JS Promise.
|
||||
|
@ -172,16 +175,6 @@ class IOUtils final {
|
|||
const InternalFileInfo& aInternalFileInfo,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
/**
|
||||
* Resolves |aPromise| with an appropriate JS value for |aValue|.
|
||||
*/
|
||||
template <typename T>
|
||||
static void ResolveJSPromise(Promise* aPromise, T&& aValue);
|
||||
/**
|
||||
* Rejects |aPromise| with an appropriate |DOMException| describing |aError|.
|
||||
*/
|
||||
static void RejectJSPromise(Promise* aPromise, const IOError& aError);
|
||||
|
||||
/**
|
||||
* Attempts to read the entire file at |aPath| into a buffer.
|
||||
*
|
||||
|
@ -365,6 +358,80 @@ class IOUtils final {
|
|||
* @return Whether or not the file exists.
|
||||
*/
|
||||
static Result<bool, IOError> ExistsSync(nsIFile* aFile);
|
||||
|
||||
enum class EventQueueStatus {
|
||||
Uninitialized,
|
||||
Initialized,
|
||||
Shutdown,
|
||||
};
|
||||
|
||||
enum class ShutdownBlockerStatus {
|
||||
Uninitialized,
|
||||
Initialized,
|
||||
Failed,
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal IOUtils state.
|
||||
*/
|
||||
class State {
|
||||
public:
|
||||
StaticAutoPtr<EventQueue> mEventQueue;
|
||||
EventQueueStatus mQueueStatus = EventQueueStatus::Uninitialized;
|
||||
ShutdownBlockerStatus mBlockerStatus = ShutdownBlockerStatus::Uninitialized;
|
||||
|
||||
/**
|
||||
* Set up shutdown hooks to free our internals at shutdown.
|
||||
*
|
||||
* NB: Must be called on main thread.
|
||||
*/
|
||||
void SetShutdownHooks();
|
||||
};
|
||||
|
||||
using StateMutex = StaticDataMutex<State>;
|
||||
|
||||
/**
|
||||
* Lock the state mutex and return a handle. If shutdown has not yet
|
||||
* finished, the internals will be constructed if necessary.
|
||||
*
|
||||
* @returns A handle to the internal state, which can be used to retrieve the
|
||||
* event queue.
|
||||
* If |Some| is returned, |mEventQueue| is guaranteed to be
|
||||
* initialized. If shutdown has finished, |Nothing| is returned.
|
||||
*/
|
||||
static Maybe<StateMutex::AutoLock> GetState();
|
||||
|
||||
static StateMutex sState;
|
||||
};
|
||||
|
||||
/**
|
||||
* The IOUtils event queue.
|
||||
*/
|
||||
class IOUtils::EventQueue final {
|
||||
friend void IOUtils::State::SetShutdownHooks();
|
||||
|
||||
public:
|
||||
EventQueue();
|
||||
|
||||
EventQueue(const EventQueue&) = delete;
|
||||
EventQueue(EventQueue&&) = delete;
|
||||
EventQueue& operator=(const EventQueue&) = delete;
|
||||
EventQueue& operator=(EventQueue&&) = delete;
|
||||
|
||||
template <typename OkT, typename Fn>
|
||||
RefPtr<IOPromise<OkT>> Dispatch(Fn aFunc);
|
||||
|
||||
Result<already_AddRefed<nsIAsyncShutdownClient>, nsresult>
|
||||
GetProfileBeforeChangeClient();
|
||||
|
||||
Result<already_AddRefed<nsIAsyncShutdownBarrier>, nsresult>
|
||||
GetProfileBeforeChangeBarrier();
|
||||
|
||||
private:
|
||||
nsresult SetShutdownHooks();
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> mBackgroundEventTarget;
|
||||
nsCOMPtr<nsIAsyncShutdownBarrier> mProfileBeforeChangeBarrier;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -477,13 +544,25 @@ class IOUtils::MozLZ4 {
|
|||
Span<const uint8_t> aFileContents, IOUtils::BufferKind);
|
||||
};
|
||||
|
||||
class IOUtilsShutdownBlocker : public nsIAsyncShutdownBlocker {
|
||||
class IOUtilsShutdownBlocker : public nsIAsyncShutdownBlocker,
|
||||
public nsIAsyncShutdownCompletionCallback {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
|
||||
NS_DECL_NSIASYNCSHUTDOWNCOMPLETIONCALLBACK
|
||||
|
||||
enum Phase {
|
||||
ProfileBeforeChange,
|
||||
XpcomWillShutdown,
|
||||
};
|
||||
|
||||
explicit IOUtilsShutdownBlocker(Phase aPhase) : mPhase(aPhase) {}
|
||||
|
||||
private:
|
||||
virtual ~IOUtilsShutdownBlocker() = default;
|
||||
|
||||
Phase mPhase;
|
||||
RefPtr<nsIAsyncShutdownClient> mParentClient;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -297,7 +297,7 @@ var ClientIDImpl = {
|
|||
try {
|
||||
await IOUtils.makeDirectory(gDatareportingPath);
|
||||
} catch (ex) {
|
||||
if (ex.name != "NotAllowedError") {
|
||||
if (!(ex instanceof DOMException) || ex.name !== "AbortError") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче