XPCOM:nsIEventTargetManager

From MozillaWiki
Jump to: navigation, search

Summary

I'd like to provide an interface that exposes our event queue system in a freezable and scriptable fashion.

nsIEventTarget abstracts the posting of a PLEvent to a thread event queue. It is currently implemented by nsEventQueue, nsSocketTransportService, and nsIOThreadPool. Most consumers only know how to work with a nsIEventQueue, which is only implemented by the nsEventQueue class. It is fairly straightforward to convert most consumers over to nsIEventTarget since most consumers only need the ability to call PostEvent. However, PostEvent is not scriptable, and it relies on the PLEvent datastructure, which is not something we want to freeze.

Proposal

In order to hide the details of nsIEventTarget, we want to invent a new singleton interface that can be used to post "events" to a nsIEventTarget. We leverage the nsIRunnable interface to express "events." nsIRunnable was originally introduced to represent a task dispatched to a newly created thread (see nsIThread), which is conceptually very similar an event being posted to an event target.

This work is being tracked by bug 315442.

Interface

The following is the proposed interface:

[scriptable, uuid(...)]
interface nsIEventTargetManager : nsISupports
{
  /**
   * This method dispatches a runnable to the specified event target, which
   * may correspond to a different thread.
   *
   * @param target
   *        The nsIEventTarget where the runnable will be executed.
   * @param runnable
   *        The nsIRunnable to execute.
   * @param synchronous
   *        If true, then this method will not return until the runnable
   *        has been executed.  If false, then this method will return
   *        immediately (possibly before the runnable has executed).  If
   *        synchronous is set to true and the event target specifies the 
   *        current thread, then the runnable will be executed directly
   *        without being posted to the event target.
   *
   * @throws NS_ERROR_INVALID_ARG
   *         This exception is thrown if either target or runnable is null.
   */
  void postEvent(in nsIEventTarget target,
                 in nsIRunnable runnable,
                 in boolean synchronous);
  /**
   * This method returns an event target by name.
   *
   * @param name
   *        The name of the event target requested.  If this value is null,
   *        then the event target of the current thread is returned.  If
   *        this value is the string "main", then the event target of the
   *        main application thread is returned.  The main application
   *        thread is the thread on which XPCOM was initialized.
   *
   * @returns null if the named event target is undefined.
   */
  nsIEventTarget getEventTarget(in string name);
  /**
   * This method sets the event target for the current thread.  If there
   * was already an event target defined for the current thread, then that
   * event target is replaced (i.e., its name is removed from the name-to-
   * event-target mapping, and the new event target takes its place as the
   * event target for the current thread).
   *
   * @param name
   *        The name of the event target being set or null.  If non-null,
   *        then the string must be unique, and it may then be used with
   *        getEventTarget to lookup this event target from another thread.
   *        If null, then this event target will be unnamed.
   * @param target
   *        The event target being set.
   *
   * @throws NS_ERROR_INVALID_ARG
   *         This exception is thrown if name is null, if target is null,
   *         or if name is either not unique or invalid.
   */
  void setEventTarget(in string name, in nsIEventTarget target);
};

Component

A singleton implementing this interface will be available under the following ContractID:

@mozilla.org/event-target-manager;1

C++ Utilities

And, the following C++ functional equivalents will be available via nsEventTargetUtils.h:

/**
 * This method is equivalent to nsIEventTargetManager::PostEvent
 */
nsresult NS_PostEvent(nsIEventTarget *target, nsIRunnable *runnable,
                      PRBool synchronous = PR_FALSE);
 
/**
 * This method is exists for API symmetry.  It is equivalent to
 * nsIEventTarget::PostEvent or nsIEventTarget::PostSynchronousEvent.
 */
nsresult NS_PostEvent(nsIEventTarget *target, PLEvent *event,
                      PRBool synchronous = PR_FALSE);
 
/**
 * This method simplifies getting an event target and posting an
 * event (in the form of a runnable) to it.
 */
nsresult NS_PostEvent(const char *targetName, nsIRunnable *runnable,
                      PRBool synchronous = PR_FALSE);
 
/**
 * This method simplifies getting an event target and posting an
 * event (in the form of a PLEvent) to it.
 */
nsresult NS_PostEvent(const char *targetName, PLEvent *event,
                      PRBool synchronous = PR_FALSE);
/**
 * This method is equivalent to nsIEventTargetManager::GetEventTarget
 */
nsresult NS_GetEventTarget(const char *name, nsIEventTarget **target);
 
/**
 * This method is equivalent to nsIEventTargetManager::SetEventTarget
 */
nsresult NS_SetEventTarget(const char *name, nsIEventTarget *target);
 
/**
 * This method is equivalent to NS_GetEventTarget(nsnull)
 */
nsresult NS_GetCurrentEventTarget(nsIEventTarget **target);
 
/**
 * This method is equivalent to NS_GetEventTarget("main")
 */
nsresult NS_GetMainEventTarget(nsIEventTarget **target);

These functions are provided to make this API easier to use from within the Mozilla codebase and thereby encourage its use.

Issues

The meaning of sychronous PostEvent needs to be better specified. Does the thread calling PostEvent pump events for that thread while it waits for its event to be processed? This is an important question because the caller of this function needs to know whether or not to expect the possibility of re-entrancy.