XPCOM:nsIThreadManager

Revision as of 20:22, 17 January 2006 by Darin (talk | contribs) (→‎Interfaces)

In a world without nested event queues, the concept of a thread and an event queue merge...

Interfaces

[scriptable, uuid(...)]
interface nsIThreadManager : nsISupports {
  /**
   * Create a new named thread (a global, user PRThread).
   */
  nsIThread newThread(in ACString name);
   
  /**
   * Find a named thread.  The empty string names the current thread.
   * The special value "main" is used to identify the name of the 
   * primordial thread.
   */
  nsIThread getThread(in ACString name);
   
  /**
   * Register an external thread implementation.  This function must
   * be called on the native thread corresponding to the given nsIThread.
   * If a nsIThread is already defined for the calling thread, then this
   * function will unregister the previous nsIThread and replace it with
   * the given nsIThread.
   */
  void registerThread(in nsIThread thread);
   
  /**
   * Unregister an external thread implementation.  This function may
   * be called from any thread.
   */
  void unregisterThread(in nsIThread thread);
   
  /**
   * Shutdown all threads.  This function may only be executed from the
   * primordial thread of the application process.
   */
  void shutdownAll();
};
 
[scriptable, uuid(...)]
interface nsIThread : nsISupports {
  /**
   * Returns the name of the thread.
   */
  readonly attribute ACString name;
   
  /**
   * Shutdown the thread.  This function should not be executed from the
   * thread itself.  Instead, it is meant to be executed from another
   * thread.  When this function returns, the thread will be shutdown, and
   * it will no longer be possible to dispatch tasks to the thread.
   */
  void shutdown();
   
  /**
   * Dispatch a task to the thread.  This function may be executed from any
   * thread.  By default, flags is 0.  If flags includes DISPATCH_SYNC, then
   * the dispatch function will not return until the task has been run.
   * NOTE: In the DISPATCH_SYNC case, this may have the side-effect of 
   * running other tasks on the current thread while waiting for the
   * given task to run.  This function is re-entrant.
   */
  void dispatch(in nsIRunnable task, in long flags);
  const long DISPATCH_SYNC = 1;
   
  /**
   * Run the next task assigned to this thread.  This function should block
   * execution of the current thread until a task is available and run.
   * This function is re-entrant but may only be called if this thread is the 
   * current thread.
   */
  void runNextTask();
   
  /**
   * Returns true if this thread is the current thread.
   */
  boolean isCurrent();
};

Remarks

  • Thread priority for native threads can be exposed via nsISupportsPriority
  • Custom threads like the socket transport thread and the primordial thread will use registerThread/unregisterThread. The primordial thread will need to interact with the "native" event system during calls to runNextTask, and the socket transport thread will need to poll sockets and perform i/o operations during calls to runNextTask.
  • Thread names must be unique.
  • The Necko I/O thread pool implements nsIEventTarget today, and we could probably imagine a pseudo-nsIThread implementation that represented a thread pool. Not sure, yet, what that would exactly look like.
  • We probably need an alternative for nsIEventQueue::revokeEvents. There are several possibilities: (1) make consumers hold references to their nsIRunnable's so they can "disconnect" them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks. I'm not sure what is best yet.

How do synchronous events work?

If dispatch is called on a nsIThread, it first checks to see if the current thread is the same as this thread. If it is, then it just runs the task directly without queuing it up. However, if not, then it must queue up the task to be executed when this thread next runs. To avoid returning to the caller immediately, the method gets the current thread and calls its runNextTask method in a loop until it receives acknowledgement that the queued task has been run.