/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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 "nsISupports.idl" #include "nsIRunnable.idl" %{C++ #include "nsCOMPtr.h" #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Atomics.h" #include "mozilla/TypedEnumBits.h" class nsITargetShutdownTask; %} native alreadyAddRefed_nsIRunnable(already_AddRefed); [ptr] native nsITargetShutdownTask(nsITargetShutdownTask); [builtinclass, scriptable, rust_sync, uuid(a03b8b63-af8b-4164-b0e5-c41e8b2b7cfa)] interface nsIEventTarget : nsISupports { /** * Flags used to customize the behaviour of a `Dispatch` call. * * WARNING: These flags are generally hints, and are not universally supported * by all nsIEventTarget implementations. An implementation may ignore some or * all of these flags. * * HISTORIC NOTE: There used to be a `DISPATCH_SYNC` flag which would spin a * nested event loop while dispatching (and could not be safely ignored by * event target implementations), but this has since been removed. */ cenum DispatchFlags : 32 { /** * DISPATCH_NORMAL corresponds to the absense of other flags. This is used * for dispatching async events to an event target which will be queued for * later processing. */ DISPATCH_NORMAL = 0, // NOTE: 1 << 0 used to be DISPATCH_SYNC /** * This flag specifies that the dispatch is occurring from a running event * that was dispatched to the same event target, and that event is about to * finish. * * A thread pool can use this as an optimization hint to not spin up * another thread, since the current thread is about to become idle. */ DISPATCH_AT_END = 1 << 1, /** * This flag specifies that the dispatched event may block the thread on * which it executes, usually by doing some sort of I/O. This information * may be used by the event target to execute the job on a thread * specifically dedicated to doing I/O, leaving other threads available for * CPU-intensive work. */ DISPATCH_EVENT_MAY_BLOCK = 1 << 2, /** * This flag specifies that the dispatched event should be delivered to the * target thread even if the thread has been configured to block dispatching * of runnables. This is generally done for threads which have their own * internal event loop, such as thread pools or the timer thread, and will not * service runnables dispatched to them until shutdown. */ DISPATCH_IGNORE_BLOCK_DISPATCH = 1 << 3, /** * This flag specifies that the caller of the given dispatch is prepared to * handle dispatch failures itself. * * Some nsIEventTarget implementations, such as nsThread, leak the passed-in * runnable if there is a failure when dispatching (e.g. due to the thread * being destroyed). This is done as many callers are unprepared to handle * calls to Dispatch failing, and could otherwise e.g. destroy a object on * the wrong thread. * * By specifying DISPATCH_FALLIBLE, you communicate to the nsIEventTarget * implementation that you are prepared to handle the consequences of the * dispatch failing. nsIEventTarget implementations should neither leak * passed-in runnables nor fire assertions on state-related error codepaths * (such as late shutdown dispatch assertions) when DISPATCH_FALLIBLE is * specified. * * When using DISPATCH_FALLIBLE, the caller must be careful that the event * object is safe to discard on the calling thread, and that other systems * do not depend on the runnable completing on error cases. * * NOTE: Many nsIEventTarget implementations (including TaskQueue and * nsThreadPool) never leak the passed-in runnable on failure, whether or * not this flag is specified. Dispatched events may always be released by * the dispatcher on error for those types. * * See bug 803174, bug 1237213 and bug 1824189 for historical context. */ DISPATCH_FALLIBLE = 1 << 4, }; /** * IsOnCurrentThread() should return true if events dispatched to this target * can possibly run on the current thread, and false otherwise. In the case * of an nsIEventTarget for a thread pool, it should return true on all * threads in the pool. In the case of a non-thread nsIEventTarget such as * ThrottledEventQueue, it should return true on the thread where events are * expected to be processed, even if no events from the queue are actually * being processed right now. * * When called on an nsISerialEventTarget, IsOnCurrentThread can be used to * ensure that no other thread has "ownership" of the event target. As such, * it's useful for asserting that an object is only used on a particular * thread. IsOnCurrentThread can't guarantee that the current event has been * dispatched through a particular event target. * * The infallible version of IsOnCurrentThread() is optimized to avoid a * virtual call for non-thread event targets. Thread targets should set * mThread to their virtual PRThread. Non-thread targets should leave * mThread null and implement IsOnCurrentThreadInfallible() to * return the correct answer. * * The fallible version of IsOnCurrentThread may return errors, such as during * shutdown. If it does not return an error, it should return the same result * as the infallible version. The infallible method should return the correct * result regardless of whether the fallible method returns an error. */ %{C++ public: // Infallible. Defined in nsThreadUtils.cpp. Delegates to // IsOnCurrentThreadInfallible when mThread is null. bool IsOnCurrentThread(); protected: mozilla::Atomic mThread; nsIEventTarget() : mThread(nullptr) {} %} // Note that this method is protected. We define it through IDL, rather than // in a %{C++ block, to ensure that the correct method indices are recorded // for XPConnect purposes. [noscript,notxpcom] boolean isOnCurrentThreadInfallible(); %{C++ public: %} // Fallible version of IsOnCurrentThread. boolean isOnCurrentThread(); /* until we can get rid of all uses, keep the non-alreadyAddRefed<> version */ %{C++ nsresult Dispatch(nsIRunnable* aEvent, DispatchFlags aFlags) { return Dispatch(nsCOMPtr(aEvent).forget(), aFlags); } %} /** * Dispatch an event to this event target. This function may be called from * any thread, and it may be called re-entrantly. * * @param event * The alreadyAddRefed<> event to dispatch. * NOTE that the event should be leaked if it fails to dispatch unless * NS_DISPATCH_FALLIBLE is passed. * @param flags * The flags modifying event dispatch. The flags are described in detail * above. * * @throws NS_ERROR_INVALID_ARG * Indicates that event is null. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is shutting down and has finished processing * events, so this event would never run and has not been dispatched. */ [noscript, binaryname(Dispatch)] void dispatchFromC(in alreadyAddRefed_nsIRunnable event, [default(DISPATCH_NORMAL)] in nsIEventTarget_DispatchFlags flags); /** * Version of Dispatch to expose to JS, which doesn't require an alreadyAddRefed<> * (it will be converted to that internally) * * @param event * The (raw) event to dispatch. * @param flags * The flags modifying event dispatch. The flags are described in detail * above. * * @throws NS_ERROR_INVALID_ARG * Indicates that event is null. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is shutting down and has finished processing * events, so this event would never run and has not been dispatched. */ [binaryname(DispatchFromScript)] void dispatch(in nsIRunnable event, in nsIEventTarget_DispatchFlags flags); /** * Dispatch an event to this event target, but do not run it before delay * milliseconds have passed. This function may be called from any thread. * * @param event * The alreadyAddrefed<> event to dispatch. * @param delay * The delay (in ms) before running the event. If event does not rise to * the top of the event queue before the delay has passed, it will be set * aside to execute once the delay has passed. Otherwise, it will be * executed immediately. * * @throws NS_ERROR_INVALID_ARG * Indicates that event is null. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is shutting down and has finished processing * events, so this event would never run and has not been dispatched, or * that delay is zero. */ [noscript] void delayedDispatch(in alreadyAddRefed_nsIRunnable event, in unsigned long delay); /** * Register an task to be run on this event target when it begins shutting * down. Shutdown tasks may be run in any order, and this function may be * called from any thread. * * The event target may or may not continue accepting events during or after * the shutdown task. The precise behaviour here depends on the event target. * * @param task * The task to be registered to the target thread. * NOTE that unlike `dispatch`, this will not leak the task if it fails. * * @throws NS_ERROR_INVALID_ARG * Indicates that task is null. * @throws NS_ERROR_NOT_IMPLEMENTED * Indicates that this event target doesn't support shutdown tasks. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is already shutting down, and no longer * accepting events. */ [noscript] void registerShutdownTask(in nsITargetShutdownTask task); /** * Unregisters an task previously registered with registerShutdownTask. This * function may be called from any thread. * * @param task * The task previously registered with registerShutdownTask * * @throws NS_ERROR_INVALID_ARG * Indicates that task is null. * @throws NS_ERROR_NOT_IMPLEMENTED * Indicates that this event target doesn't support shutdown tasks. * @throws NS_ERROR_UNEXPECTED * Indicates that the thread is already shutting down, and no longer * accepting events, or that the shutdown task cannot be found. */ [noscript] void unregisterShutdownTask(in nsITargetShutdownTask task); }; %{C++ // convenient aliases: #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL #define NS_DISPATCH_AT_END nsIEventTarget::DISPATCH_AT_END #define NS_DISPATCH_EVENT_MAY_BLOCK nsIEventTarget::DISPATCH_EVENT_MAY_BLOCK #define NS_DISPATCH_IGNORE_BLOCK_DISPATCH nsIEventTarget::DISPATCH_IGNORE_BLOCK_DISPATCH #define NS_DISPATCH_FALLIBLE nsIEventTarget::DISPATCH_FALLIBLE // Convenience bitwise operators for the flag cenum MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIEventTarget::DispatchFlags) // Convenient NS_DECL variant that includes some C++-only methods. #define NS_DECL_NSIEVENTTARGET_FULL \ NS_DECL_NSIEVENTTARGET \ /* Avoid hiding these methods */ \ using nsIEventTarget::Dispatch; \ using nsIEventTarget::IsOnCurrentThread; %}