<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mozilla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Darin</id>
	<title>MozillaWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mozilla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Darin"/>
	<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/Special:Contributions/Darin"/>
	<updated>2026-08-19T00:31:51Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.10</generator>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=28016</id>
		<title>Class:nsTDeque</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=28016"/>
		<updated>2006-06-18T19:06:38Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; template &amp;lt;class T&amp;gt;&lt;br /&gt;
 class nsTDeque {&lt;br /&gt;
 public:&lt;br /&gt;
   /**&lt;br /&gt;
    * @constructor&lt;br /&gt;
    * @param objectsPerPage&lt;br /&gt;
    *    Optional parameter that specifies the number of objects per page&lt;br /&gt;
    *    in the deque.&lt;br /&gt;
    */&lt;br /&gt;
   explicit nsTDeque(PRUint32 objectsPerPage = 32);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @destructor&lt;br /&gt;
    */&lt;br /&gt;
   ~nsTDeque();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Clear all elements from the deque.&lt;br /&gt;
    */&lt;br /&gt;
   void Clear();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   PR_TRUE if the deque contains no elements and PR_FALSE otherwise.&lt;br /&gt;
    */&lt;br /&gt;
   PRBool IsEmpty();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the front of the deque.&lt;br /&gt;
    * @param obj&lt;br /&gt;
    *   The object to be added.&lt;br /&gt;
    */&lt;br /&gt;
   void PushFront(const T&amp;amp; obj);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element using T&#039;s default constructor to the front of the &lt;br /&gt;
    * deque.&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   The address of the newly added element or null if the object&lt;br /&gt;
    *   could not be allocated. &lt;br /&gt;
    */&lt;br /&gt;
   T* PushFront();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the back of the deque.&lt;br /&gt;
    * @param obj&lt;br /&gt;
    *   The object to be added.&lt;br /&gt;
    */&lt;br /&gt;
   void PushBack(const T&amp;amp; obj);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element using T&#039;s default constructor to the back of the &lt;br /&gt;
    * deque.&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   The address of the newly added element or null if the object&lt;br /&gt;
    *   could not be allocated. &lt;br /&gt;
    */&lt;br /&gt;
   T* PushBack();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A const reference to the element at the front of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   const T&amp;amp; Front() const;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A reference to the element at the front of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   T&amp;amp; Front();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A const reference to the element at the back of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   const T&amp;amp; Back() const;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A reference to the element at the back of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   T&amp;amp; Back();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Removes the element at the front of the deque.  This method&lt;br /&gt;
    * has no effect if the deque is empty.&lt;br /&gt;
    */&lt;br /&gt;
   void PopFront();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Removes the element at the back of the deque.  This method&lt;br /&gt;
    * has no effect if the deque is empty.&lt;br /&gt;
    */&lt;br /&gt;
   void PopBack();&lt;br /&gt;
 };&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=27914</id>
		<title>Class:nsTDeque</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=27914"/>
		<updated>2006-06-15T17:51:08Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; template &amp;lt;class T&amp;gt;&lt;br /&gt;
 class nsTDeque {&lt;br /&gt;
 public:&lt;br /&gt;
   /**&lt;br /&gt;
    * @constructor&lt;br /&gt;
    * @param objectsPerPage&lt;br /&gt;
    *    Optional parameter that specifies the number of objects per page&lt;br /&gt;
    *    in the deque.&lt;br /&gt;
    */&lt;br /&gt;
   explicit nsTDeque(PRUint32 objectsPerPage = 32);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @destructor&lt;br /&gt;
    */&lt;br /&gt;
   ~nsTDeque();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Clear all elements from the deque.&lt;br /&gt;
    */&lt;br /&gt;
   void Clear();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   The number of elements in the deque.&lt;br /&gt;
    */&lt;br /&gt;
   PRUint32 Length();  // or Count() ?&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   PR_TRUE if the deque contains no elements and PR_FALSE otherwise.&lt;br /&gt;
    */&lt;br /&gt;
   PRBool IsEmpty();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the front of the deque.&lt;br /&gt;
    * @param obj&lt;br /&gt;
    *   The object to be added.&lt;br /&gt;
    */&lt;br /&gt;
   void PushFront(const T&amp;amp; obj);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element using T&#039;s default constructor to the front of the &lt;br /&gt;
    * deque.&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   The address of the newly added element or null if the object&lt;br /&gt;
    *   could not be allocated. &lt;br /&gt;
    */&lt;br /&gt;
   T* PushFront();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the back of the deque.&lt;br /&gt;
    * @param obj&lt;br /&gt;
    *   The object to be added.&lt;br /&gt;
    */&lt;br /&gt;
   void PushBack(const T&amp;amp; obj);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element using T&#039;s default constructor to the back of the &lt;br /&gt;
    * deque.&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   The address of the newly added element or null if the object&lt;br /&gt;
    *   could not be allocated. &lt;br /&gt;
    */&lt;br /&gt;
   T* PushBack();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A const reference to the element at the front of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   const T&amp;amp; Front() const;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A reference to the element at the front of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   T&amp;amp; Front();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A const reference to the element at the back of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   const T&amp;amp; Back() const;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @returns&lt;br /&gt;
    *   A reference to the element at the back of the deque.&lt;br /&gt;
    *   It is an error to call this method on an empty deque.&lt;br /&gt;
    */&lt;br /&gt;
   T&amp;amp; Back();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Removes the element at the front of the deque.  This method&lt;br /&gt;
    * has no effect if the deque is empty.&lt;br /&gt;
    */&lt;br /&gt;
   void PopFront();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Removes the element at the back of the deque.  This method&lt;br /&gt;
    * has no effect if the deque is empty.&lt;br /&gt;
    */&lt;br /&gt;
   void PopBack();&lt;br /&gt;
 };&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=27903</id>
		<title>Class:nsTDeque</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Class:nsTDeque&amp;diff=27903"/>
		<updated>2006-06-15T15:34:10Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; template &amp;lt;class T&amp;gt;&lt;br /&gt;
 class nsTDeque {&lt;br /&gt;
 public:&lt;br /&gt;
   /**&lt;br /&gt;
    * @constructor&lt;br /&gt;
    * @param objectsPerPage&lt;br /&gt;
    *    Optional parameter that specifies the number of objects per page&lt;br /&gt;
    *    in the deque.&lt;br /&gt;
    */&lt;br /&gt;
   explicit nsTDeque(PRUint32 objectsPerPage = 32);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * @destructor&lt;br /&gt;
    */&lt;br /&gt;
   ~nsTDeque();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Clear all elements from the deque.&lt;br /&gt;
    */&lt;br /&gt;
   void Clear();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the number of elements in the deque.&lt;br /&gt;
    */&lt;br /&gt;
   PRUint32 Length();  // or Count() ?&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the front of the deque.&lt;br /&gt;
    * @param obj&lt;br /&gt;
    *    The object to be added.&lt;br /&gt;
    */&lt;br /&gt;
   void PushFront(const T&amp;amp; obj);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Adds a new element to the front of the deque.&lt;br /&gt;
    * @returns the address of the newly added element. &lt;br /&gt;
    */&lt;br /&gt;
   T* PushFront();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   void PushBack(const T&amp;amp; obj);&lt;br /&gt;
   T* PushBack();&lt;br /&gt;
   const T&amp;amp; Front() const;&lt;br /&gt;
   T&amp;amp; Front();&lt;br /&gt;
   const T&amp;amp; Back() const;&lt;br /&gt;
   T&amp;amp; Back();&lt;br /&gt;
   void PopFront();&lt;br /&gt;
   void PopBack();&lt;br /&gt;
 };&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Necko:UnitTests&amp;diff=27186</id>
		<title>Necko:UnitTests</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Necko:UnitTests&amp;diff=27186"/>
		<updated>2006-06-05T20:17:44Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Overview =&lt;br /&gt;
&lt;br /&gt;
Unit tests for the networking library live under [http://lxr.mozilla.org/mozilla/source/netwerk/test/unit/ netwerk/test/unit/].  The test files are javascript files that are executed using xpcshell (via the [http://lxr.mozilla.org/mozilla/source/tools/test-harness/xpcshell-simple/ xpcshell test harness]).&lt;br /&gt;
&lt;br /&gt;
Unit tests are files named with the prefix &amp;lt;code&amp;gt;&#039;&#039;&#039;test_&#039;&#039;&#039;&amp;lt;/code&amp;gt;.  Code may be shared across unit tests by adding it to a file named with the prefix &amp;lt;code&amp;gt;&#039;&#039;&#039;head_&#039;&#039;&#039;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Basics =&lt;br /&gt;
&lt;br /&gt;
Each test file must define a function named &amp;lt;code&amp;gt;&#039;&#039;&#039;run_test&#039;&#039;&#039;&amp;lt;/code&amp;gt; that will be called to execute the test.  Any exception thrown from this function causes the test to fail.  If the function runs to completely without throwing an exception then the test succeeds.&lt;br /&gt;
&lt;br /&gt;
However, for tests that require asynchronous operations, completion of the test can be deferred by calling &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_pending&#039;&#039;&#039;&amp;lt;/code&amp;gt;, which must be paired with a call to &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_finished&#039;&#039;&#039;&amp;lt;/code&amp;gt; when the asynchronous operation completes.&lt;br /&gt;
&lt;br /&gt;
When the test is run, a log file is generated.  That log file will contain the output from the test, plus any error messages with call stacks.&lt;br /&gt;
&lt;br /&gt;
= Functions =&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_throw(messageText)&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Call this function to report an error and exit the test.  The argument is a string that will be reported in the test&#039;s log file.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_check_eq(a, b)&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Call this function to assert that two objects are equal.  If not equal, an exception is logged and the test case is halted.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_check_neq(a, b)&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Call this function to assert that two objects are not equal.  If equal, an exception is logged and the test case is halted.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_timeout(delay, expr)&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Call this function to schedule a timeout.  The given expression will be evaluated after the specified delay (in milliseconds).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_pending()&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Delay exit of the test until &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_finished()&#039;&#039;&#039;&amp;lt;/code&amp;gt; is called.  &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_pending()&#039;&#039;&#039;&amp;lt;/code&amp;gt; may be called multiple times, and &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_finished()&#039;&#039;&#039;&amp;lt;/code&amp;gt; must be paired with each before the unit test will exit.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;&#039;&#039;&#039;do_test_finished()&#039;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
: Call this function to inform the test framework that an asychronous operation has completed.  If all asynchronous operations have completed, then the unit test will exit.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox3/Gecko_Feature_List&amp;diff=27124</id>
		<title>Firefox3/Gecko Feature List</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox3/Gecko_Feature_List&amp;diff=27124"/>
		<updated>2006-06-02T21:47:40Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Gecko 1.9 Feature List */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
= Gecko 1.9 Feature List =&lt;br /&gt;
&lt;br /&gt;
This page is intended to collect the set of features that either have gone in to Gecko 1.9 since Gecko 1.8 was branched, features that people are working on, or features that people intend to work on for Gecko 1.9.  It will eventually be migrated into the [[Firefox3/Gecko_Requirements|Gecko 1.9 Requirements]] document.&lt;br /&gt;
&lt;br /&gt;
Please use this template when adding entries to this list:&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Feature name&lt;br /&gt;
|owner=owner(s)&lt;br /&gt;
|status=&lt;br /&gt;
Status notes: completed, development in progress, spec finished (but no implementation started yet), spec in progress, not started.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== GFX/Widget ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Cairo Graphics&lt;br /&gt;
|owner=vlad, stuart&lt;br /&gt;
|status=&lt;br /&gt;
In progress; 90% on windows, 75% on linux, 25% on mac&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Cocoa Widgets&lt;br /&gt;
|owner=josh&lt;br /&gt;
|status=&lt;br /&gt;
In progress&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Layout ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Reflow branch&lt;br /&gt;
|owner=dbaron&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=CSS box model&lt;br /&gt;
|owner=&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== XUL ===&lt;br /&gt;
&lt;br /&gt;
=== Core/XML ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=XBL2&lt;br /&gt;
|owner=sicking&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== JavaScript ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=JavaScript 2&lt;br /&gt;
|owner=brendan&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=E4X4DOM&lt;br /&gt;
|owner=brendan?&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== DOM ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Language-agnostic DOM&lt;br /&gt;
|owner=&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== SVG ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=SVG images&lt;br /&gt;
|owner=&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Networking ===&lt;br /&gt;
&lt;br /&gt;
{{statusitem&lt;br /&gt;
|name=Cross-domain XMLHttpRequest&lt;br /&gt;
|owner=darin&lt;br /&gt;
|status=&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Runway/Queue&amp;diff=25701</id>
		<title>Runway/Queue</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Runway/Queue&amp;diff=25701"/>
		<updated>2006-05-11T00:52:07Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Add your bugs here to have them scheduled for landing on the [[Runway|runway]]. Be sure to ping the [[Sheriff_Schedule|sheriff on duty]] to let them know once you&#039;ve added your entry to the list.&lt;br /&gt;
* use { { bug | #} } to add your bug&lt;br /&gt;
* the pilot must be around to check in the code and help it land&lt;br /&gt;
* include a summary so the sheriff can prioritize&lt;br /&gt;
* include the pilot&#039;s availability&lt;br /&gt;
&lt;br /&gt;
{|cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #efefef&amp;quot;&lt;br /&gt;
| &#039;&#039;&#039;Bug&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Pilot&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Summary&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;requested time&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;del&amp;gt;{{bug|336945}}&amp;lt;/del&amp;gt;&lt;br /&gt;
| beng&lt;br /&gt;
| Fix web handler selection options on windows. Not so scary. &lt;br /&gt;
| evening EDT&lt;br /&gt;
|-&lt;br /&gt;
| {{bug|336609}}&lt;br /&gt;
| smontagu&lt;br /&gt;
| DeCOMtaminate utils in intl/uconv. Moderately scary, and I will need help from a CVS admin to preserve history of files being moved&lt;br /&gt;
| after 10pm PDT&lt;br /&gt;
|-&lt;br /&gt;
| {{bug|337178}}&lt;br /&gt;
| mconnor&lt;br /&gt;
| Enable suggest search on trunk.  Not so scary, but original landing leaked. &lt;br /&gt;
| flexible with an hour&#039;s notice&lt;br /&gt;
|-&lt;br /&gt;
| {{bug|337305}}&lt;br /&gt;
| myk&lt;br /&gt;
| unbreak adding bookmark from scratch; trivial fix&lt;br /&gt;
| early afternoon PDT &lt;br /&gt;
|-&lt;br /&gt;
| {{bug|337113}}&lt;br /&gt;
| myk&lt;br /&gt;
| make the microsummary service grab generators from the cache instead of the network in more cases; low risk, already checked in on branch&lt;br /&gt;
| early afternoon PDT&lt;br /&gt;
|-&lt;br /&gt;
| {{bug|336857}}&lt;br /&gt;
| myk&lt;br /&gt;
| fix bookmark display regressions in bookmarks menu/toolbar; low risk, possible slight performance win (but probably negligible)&lt;br /&gt;
| early afternoon PDT&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25141</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25141"/>
		<updated>2006-05-05T07:03:38Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsRunnable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] readonly attribute PRThread PRThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(nsIThread **result, nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 rv = NS_DispatchToCurrentThread(event);&lt;br /&gt;
 NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25140</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25140"/>
		<updated>2006-05-05T07:02:41Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsCOMPtr helpers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] readonly attribute PRThread PRThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(nsIThread **result, nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25139</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25139"/>
		<updated>2006-05-05T07:02:27Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] readonly attribute PRThread PRThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(nsIThread **result, nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25138</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25138"/>
		<updated>2006-05-05T06:57:18Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThread */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] readonly attribute PRThread PRThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25137</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25137"/>
		<updated>2006-05-05T06:56:58Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThread */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25136</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=25136"/>
		<updated>2006-05-05T06:56:42Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadManager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new thread (a global, user PRThread).  Currently, flags is&lt;br /&gt;
    * an unused parameter, that must be 0.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Sheriff_Schedule&amp;diff=24940</id>
		<title>Sheriff Schedule</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Sheriff_Schedule&amp;diff=24940"/>
		<updated>2006-05-02T01:59:25Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Schedule */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Schedule =&lt;br /&gt;
{|&lt;br /&gt;
|Saturday || 2006-04-22 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-04-23 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 2006-04-24 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 2006-04-25 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 2006-04-26 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 2006-04-27 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 2006-04-28 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 2006-04-29 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-04-30 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 2006-05-01 || stuart&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 2006-05-02 || vlad&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 2006-05-03 || biesi&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 2006-05-04 || dveditz&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 2006-05-05 || darin&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 2006-05-06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-05-07 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 2006-05-08 || sicking&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 2006-05-09 || brettw&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 2006-05-10 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 2006-05-11 || roc&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 2006-05-12 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 2006-05-13 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-05-14 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 2006-05-15 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 2006-05-16 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 2006-05-17 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 2006-05-18 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 2006-05-19 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 2006-05-20 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-05-21 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 2006-05-22 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 2006-05-23 || bryner&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 2006-05-24 || [[User:Dbaron|David Baron]]&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 2006-05-25 || [[User:Robert_Strong|Robert Strong]]&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 2006-05-26 || &#039;&#039;&#039;available&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 2006-05-27 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 2006-05-28 || #developers&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=WhatwgStorage_Whiteboard&amp;diff=24002</id>
		<title>WhatwgStorage Whiteboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=WhatwgStorage_Whiteboard&amp;diff=24002"/>
		<updated>2006-04-13T22:47:42Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Neil to impl core storage system, jst to impl security/access/scoping.  vlad to advise, shaver to cheerlead.&lt;br /&gt;
&lt;br /&gt;
* Can we track &amp;quot;browser context&amp;quot; well enough?&lt;br /&gt;
** https://bugzilla.mozilla.org/show_bug.cgi?id=117222#c125&lt;br /&gt;
* UI requirements?&lt;br /&gt;
** need a storage limit (by domain and subdomain) -- global limit for A2&lt;br /&gt;
** expiration policy? (after A2)&lt;br /&gt;
* domain hierarchy stuff? (see [http://groups.google.com/group/mozilla.dev.platform/browse_frm/thread/aafd263e23666ee/0a2c54c8c6c5754e?q=domain&amp;amp;rnum=1#0a2c54c8c6c5754e m.d.platform posting])&lt;br /&gt;
&lt;br /&gt;
* What subset?&lt;br /&gt;
** no DOM object or JS object auto-serialization&lt;br /&gt;
** jst to propose the removal of key enumeration to whatwg list (security reasons)&lt;br /&gt;
&lt;br /&gt;
* sessionStorage using in-memory hash or just another table?&lt;br /&gt;
** vlad: no on-disk storage for security reasons?&lt;br /&gt;
** shaver: what about session saver? (what does it do for session cookies?)&lt;br /&gt;
** spec suggests persistence of session data in this case: [http://www.whatwg.org/specs/web-apps/current-work/#the-sessionstorage 4.9.3]&lt;br /&gt;
** darin: cookies have the notion of session only, which is not persisted.  the web cache has the concept of &amp;quot;no-store&amp;quot;.  this storage system needs something like that too.  web apps should be given a way to restrict storage to in-memory only.&lt;br /&gt;
* globalStorage using mozStorage, simple table&lt;br /&gt;
** look at what history guys did for fast domain-based lookup?&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=23557</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=23557"/>
		<updated>2006-04-07T18:55:02Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThread */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method may wait -- provided mayWait is true -- until an event is &lt;br /&gt;
    * dispatched to this thread.  This method is re-entrant but may only be&lt;br /&gt;
    * called if this thread is the current thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @return A boolean value that is &amp;quot;true&amp;quot; if an event was processed.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=23556</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=23556"/>
		<updated>2006-04-07T18:54:01Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThread */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   boolean processNextEvent(in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23054</id>
		<title>Browser Metrics:Data Collectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23054"/>
		<updated>2006-03-28T15:13:43Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Load Event */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Data Format==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
Data will be collected as a stream of events, with the exception of a user profile that is collected once every browser session.  Each event type is represented by a particular XML element in the &amp;lt;tt&amp;gt;http://www.mozilla.org/metrics&amp;lt;/tt&amp;gt; namespace.  We will define several event types that will have predefined schemas.  We will be able to throttle data collection based on the event type, so that verbose events can be turned on and off when we want.  The tentative event types and associated schemas are listed below.  (Note: the list is still very much in flux and will likely change.)&lt;br /&gt;
&lt;br /&gt;
All event types have a &amp;lt;tt&amp;gt;time&amp;lt;/tt&amp;gt; attribute, which gives a timestamp for the event, recorded as seconds since the epoch.&lt;br /&gt;
&lt;br /&gt;
===Profile===&lt;br /&gt;
&lt;br /&gt;
The profile will be collected every browser session, to pick up changes periodically.  The profile element is a grouping element which contains a set of profile values.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
The following elements are optional children of &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;memory&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the memory configuration of the client system.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;mb = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of megabytes of system memory.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;os&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the operating system the client is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the operating system, e.g. &amp;quot;Windows&amp;quot; or &amp;quot;MacOSX&amp;quot;.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the operating system, e.g. &amp;quot;XP&amp;quot; or &amp;quot;Tiger&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;install&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the installation of Firefox the user is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;buildid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the Build ID (e.g. 20060327).&lt;br /&gt;
:; &amp;lt;tt&amp;gt;installdate = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the date the build was first run on this profile (seconds since the epoch).&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extensions&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;extension&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extension&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single extension.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;extensionid = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s id.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s version number.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugins&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugin&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the plugin.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;display&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the user&#039;s display.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;xsize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels horizontally on the display.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;ysize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels vertically on the display.&lt;br /&gt;
&lt;br /&gt;
TBD: talkback GUID&lt;br /&gt;
&lt;br /&gt;
===Window Event===&lt;br /&gt;
&lt;br /&gt;
Window events log various actions pertaining to DOM Windows, which provide a context for load events.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;window&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;action = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Indicates the action that happened for this window.  Possible values are:&lt;br /&gt;
::* &amp;lt;tt&amp;gt;create&amp;lt;/tt&amp;gt;: a new toplevel or child DOM Window was created&lt;br /&gt;
::* &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt;: a toplevel DOM Window was opened&lt;br /&gt;
::* &amp;lt;tt&amp;gt;close&amp;lt;/tt&amp;gt;: a toplevel DOM Window was closed&lt;br /&gt;
::* &amp;lt;tt&amp;gt;destroy&amp;lt;/tt&amp;gt;: a toplevel or child DOM Window was destroyed&lt;br /&gt;
:; &amp;lt;tt&amp;gt;windowid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: The id of the affected window.  Ids are assigned starting from 0 and are never reused during that session.  The window id is not unique across sessions.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;parent = [integer]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For create events, the id of the parent of the newly created window.  Toplevel windows do not have a parent, so this attribute will not be set.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;chrome = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For create events, whether the new window has chrome privileges.  Defaults to false.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;opener = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For open events, the id of the opener DOM window.  Windows opened from native code may not have an opener, and this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
===Load Event===&lt;br /&gt;
&lt;br /&gt;
Load events record a document being loaded into a DOM Window.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;load&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;window = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: The id of the window where the document was loaded.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;origin = [string]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: The action which initiated the load.  Possible values include:&lt;br /&gt;
::* &amp;lt;tt&amp;gt;typed&amp;lt;/tt&amp;gt;: The document URI was typed (or pasted) by the user.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;link&amp;lt;/tt&amp;gt;: The user followed a link to the document URI.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;session-history&amp;lt;/tt&amp;gt;: The user used back/forward navigation to load the document.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;reload&amp;lt;/tt&amp;gt;: The user used the reload button or keyboard shortcut to reload the document.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;global-history&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from their global history.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;bookmark&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from the bookmarks menu, bookmarks toolbar, or bookmarks management UI.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;script&amp;lt;/tt&amp;gt;: A script executing on a page loaded the document.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;refresh&amp;lt;/tt&amp;gt;: A meta-refresh loaded the document.&lt;br /&gt;
::* &amp;lt;tt&amp;gt;external&amp;lt;/tt&amp;gt;: The document URI was passed in from an external application.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;loadtime = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: The time from the initiation of the load until the document is complete (which includes all images, stylesheet, etc) in milliseconds.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;bfCacheHit = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: Whether the document presentation was loaded from the session history cache.  If not specified, assumed to be false.&lt;br /&gt;
&lt;br /&gt;
Todo / possible todo items:&lt;br /&gt;
* cache size before/after load&lt;br /&gt;
* content viewer size estimate&lt;br /&gt;
* cache hit&lt;br /&gt;
* session history index&lt;br /&gt;
* last visit date&lt;br /&gt;
* tagged/bookmarked&lt;br /&gt;
&lt;br /&gt;
===UI Event===&lt;br /&gt;
&lt;br /&gt;
*  action = [click, key, drag, drop...]&lt;br /&gt;
*  target = [some kind of ID, possibly XUL name]&lt;br /&gt;
&lt;br /&gt;
===Garbage Collection===&lt;br /&gt;
&lt;br /&gt;
*  number/size of objects reachable&lt;br /&gt;
*  time spent doing garbage collection&lt;br /&gt;
&lt;br /&gt;
===Startup/Shutdown===&lt;br /&gt;
&lt;br /&gt;
*  time taken&lt;br /&gt;
&lt;br /&gt;
===Places UI Event===&lt;br /&gt;
&lt;br /&gt;
We&#039;ll have to be sure not to duplicate data here between the UI Event and the Places UI Event.  This could potentially be an extension of the regular UI Event.&lt;br /&gt;
&lt;br /&gt;
* node types expanded/clicked&lt;br /&gt;
* periods of time searched&lt;br /&gt;
&lt;br /&gt;
===Autocomplete===&lt;br /&gt;
&lt;br /&gt;
We may try to fit this into the schema of another event type.&lt;br /&gt;
&lt;br /&gt;
*  how far down the list?&lt;br /&gt;
*  match but typed anyway?&lt;br /&gt;
&lt;br /&gt;
===Open Issues===&lt;br /&gt;
&lt;br /&gt;
*  We may want to consolidate some of these events into summary statistics, to compact the amount of data we are collecting.  However, this may not be necessary since we will be able to throttle the data collection on a per event type.&lt;br /&gt;
&lt;br /&gt;
*  To allow extensions to collect data via this system, we will need to define a generic event type or a way to extend the list of predefined events.  This is TBD.&lt;br /&gt;
&lt;br /&gt;
*  The event types listed above are still in flux and may be combined or removed.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23053</id>
		<title>Browser Metrics:Data Collectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23053"/>
		<updated>2006-03-28T15:11:51Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Window Event */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Data Format==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
Data will be collected as a stream of events, with the exception of a user profile that is collected once every browser session.  Each event type is represented by a particular XML element in the &amp;lt;tt&amp;gt;http://www.mozilla.org/metrics&amp;lt;/tt&amp;gt; namespace.  We will define several event types that will have predefined schemas.  We will be able to throttle data collection based on the event type, so that verbose events can be turned on and off when we want.  The tentative event types and associated schemas are listed below.  (Note: the list is still very much in flux and will likely change.)&lt;br /&gt;
&lt;br /&gt;
All event types have a &amp;lt;tt&amp;gt;time&amp;lt;/tt&amp;gt; attribute, which gives a timestamp for the event, recorded as seconds since the epoch.&lt;br /&gt;
&lt;br /&gt;
===Profile===&lt;br /&gt;
&lt;br /&gt;
The profile will be collected every browser session, to pick up changes periodically.  The profile element is a grouping element which contains a set of profile values.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
The following elements are optional children of &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;memory&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the memory configuration of the client system.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;mb = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of megabytes of system memory.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;os&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the operating system the client is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the operating system, e.g. &amp;quot;Windows&amp;quot; or &amp;quot;MacOSX&amp;quot;.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the operating system, e.g. &amp;quot;XP&amp;quot; or &amp;quot;Tiger&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;install&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the installation of Firefox the user is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;buildid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the Build ID (e.g. 20060327).&lt;br /&gt;
:; &amp;lt;tt&amp;gt;installdate = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the date the build was first run on this profile (seconds since the epoch).&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extensions&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;extension&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extension&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single extension.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;extensionid = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s id.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s version number.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugins&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugin&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the plugin.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;display&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the user&#039;s display.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;xsize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels horizontally on the display.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;ysize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels vertically on the display.&lt;br /&gt;
&lt;br /&gt;
TBD: talkback GUID&lt;br /&gt;
&lt;br /&gt;
===Window Event===&lt;br /&gt;
&lt;br /&gt;
Window events log various actions pertaining to DOM Windows, which provide a context for load events.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;window&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;action = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Indicates the action that happened for this window.  Possible values are:&lt;br /&gt;
::* &amp;lt;tt&amp;gt;create&amp;lt;/tt&amp;gt;: a new toplevel or child DOM Window was created&lt;br /&gt;
::* &amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt;: a toplevel DOM Window was opened&lt;br /&gt;
::* &amp;lt;tt&amp;gt;close&amp;lt;/tt&amp;gt;: a toplevel DOM Window was closed&lt;br /&gt;
::* &amp;lt;tt&amp;gt;destroy&amp;lt;/tt&amp;gt;: a toplevel or child DOM Window was destroyed&lt;br /&gt;
:; &amp;lt;tt&amp;gt;windowid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: The id of the affected window.  Ids are assigned starting from 0 and are never reused during that session.  The window id is not unique across sessions.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;parent = [integer]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For create events, the id of the parent of the newly created window.  Toplevel windows do not have a parent, so this attribute will not be set.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;chrome = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For create events, whether the new window has chrome privileges.  Defaults to false.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;opener = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
:: For open events, the id of the opener DOM window.  Windows opened from native code may not have an opener, and this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
===Load Event===&lt;br /&gt;
&lt;br /&gt;
Load events record a document being loaded into a DOM Window.&lt;br /&gt;
&lt;br /&gt;
Element name: &amp;lt;tt&amp;gt;load&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attributes:&lt;br /&gt;
&amp;lt;tt&amp;gt;window = [integer window id]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The id of the window where the document was loaded.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;origin = [string]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
The action which initiated the load.  Possible values include:&lt;br /&gt;
*  &amp;lt;tt&amp;gt;typed&amp;lt;/tt&amp;gt;: The document URI was typed (or pasted) by the user.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;link&amp;lt;/tt&amp;gt;: The user followed a link to the document URI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;session-history&amp;lt;/tt&amp;gt;: The user used back/forward navigation to load the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;reload&amp;lt;/tt&amp;gt;: The user used the reload button or keyboard shortcut to reload the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;global-history&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from their global history.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;bookmark&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from the bookmarks menu, bookmarks toolbar, or bookmarks management UI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;script&amp;lt;/tt&amp;gt;: A script executing on a page loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;refresh&amp;lt;/tt&amp;gt;: A meta-refresh loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;external&amp;lt;/tt&amp;gt;: The document URI was passed in from an external application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;loadtime = [milliseconds]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The time from the initiation of the load until the document is complete (which includes all images, stylesheet, etc) in milliseconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;bfCacheHit = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
Whether the document presentation was loaded from the session history cache.  If not specified, assumed to be false.&lt;br /&gt;
&lt;br /&gt;
Todo / possible todo items:&lt;br /&gt;
*  cache size before/after load&lt;br /&gt;
*  content viewer size estimate&lt;br /&gt;
*  cache hit&lt;br /&gt;
*  session history index&lt;br /&gt;
*  last visit date&lt;br /&gt;
*  tagged/bookmarked&lt;br /&gt;
&lt;br /&gt;
===UI Event===&lt;br /&gt;
&lt;br /&gt;
*  action = [click, key, drag, drop...]&lt;br /&gt;
*  target = [some kind of ID, possibly XUL name]&lt;br /&gt;
&lt;br /&gt;
===Garbage Collection===&lt;br /&gt;
&lt;br /&gt;
*  number/size of objects reachable&lt;br /&gt;
*  time spent doing garbage collection&lt;br /&gt;
&lt;br /&gt;
===Startup/Shutdown===&lt;br /&gt;
&lt;br /&gt;
*  time taken&lt;br /&gt;
&lt;br /&gt;
===Places UI Event===&lt;br /&gt;
&lt;br /&gt;
We&#039;ll have to be sure not to duplicate data here between the UI Event and the Places UI Event.  This could potentially be an extension of the regular UI Event.&lt;br /&gt;
&lt;br /&gt;
* node types expanded/clicked&lt;br /&gt;
* periods of time searched&lt;br /&gt;
&lt;br /&gt;
===Autocomplete===&lt;br /&gt;
&lt;br /&gt;
We may try to fit this into the schema of another event type.&lt;br /&gt;
&lt;br /&gt;
*  how far down the list?&lt;br /&gt;
*  match but typed anyway?&lt;br /&gt;
&lt;br /&gt;
===Open Issues===&lt;br /&gt;
&lt;br /&gt;
*  We may want to consolidate some of these events into summary statistics, to compact the amount of data we are collecting.  However, this may not be necessary since we will be able to throttle the data collection on a per event type.&lt;br /&gt;
&lt;br /&gt;
*  To allow extensions to collect data via this system, we will need to define a generic event type or a way to extend the list of predefined events.  This is TBD.&lt;br /&gt;
&lt;br /&gt;
*  The event types listed above are still in flux and may be combined or removed.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23051</id>
		<title>Browser Metrics:Data Collectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23051"/>
		<updated>2006-03-28T15:08:08Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Profile */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Data Format==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
Data will be collected as a stream of events, with the exception of a user profile that is collected once every browser session.  Each event type is represented by a particular XML element in the &amp;lt;tt&amp;gt;http://www.mozilla.org/metrics&amp;lt;/tt&amp;gt; namespace.  We will define several event types that will have predefined schemas.  We will be able to throttle data collection based on the event type, so that verbose events can be turned on and off when we want.  The tentative event types and associated schemas are listed below.  (Note: the list is still very much in flux and will likely change.)&lt;br /&gt;
&lt;br /&gt;
All event types have a &amp;lt;tt&amp;gt;time&amp;lt;/tt&amp;gt; attribute, which gives a timestamp for the event, recorded as seconds since the epoch.&lt;br /&gt;
&lt;br /&gt;
===Profile===&lt;br /&gt;
&lt;br /&gt;
The profile will be collected every browser session, to pick up changes periodically.  The profile element is a grouping element which contains a set of profile values.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
The following elements are optional children of &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;memory&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the memory configuration of the client system.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;mb = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of megabytes of system memory.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;os&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the operating system the client is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the operating system, e.g. &amp;quot;Windows&amp;quot; or &amp;quot;MacOSX&amp;quot;.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the operating system, e.g. &amp;quot;XP&amp;quot; or &amp;quot;Tiger&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;install&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the installation of Firefox the user is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;buildid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the Build ID (e.g. 20060327).&lt;br /&gt;
:; &amp;lt;tt&amp;gt;installdate = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the date the build was first run on this profile (seconds since the epoch).&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extensions&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;extension&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extension&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single extension.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;extensionid = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s id.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s version number.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugins&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugin&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the plugin.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;display&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the user&#039;s display.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;xsize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels horizontally on the display.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;ysize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels vertically on the display.&lt;br /&gt;
&lt;br /&gt;
TBD: talkback GUID&lt;br /&gt;
&lt;br /&gt;
===Window Event===&lt;br /&gt;
&lt;br /&gt;
Window events log various actions pertaining to DOM Windows, which provide a context for load events.&lt;br /&gt;
&lt;br /&gt;
Element name: &amp;lt;tt&amp;gt;window&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;action = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Indicates the action that happened for this window.  Possible values are:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;create&amp;lt;/tt&amp;gt;: a new toplevel or child DOM Window was created&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt;: a toplevel DOM Window was opened&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;close&amp;lt;/tt&amp;gt;: a toplevel DOM Window was closed&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;destroy&amp;lt;/tt&amp;gt;: a toplevel or child DOM Window was destroyed&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;windowid = [integer window id]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The id of the affected window.  Ids are assigned starting from 0 and are never reused during that session.  The window id is not unique across sessions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;parent = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For create events, the id of the parent of the newly created window.  Toplevel windows do not have a parent, so this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;chrome = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For create events, whether the new window has chrome privileges.  Defaults to false.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;opener = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For open events, the id of the opener DOM window.  Windows opened from native code may not have an opener, and this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
===Load Event===&lt;br /&gt;
&lt;br /&gt;
Load events record a document being loaded into a DOM Window.&lt;br /&gt;
&lt;br /&gt;
Element name: &amp;lt;tt&amp;gt;load&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attributes:&lt;br /&gt;
&amp;lt;tt&amp;gt;window = [integer window id]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The id of the window where the document was loaded.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;origin = [string]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
The action which initiated the load.  Possible values include:&lt;br /&gt;
*  &amp;lt;tt&amp;gt;typed&amp;lt;/tt&amp;gt;: The document URI was typed (or pasted) by the user.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;link&amp;lt;/tt&amp;gt;: The user followed a link to the document URI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;session-history&amp;lt;/tt&amp;gt;: The user used back/forward navigation to load the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;reload&amp;lt;/tt&amp;gt;: The user used the reload button or keyboard shortcut to reload the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;global-history&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from their global history.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;bookmark&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from the bookmarks menu, bookmarks toolbar, or bookmarks management UI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;script&amp;lt;/tt&amp;gt;: A script executing on a page loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;refresh&amp;lt;/tt&amp;gt;: A meta-refresh loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;external&amp;lt;/tt&amp;gt;: The document URI was passed in from an external application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;loadtime = [milliseconds]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The time from the initiation of the load until the document is complete (which includes all images, stylesheet, etc) in milliseconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;bfCacheHit = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
Whether the document presentation was loaded from the session history cache.  If not specified, assumed to be false.&lt;br /&gt;
&lt;br /&gt;
Todo / possible todo items:&lt;br /&gt;
*  cache size before/after load&lt;br /&gt;
*  content viewer size estimate&lt;br /&gt;
*  cache hit&lt;br /&gt;
*  session history index&lt;br /&gt;
*  last visit date&lt;br /&gt;
*  tagged/bookmarked&lt;br /&gt;
&lt;br /&gt;
===UI Event===&lt;br /&gt;
&lt;br /&gt;
*  action = [click, key, drag, drop...]&lt;br /&gt;
*  target = [some kind of ID, possibly XUL name]&lt;br /&gt;
&lt;br /&gt;
===Garbage Collection===&lt;br /&gt;
&lt;br /&gt;
*  number/size of objects reachable&lt;br /&gt;
*  time spent doing garbage collection&lt;br /&gt;
&lt;br /&gt;
===Startup/Shutdown===&lt;br /&gt;
&lt;br /&gt;
*  time taken&lt;br /&gt;
&lt;br /&gt;
===Places UI Event===&lt;br /&gt;
&lt;br /&gt;
We&#039;ll have to be sure not to duplicate data here between the UI Event and the Places UI Event.  This could potentially be an extension of the regular UI Event.&lt;br /&gt;
&lt;br /&gt;
* node types expanded/clicked&lt;br /&gt;
* periods of time searched&lt;br /&gt;
&lt;br /&gt;
===Autocomplete===&lt;br /&gt;
&lt;br /&gt;
We may try to fit this into the schema of another event type.&lt;br /&gt;
&lt;br /&gt;
*  how far down the list?&lt;br /&gt;
*  match but typed anyway?&lt;br /&gt;
&lt;br /&gt;
===Open Issues===&lt;br /&gt;
&lt;br /&gt;
*  We may want to consolidate some of these events into summary statistics, to compact the amount of data we are collecting.  However, this may not be necessary since we will be able to throttle the data collection on a per event type.&lt;br /&gt;
&lt;br /&gt;
*  To allow extensions to collect data via this system, we will need to define a generic event type or a way to extend the list of predefined events.  This is TBD.&lt;br /&gt;
&lt;br /&gt;
*  The event types listed above are still in flux and may be combined or removed.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23040</id>
		<title>Browser Metrics:Data Collectors</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Browser_Metrics:Data_Collectors&amp;diff=23040"/>
		<updated>2006-03-28T05:18:37Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Profile */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Data Format==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
Data will be collected as a stream of events, with the exception of a user profile that is collected once every browser session.  Each event type is represented by a particular XML element in the &amp;lt;tt&amp;gt;http://www.mozilla.org/metrics&amp;lt;/tt&amp;gt; namespace.  We will define several event types that will have predefined schemas.  We will be able to throttle data collection based on the event type, so that verbose events can be turned on and off when we want.  The tentative event types and associated schemas are listed below.  (Note: the list is still very much in flux and will likely change.)&lt;br /&gt;
&lt;br /&gt;
All event types have a &amp;lt;tt&amp;gt;time&amp;lt;/tt&amp;gt; attribute, which gives a timestamp for the event, recorded as seconds since the epoch.&lt;br /&gt;
&lt;br /&gt;
===Profile===&lt;br /&gt;
&lt;br /&gt;
The profile will be collected every browser session, to pick up changes periodically.  The profile element is a grouping element which contains a set of profile values.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
The following elements are optional children of &amp;lt;tt&amp;gt;&amp;amp;lt;profile&amp;amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;memory&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the memory configuration of the client system.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;mb = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of megabytes of system memory.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;os&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the operating system the client is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the operating system, e.g. &amp;quot;Windows&amp;quot; or &amp;quot;MacOSX&amp;quot;.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the operating system, e.g. &amp;quot;XP&amp;quot; or &amp;quot;Tiger&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;install&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the installation of Firefox the user is running.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;buildid = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the Build ID (e.g. 20060327).&lt;br /&gt;
:; &amp;lt;tt&amp;gt;installdate = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the date the build was first run on this profile (seconds since the epoch).&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extensions&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;extension&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039; none&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;extension&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Contains information about a single extension installed in the profile.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;extensionid = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s id.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the extension&#039;s version number.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;plugins&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: A container element for 1 or more &amp;lt;tt&amp;gt;plugin&amp;lt;/tt&amp;gt; elements.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;name = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the name of the plugin.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;version = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the version of the plugin.&lt;br /&gt;
&lt;br /&gt;
; Element &amp;lt;tt&amp;gt;&amp;amp;lt;display&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Describes the user&#039;s display.&lt;br /&gt;
: &#039;&#039;Attributes:&#039;&#039;&lt;br /&gt;
:; &amp;lt;tt&amp;gt;xsize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels horizontally on the display.&lt;br /&gt;
:; &amp;lt;tt&amp;gt;ysize = [integer]&amp;lt;/tt&amp;gt;&lt;br /&gt;
:: Gives the number of pixels vertically on the display.&lt;br /&gt;
&lt;br /&gt;
TBD: talkback GUID&lt;br /&gt;
&lt;br /&gt;
===Window Event===&lt;br /&gt;
&lt;br /&gt;
Window events log various actions pertaining to DOM Windows, which provide a context for load events.&lt;br /&gt;
&lt;br /&gt;
Element name: &amp;lt;tt&amp;gt;window&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attributes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;action = [string]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Indicates the action that happened for this window.  Possible values are:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;create&amp;lt;/tt&amp;gt;: a new toplevel or child DOM Window was created&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;open&amp;lt;/tt&amp;gt;: a toplevel DOM Window was opened&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;close&amp;lt;/tt&amp;gt;: a toplevel DOM Window was closed&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;tt&amp;gt;destroy&amp;lt;/tt&amp;gt;: a toplevel or child DOM Window was destroyed&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;windowid = [integer window id]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The id of the affected window.  Ids are assigned starting from 0 and are never reused during that session.  The window id is not unique across sessions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;parent = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For create events, the id of the parent of the newly created window.  Toplevel windows do not have a parent, so this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;chrome = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For create events, whether the new window has chrome privileges.  Defaults to false.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;opener = [integer window id]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
For open events, the id of the opener DOM window.  Windows opened from native code may not have an opener, and this attribute will not be set.&lt;br /&gt;
&lt;br /&gt;
===Load Event===&lt;br /&gt;
&lt;br /&gt;
Load events record a document being loaded into a DOM Window.&lt;br /&gt;
&lt;br /&gt;
Element name: &amp;lt;tt&amp;gt;load&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attributes:&lt;br /&gt;
&amp;lt;tt&amp;gt;window = [integer window id]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The id of the window where the document was loaded.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;origin = [string]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
The action which initiated the load.  Possible values include:&lt;br /&gt;
*  &amp;lt;tt&amp;gt;typed&amp;lt;/tt&amp;gt;: The document URI was typed (or pasted) by the user.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;link&amp;lt;/tt&amp;gt;: The user followed a link to the document URI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;session-history&amp;lt;/tt&amp;gt;: The user used back/forward navigation to load the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;reload&amp;lt;/tt&amp;gt;: The user used the reload button or keyboard shortcut to reload the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;global-history&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from their global history.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;bookmark&amp;lt;/tt&amp;gt;: The user loaded the page by selecting it from the bookmarks menu, bookmarks toolbar, or bookmarks management UI.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;script&amp;lt;/tt&amp;gt;: A script executing on a page loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;refresh&amp;lt;/tt&amp;gt;: A meta-refresh loaded the document.&lt;br /&gt;
*  &amp;lt;tt&amp;gt;external&amp;lt;/tt&amp;gt;: The document URI was passed in from an external application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;loadtime = [milliseconds]&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The time from the initiation of the load until the document is complete (which includes all images, stylesheet, etc) in milliseconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;bfCacheHit = [boolean]&amp;lt;/tt&amp;gt; (optional)&lt;br /&gt;
&lt;br /&gt;
Whether the document presentation was loaded from the session history cache.  If not specified, assumed to be false.&lt;br /&gt;
&lt;br /&gt;
Todo / possible todo items:&lt;br /&gt;
*  cache size before/after load&lt;br /&gt;
*  content viewer size estimate&lt;br /&gt;
*  cache hit&lt;br /&gt;
*  session history index&lt;br /&gt;
*  last visit date&lt;br /&gt;
*  tagged/bookmarked&lt;br /&gt;
&lt;br /&gt;
===UI Event===&lt;br /&gt;
&lt;br /&gt;
*  action = [click, key, drag, drop...]&lt;br /&gt;
*  target = [some kind of ID, possibly XUL name]&lt;br /&gt;
&lt;br /&gt;
===Garbage Collection===&lt;br /&gt;
&lt;br /&gt;
*  number/size of objects reachable&lt;br /&gt;
*  time spent doing garbage collection&lt;br /&gt;
&lt;br /&gt;
===Startup/Shutdown===&lt;br /&gt;
&lt;br /&gt;
*  time taken&lt;br /&gt;
&lt;br /&gt;
===Places UI Event===&lt;br /&gt;
&lt;br /&gt;
We&#039;ll have to be sure not to duplicate data here between the UI Event and the Places UI Event.  This could potentially be an extension of the regular UI Event.&lt;br /&gt;
&lt;br /&gt;
* node types expanded/clicked&lt;br /&gt;
* periods of time searched&lt;br /&gt;
&lt;br /&gt;
===Autocomplete===&lt;br /&gt;
&lt;br /&gt;
We may try to fit this into the schema of another event type.&lt;br /&gt;
&lt;br /&gt;
*  how far down the list?&lt;br /&gt;
*  match but typed anyway?&lt;br /&gt;
&lt;br /&gt;
===Open Issues===&lt;br /&gt;
&lt;br /&gt;
*  We may want to consolidate some of these events into summary statistics, to compact the amount of data we are collecting.  However, this may not be necessary since we will be able to throttle the data collection on a per event type.&lt;br /&gt;
&lt;br /&gt;
*  To allow extensions to collect data via this system, we will need to define a generic event type or a way to extend the list of predefined events.  This is TBD.&lt;br /&gt;
&lt;br /&gt;
*  The event types listed above are still in flux and may be combined or removed.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=User:Darin&amp;diff=23033</id>
		<title>User:Darin</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=User:Darin&amp;diff=23033"/>
		<updated>2006-03-28T01:57:58Z</updated>

		<summary type="html">&lt;p&gt;Darin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Darin Fisher ==&lt;br /&gt;
&lt;br /&gt;
http://weblogs.mozillazine.org/darin/&lt;br /&gt;
&lt;br /&gt;
[mailto:darin@meer.net]&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Sheriff_Schedule&amp;diff=23032</id>
		<title>Sheriff Schedule</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Sheriff_Schedule&amp;diff=23032"/>
		<updated>2006-03-28T01:56:58Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Schedule */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Schedule =&lt;br /&gt;
{|&lt;br /&gt;
|Tuesday || 03/28/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 03/29/06 || biesi&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 03/30/06 || [[User:Darin|Darin Fisher]]&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 03/31/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 04/01/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 04/02/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 04/03/06 || stuart&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 04/04/06 || vlad&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 04/05/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 04/06/06 || bryner&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 04/07/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 04/08/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 04/09/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 04/10/06 || rob_strong&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 04/11/06 || [[User:Dbaron|David Baron]]&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 04/12/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 04/13/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 04/14/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 04/15/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 04/16/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 04/17/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Tuesday || 04/18/06 || brettw&lt;br /&gt;
|-&lt;br /&gt;
|Wednesday || 04/19/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Thursday || 04/20/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Friday || 04/21/06 || available&lt;br /&gt;
|-&lt;br /&gt;
|Saturday || 04/22/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Sunday || 04/23/06 || #developers&lt;br /&gt;
|-&lt;br /&gt;
|Monday || 04/24/06 || available&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=WeeklyUpdates/2006-03-27&amp;diff=22994</id>
		<title>WeeklyUpdates/2006-03-27</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=WeeklyUpdates/2006-03-27&amp;diff=22994"/>
		<updated>2006-03-27T21:20:44Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* In Attendance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Staff/StatusMeetings/2006-03-19|&amp;lt;&amp;lt; previous week]] | [[Staff/StatusMeetings|index]] | [[Staff/StatusMeetings/2006-04-03|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Meeting Details&#039;&#039;&#039;&lt;br /&gt;
* 1:00pm PST (21:00 GMT)&lt;br /&gt;
* Mozilla HQ, 1st floor conference table&lt;br /&gt;
* 866-432-7917 (US)&lt;br /&gt;
* 334-309-0297 (INTL)&lt;br /&gt;
* join irc.mozilla.org #staffmeeting for attendance taking&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
&lt;br /&gt;
bienvenu, blizzard, bsemdberg, darin, dmose, dveditz, hecker, justdave, justin, schrep, tim, preed, basil, rstrong, marcia, choffman, aravind, mscott, matt, karen, davel, mitchell, pav, asa, vlad, myk, dbaron, pkim, jlilly, cbeard&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Development Updates&lt;br /&gt;
# IT Updates&lt;br /&gt;
# Marketing Updates&lt;br /&gt;
# Roundtable &lt;br /&gt;
# Other Business&lt;br /&gt;
&lt;br /&gt;
= Development Updates =&lt;br /&gt;
== FF/TB 1.5.0.2/1.0.8 ==&lt;br /&gt;
&lt;br /&gt;
* 1.0.8&lt;br /&gt;
** Build&lt;br /&gt;
*** Respins for FF CJK due to {{bug|331234}} are needed.  &lt;br /&gt;
*** FF Mac l10n bits aren&#039;t available, due to a bug Preed is tracking down: {{bug|330959}}&lt;br /&gt;
*** These are behind 1.5.0.2 build tasks.&lt;br /&gt;
*** TB - Needed to be respun with the correct date problem.  Also, the Linux bits never got produced, so a respin is required.&lt;br /&gt;
*** Will build/test L10n bugs on a &amp;quot;best effort&amp;quot; basis as localizers update from the en-UB build.&lt;br /&gt;
** QA&lt;br /&gt;
*** FF L10n testing after re-spins&lt;br /&gt;
*** TB testing has not yet commensed.&lt;br /&gt;
&lt;br /&gt;
* 1.5.0.2&lt;br /&gt;
** Build&lt;br /&gt;
*** Completed the trial build for FF universal binary (UB), with the Talkback fix included.  Tested well. Ready for final build.&lt;br /&gt;
*** Need to look into FF update channel issues.&lt;br /&gt;
*** Start l10n for FF 1.5.0.2, since we&#039;ll have all the platforms&lt;br /&gt;
*** TB: Final tag set, respins, UBs worked out (possibly)&lt;br /&gt;
*** We are debating whether to ship UB for TB.  There are signifcant issues here.  One is {{bug|331511}}.&lt;br /&gt;
** QA &lt;br /&gt;
*** FF testing to be done: Smoke test UB once final build is available. Start L10n testing.  Update verification&lt;br /&gt;
*** TB testing to be done: UB testing - awaiting official binary.  Need to continue with verifications (critical and security bugs).  L10n testing&lt;br /&gt;
&lt;br /&gt;
== FF/TB 1.5.0.3 ==&lt;br /&gt;
&lt;br /&gt;
* Started triaging bugs.  This is the earliest we have started for the 1.5.0.x releases!&lt;br /&gt;
* Starting with Blocker Nominations: ~22 triaged on Fri.  26 done today.  23 still in the queue.&lt;br /&gt;
*  Hoping to start approving patches and open the 1.8.0 branch ~Wednesday.&lt;br /&gt;
&lt;br /&gt;
== FF 2.0 ==&lt;br /&gt;
* All information updated [[Firefox2|here]] &lt;br /&gt;
* A1 Has Shipped&lt;br /&gt;
** Places backend&lt;br /&gt;
** Extension blacklisting&lt;br /&gt;
** Extension dependencies&lt;br /&gt;
** Search plugin format changeover&lt;br /&gt;
** RSS content detection&lt;br /&gt;
* Planning begun for A2&lt;br /&gt;
** Intended to be feature complete &lt;br /&gt;
** Scoping of work begun&lt;br /&gt;
* &#039;&#039;&#039;action:&#039;&#039;&#039; Review [[Firefox2|Planning Docs]] and give feedback in moz.dev.apps.firefox or moz.dev.planning&lt;br /&gt;
&lt;br /&gt;
== TB 2.0 ==&lt;br /&gt;
* We are sending out Firefox developer shirts to some of the Thunderbird 1.5 contributors who didn&#039;t already receive Firefox shirts. We&#039;re almost done with the thank you letters. Many thanks to Marcia and Karen for helping to send out the thank you packages.&lt;br /&gt;
*Several of the Thunderbird 2 features are now available on the 1.8.1 branch for testing including folder views, new mail alert notifications, and folder summary tooltips.&lt;br /&gt;
* 1.5.0.2 getting close!&lt;br /&gt;
&lt;br /&gt;
== Gecko 1.9 ==&lt;br /&gt;
&lt;br /&gt;
= IT Updates =&lt;br /&gt;
&lt;br /&gt;
* Colo Progress&lt;br /&gt;
** Network design drafts complete - will have breakout session on network design&lt;br /&gt;
* Wiki &amp;amp; Firefox Flicks migrated to the LVS cluster&lt;br /&gt;
* Firewall migration&lt;br /&gt;
** More capacity - 5 minute or less outage at Meer&lt;br /&gt;
** Planned for this weekend - more info to come&lt;br /&gt;
* Newsgroups&lt;br /&gt;
** Progressing slowly with Google - have several open tickets; posting through Google Groups and Giganews should be possible (according to Google)&lt;br /&gt;
* Service Requests&lt;br /&gt;
** Just a reminder to send all service requests through bugzilla - [https://bugzilla.mozilla.org/enter_bug.cgi?product=mozilla.org&amp;amp;format=itrequest  bugzilla link]&lt;br /&gt;
* Addons2&lt;br /&gt;
&lt;br /&gt;
= Marketing Updates =&lt;br /&gt;
&lt;br /&gt;
* Firefox Flicks Ad Contest well underway&lt;br /&gt;
** ~70 submissions received so far&lt;br /&gt;
** Contest ends April 14, 2006&lt;br /&gt;
** This week, launching enhanced [http://www.FirefoxFlicks.com FirefoxFlicks.com] with capability to view and share Flicks ads. &lt;br /&gt;
** 4 Flicks ads to be screened at Vail Film Festival as part of Oscar Shorts Showcase on March 31.  &lt;br /&gt;
* Planning for Firefox 2 marketing launch beginning this week.&lt;br /&gt;
* Updates to tools and infrastructure at [http://www.SpreadFirefox.com SpreadFirefox.com] coming this Spring, to enable SFx members easier ways to plan, initiate and share community marketing projects.&lt;br /&gt;
* Mozilla will be co-hosting the 2006 XTech Conference in Amsterdam from May 16th to 19th, for more information see http://www.xtech-conference.org&lt;br /&gt;
** We will be offering scholarships for Mozilla contributors to attend.  cbeard is organizing.&lt;br /&gt;
&lt;br /&gt;
= Roundtable =&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=21843</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=21843"/>
		<updated>2006-03-16T21:18:35Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Development */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060307_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18783</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18783"/>
		<updated>2006-03-16T21:02:40Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadObserver */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    * @param recursionDepth&lt;br /&gt;
    *        Indicates the number of calls to ProcessNextEvent on the call stack&lt;br /&gt;
    *        in addition to the current call.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,&lt;br /&gt;
                           in unsigned long recursionDepth);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Better_Offline_Mode&amp;diff=21967</id>
		<title>Better Offline Mode</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Better_Offline_Mode&amp;diff=21967"/>
		<updated>2006-03-14T15:13:49Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Nice to have */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Historically, Firefox and other Mozilla-based products have not handled disconnected operation, flaky network conditions, or network configuration changes well.  Several extensions help to ease some of these problems, but it would be nice to have something built into Mozilla to better deal with these sorts of conditions.&lt;br /&gt;
&lt;br /&gt;
=== Low-hanging fruit ===&lt;br /&gt;
&lt;br /&gt;
* Do not discard cached content when we have a network connection failure. (&amp;lt;del&amp;gt;{{bug|189570}}&amp;lt;/del&amp;gt; and &amp;lt;del&amp;gt;{{bug|278007}}&amp;lt;/del&amp;gt;)&lt;br /&gt;
* Automatically reload PAC file when changing networks, or at least reload the PAC file when we encounter a network connection failure. ({{bug|243277}} and {{bug|125875}})&lt;br /&gt;
&lt;br /&gt;
=== Nice to have ===&lt;br /&gt;
&lt;br /&gt;
* Detect offline/online state changes from OS, and put browser in offline/online mode. ({{bug|76111}} and {{bug|312793}})&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Better_Offline_Mode&amp;diff=18677</id>
		<title>Better Offline Mode</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Better_Offline_Mode&amp;diff=18677"/>
		<updated>2006-03-14T15:13:11Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Low-hanging fruit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Historically, Firefox and other Mozilla-based products have not handled disconnected operation, flaky network conditions, or network configuration changes well.  Several extensions help to ease some of these problems, but it would be nice to have something built into Mozilla to better deal with these sorts of conditions.&lt;br /&gt;
&lt;br /&gt;
=== Low-hanging fruit ===&lt;br /&gt;
&lt;br /&gt;
* Do not discard cached content when we have a network connection failure. (&amp;lt;del&amp;gt;{{bug|189570}}&amp;lt;/del&amp;gt; and &amp;lt;del&amp;gt;{{bug|278007}}&amp;lt;/del&amp;gt;)&lt;br /&gt;
* Automatically reload PAC file when changing networks, or at least reload the PAC file when we encounter a network connection failure. ({{bug|243277}} and {{bug|125875}})&lt;br /&gt;
&lt;br /&gt;
=== Nice to have ===&lt;br /&gt;
&lt;br /&gt;
* Detect offline/online state changes from OS, and put browser in offline/online mode. ({{bug|76111}})&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18781</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18781"/>
		<updated>2006-03-08T01:44:05Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* darin: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;br /&gt;
&lt;br /&gt;
dbaron: Also, with the new push/popEventQueue API defined on nsIThreadInternal, it is possible to suppress event dispatch for a particular scope.  That is needed to implement synchronous XPCOM proxy calls.  I&#039;m assuming that any proper use of synchronous XPCOM proxy calls will be one that completes relatively quickly so as to negate the effects of locking up the browser.  We should probably be very careful about calling PushEventQueue on the main thread, where it would potentially disrupt the browser UI.  Native events would still be dispatched as always, but without application level events, the UI isn&#039;t very useful.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18416</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18416"/>
		<updated>2006-03-08T01:30:49Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* darin: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stall and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18410</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18410"/>
		<updated>2006-03-08T01:28:28Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Comments */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;br /&gt;
&lt;br /&gt;
=== dbaron: ===&lt;br /&gt;
So mrbkap was telling me at lunch about what&#039;s essentially the third bullet point of your comment to biesi above -- that you&#039;re making the concept of &amp;quot;modal event loop&amp;quot; even more powerful.  This actually scares me a good bit, because these modal event loops happen within another event -- an event that may have state on the stack (e.g., |this| parameters) that could be destroyed by the processing of further events, or may have posted events that rely on the event completing.  I really don&#039;t like the mix of programming models here that makes it very hard to write robust code, and I wish we could avoid this whole concept altogether rather than making it even more powerful, and thus more dangerous.  We already have crashes where frame trees get destroyed while processing an event that are related to the Windows API&#039;s way of doing the same thing, though (for, e.g., a DestroyWindow call or whatever it&#039;s called).&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
Yup, I&#039;m aware of that issue.  In fact, the problem already exists today.  There are some places in the code where WaitPLEvent + HandleEvent are called in a loop waiting for an event to process.  That bypasses PL_ProcessPendingEvents recursion restriction.  PopThreadEventQueue does not behave as you would expect either.  It can cause ProcessPendingEvents to run for all but the PLEventQueue that is the subject of the current call to PL_ProcessPendingEvents on the stack.  That defeats the purpose of the nested event queue in the first place.&lt;br /&gt;
&lt;br /&gt;
The problem you describe with layout events also occurs for nsIStreamListener implementations.  It would be really wierd if OnDataAvailable were called recursively, or if OnDataAvailable were called while the consumer is calling nsIChannel::AsyncOpen.  These specific problems are dealt with in nsBaseChannel.cpp by temporarily suspending the channel during callbacks.  That suppresses recusive stream listener calls.&lt;br /&gt;
&lt;br /&gt;
Do you have a suggestion that would allow us to prevent this problem?  Is there a better way to make XMLHttpRequest.send, document.load, window.alert, etc. appear modal to the calling Javascript?&lt;br /&gt;
&lt;br /&gt;
For C++ consumers, we&#039;d have to basically eliminate modal dialogs altogether to avoid this problem.  Today, we have bugs where downloads stale and get disconnected all because the browser popped up a modal dialog and the dialog was not closed promptly enough by the user.  That&#039;s just unacceptable.  And, nsIPromptService is frozen.&lt;br /&gt;
&lt;br /&gt;
I think the answer is to be careful about making callbacks across XPCOM boundaries where event queues may be pumped.  Maybe the layout code needs to unwind the stack more before allowing such callbacks to happen so that it can be sure that event processing won&#039;t be the end of the world.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18355</id>
		<title>Firefox2/StatusMeetings/2006-03-07</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18355"/>
		<updated>2006-03-07T18:35:36Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Instrumentation / Exit Surveys */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-28|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-14|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
jhughes&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;now on trunk, ready for branch?&#039;&#039;&lt;br /&gt;
** &#039;&#039;estimated time remaining for A1 readiness&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039; pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed and landed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;landed, no regressions&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has. (cbeard: we can do better! ;-) perhaps we can license or buy dictionaries and release under a compatible license? rebron is going to dive into this.  we should continue on the current path regardless.)&lt;br /&gt;
** &#039;&#039;enable this on branch by default? where do we package the dictionary file?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;landed on trunk?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** SAX parser [https://bugzilla.mozilla.org/show_bug.cgi?id=315826 bug 315826] and dependencies finally got reviewed. Documented and almost ready to land. [https://bugzilla.mozilla.org/show_bug.cgi?id=325080 bug 325080] contains working RSS2/RSS1 parser w/ some Atom support. Need to cover more pathological cases and finish Atom. [-RS]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;has this landed for branch?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release Issues &amp;amp; Timing ==&lt;br /&gt;
* version number for A1 will be 2.0a1, trunk will be 3.0a1 (see [http://forums.mozillazine.org/viewtopic.php?t=388559 MZ forums post by mscott])&lt;br /&gt;
* still have to make the patch to rename trunk/branch&lt;br /&gt;
** trunk will become browser/3.0a1, 1.8_BRANCH will become Bon Echo/2.0a1&lt;br /&gt;
* plan is to promote this as developer only release, low-key announce&lt;br /&gt;
* &#039;&#039;any updates from QA/Software Update questions raised last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
* Brett: have seen no new data loss bugs since re-turning on. Startup and PLT are reasonable.&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* started [http://groups.google.com/group/mozilla.dev.themes/browse_frm/thread/32c6e0c4fbc03fa5/1574dfb465b7fe8a#1574dfb465b7fe8a discussion in moz.dev.themes] about new theme for Firefox2; surprisingly low response!&lt;br /&gt;
* the Chrome changes UI thread in dev.apps.firefox seems to have wound down, will consolidate feedback and review later today and post back on that thread&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
* &#039;&#039;anything new from last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
* we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** rebron will explore the possibilities, cbeard has suggested that we could look to either license or buy dictionaries for inclusion or release under compatible licenses.&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* working on getting machines for server&lt;br /&gt;
* lots of progress on server side code&lt;br /&gt;
* working on finishing client side tasks&lt;br /&gt;
* exit survey web app {{bug|322884}} is still not live.  need to poke morgamic.&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* Patch almost ready, testing now.&lt;br /&gt;
* No other news.&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* Still a todo item for Darin.  We don&#039;t need to do anything special for FF 2.0a1, but it would be nice to get the nightly update channel working again.  Preed says it is &amp;quot;midway on the list.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* biesi&#039;s generic content sniffing patch landed on the MOZILLA_1_8_BRANCH.&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* Fixed a regression&lt;br /&gt;
* Roc has a patch to observe OS network state on linux.  A similar patch exists in bugzilla for windows.  Might be worth it to get some of this into FF2.&lt;br /&gt;
* Other work remaining: refresh PAC automatically&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* [https://bugzilla.mozilla.org/show_bug.cgi?id=329292 bug 329292] filed to track the landing of Google&#039;s &amp;quot;Safe Browsing&amp;quot; code on branch&lt;br /&gt;
** to-dos include: opening up to other data providers, anonymizing data stream, creating generic API for other Mozilla products to use, renaming to &amp;quot;anti-phishing&amp;quot; (see [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c26 comment 26] and [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c28 comment 28])&lt;br /&gt;
* Sherman Dickman to take over this bit from cbeard, and investigate heuristic mechanisms as well as integration of this code from Google&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* &#039;&#039;any updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* &#039;&#039;any other business?&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18352</id>
		<title>Firefox2/StatusMeetings/2006-03-07</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18352"/>
		<updated>2006-03-07T18:32:09Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* RSS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-28|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-14|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
jhughes&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;now on trunk, ready for branch?&#039;&#039;&lt;br /&gt;
** &#039;&#039;estimated time remaining for A1 readiness&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039; pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed and landed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;landed, no regressions&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has. (cbeard: we can do better! ;-) perhaps we can license or buy dictionaries and release under a compatible license? rebron is going to dive into this.  we should continue on the current path regardless.)&lt;br /&gt;
** &#039;&#039;enable this on branch by default? where do we package the dictionary file?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;landed on trunk?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** SAX parser [https://bugzilla.mozilla.org/show_bug.cgi?id=315826 bug 315826] and dependencies finally got reviewed. Documented and almost ready to land. [https://bugzilla.mozilla.org/show_bug.cgi?id=325080 bug 325080] contains working RSS2/RSS1 parser w/ some Atom support. Need to cover more pathological cases and finish Atom. [-RS]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;has this landed for branch?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release Issues &amp;amp; Timing ==&lt;br /&gt;
* version number for A1 will be 2.0a1, trunk will be 3.0a1 (see [http://forums.mozillazine.org/viewtopic.php?t=388559 MZ forums post by mscott])&lt;br /&gt;
* still have to make the patch to rename trunk/branch&lt;br /&gt;
** trunk will become browser/3.0a1, 1.8_BRANCH will become Bon Echo/2.0a1&lt;br /&gt;
* plan is to promote this as developer only release, low-key announce&lt;br /&gt;
* &#039;&#039;any updates from QA/Software Update questions raised last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
* Brett: have seen no new data loss bugs since re-turning on. Startup and PLT are reasonable.&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* started [http://groups.google.com/group/mozilla.dev.themes/browse_frm/thread/32c6e0c4fbc03fa5/1574dfb465b7fe8a#1574dfb465b7fe8a discussion in moz.dev.themes] about new theme for Firefox2; surprisingly low response!&lt;br /&gt;
* the Chrome changes UI thread in dev.apps.firefox seems to have wound down, will consolidate feedback and review later today and post back on that thread&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
* &#039;&#039;anything new from last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
* we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** need to come up with a strategy for handling this issue&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* working on getting machines for server&lt;br /&gt;
* lots of progress on server side code&lt;br /&gt;
* working on finishing client side tasks&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* Patch almost ready, testing now.&lt;br /&gt;
* No other news.&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* Still a todo item for Darin.  We don&#039;t need to do anything special for FF 2.0a1, but it would be nice to get the nightly update channel working again.  Preed says it is &amp;quot;midway on the list.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* biesi&#039;s generic content sniffing patch landed on the MOZILLA_1_8_BRANCH.&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* Fixed a regression&lt;br /&gt;
* Roc has a patch to observe OS network state on linux.  A similar patch exists in bugzilla for windows.  Might be worth it to get some of this into FF2.&lt;br /&gt;
* Other work remaining: refresh PAC automatically&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* [https://bugzilla.mozilla.org/show_bug.cgi?id=329292 bug 329292] filed to track the landing of Google&#039;s &amp;quot;Safe Browsing&amp;quot; code on branch&lt;br /&gt;
** to-dos include: opening up to other data providers, anonymizing data stream, creating generic API for other Mozilla products to use, renaming to &amp;quot;anti-phishing&amp;quot; (see [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c26 comment 26] and [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c28 comment 28])&lt;br /&gt;
* Sherman Dickman to take over this bit from cbeard, and investigate heuristic mechanisms as well as integration of this code from Google&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* &#039;&#039;any updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* &#039;&#039;any other business?&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18350</id>
		<title>Firefox2/StatusMeetings/2006-03-07</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18350"/>
		<updated>2006-03-07T18:30:37Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Branding &amp;amp; Update Systems */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-28|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-14|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
jhughes&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;now on trunk, ready for branch?&#039;&#039;&lt;br /&gt;
** &#039;&#039;estimated time remaining for A1 readiness&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039; pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed and landed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;landed, no regressions&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** &#039;&#039;enable this on branch by default? where do we package the dictionary file?&#039;&#039;&lt;br /&gt;
** (cbeard: we can do better, perhaps we can license or buy dictionaries and release under a compatible license? rebron is going to dive into this.  we should continue on the current path regardless.)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;landed on trunk?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** SAX parser [https://bugzilla.mozilla.org/show_bug.cgi?id=315826 bug 315826] and dependencies finally got reviewed. Documented and almost ready to land. [https://bugzilla.mozilla.org/show_bug.cgi?id=325080 bug 325080] contains working RSS2/RSS1 parser w/ some Atom support. Need to cover more pathological cases and finish Atom. [-RS]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;has this landed for branch?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release Issues &amp;amp; Timing ==&lt;br /&gt;
* version number for A1 will be 2.0a1, trunk will be 3.0a1 (see [http://forums.mozillazine.org/viewtopic.php?t=388559 MZ forums post by mscott])&lt;br /&gt;
* still have to make the patch to rename trunk/branch&lt;br /&gt;
** trunk will become browser/3.0a1, 1.8_BRANCH will become Bon Echo/2.0a1&lt;br /&gt;
* plan is to promote this as developer only release, low-key announce&lt;br /&gt;
* &#039;&#039;any updates from QA/Software Update questions raised last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
* Brett: have seen no new data loss bugs since re-turning on. Startup and PLT are reasonable.&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* started [http://groups.google.com/group/mozilla.dev.themes/browse_frm/thread/32c6e0c4fbc03fa5/1574dfb465b7fe8a#1574dfb465b7fe8a discussion in moz.dev.themes] about new theme for Firefox2; surprisingly low response!&lt;br /&gt;
* the Chrome changes UI thread in dev.apps.firefox seems to have wound down, will consolidate feedback and review later today and post back on that thread&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
* &#039;&#039;anything new from last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
* we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** need to come up with a strategy for handling this issue&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* working on getting machines for server&lt;br /&gt;
* lots of progress on server side code&lt;br /&gt;
* working on finishing client side tasks&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* Patch almost ready, testing now.&lt;br /&gt;
* No other news.&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* Still a todo item for Darin.  We don&#039;t need to do anything special for FF 2.0a1, but it would be nice to get the nightly update channel working again.  Preed says it is &amp;quot;midway on the list.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* Fixed a regression&lt;br /&gt;
* Roc has a patch to observe OS network state on linux.  A similar patch exists in bugzilla for windows.  Might be worth it to get some of this into FF2.&lt;br /&gt;
* Other work remaining: refresh PAC automatically&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* [https://bugzilla.mozilla.org/show_bug.cgi?id=329292 bug 329292] filed to track the landing of Google&#039;s &amp;quot;Safe Browsing&amp;quot; code on branch&lt;br /&gt;
** to-dos include: opening up to other data providers, anonymizing data stream, creating generic API for other Mozilla products to use, renaming to &amp;quot;anti-phishing&amp;quot; (see [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c26 comment 26] and [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c28 comment 28])&lt;br /&gt;
* Sherman Dickman to take over this bit from cbeard, and investigate heuristic mechanisms as well as integration of this code from Google&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* &#039;&#039;any updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* &#039;&#039;any other business?&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18349</id>
		<title>Firefox2/StatusMeetings/2006-03-07</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18349"/>
		<updated>2006-03-07T18:27:14Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Offline mode / better use of cache */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-28|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-14|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
jhughes&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;now on trunk, ready for branch?&#039;&#039;&lt;br /&gt;
** &#039;&#039;estimated time remaining for A1 readiness&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039; pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed and landed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;landed, no regressions&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** &#039;&#039;enable this on branch by default? where do we package the dictionary file?&#039;&#039;&lt;br /&gt;
** (cbeard: we can do better, perhaps we can license or buy dictionaries and release under a compatible license? rebron is going to dive into this.  we should continue on the current path regardless.)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;landed on trunk?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** SAX parser [https://bugzilla.mozilla.org/show_bug.cgi?id=315826 bug 315826] and dependencies finally got reviewed. Documented and almost ready to land. [https://bugzilla.mozilla.org/show_bug.cgi?id=325080 bug 325080] contains working RSS2/RSS1 parser w/ some Atom support. Need to cover more pathological cases and finish Atom. [-RS]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;has this landed for branch?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release Issues &amp;amp; Timing ==&lt;br /&gt;
* version number for A1 will be 2.0a1, trunk will be 3.0a1 (see [http://forums.mozillazine.org/viewtopic.php?t=388559 MZ forums post by mscott])&lt;br /&gt;
* still have to make the patch to rename trunk/branch&lt;br /&gt;
** trunk will become browser/3.0a1, 1.8_BRANCH will become Bon Echo/2.0a1&lt;br /&gt;
* plan is to promote this as developer only release, low-key announce&lt;br /&gt;
* &#039;&#039;any updates from QA/Software Update questions raised last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
* Brett: have seen no new data loss bugs since re-turning on. Startup and PLT are reasonable.&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* started [http://groups.google.com/group/mozilla.dev.themes/browse_frm/thread/32c6e0c4fbc03fa5/1574dfb465b7fe8a#1574dfb465b7fe8a discussion in moz.dev.themes] about new theme for Firefox2; surprisingly low response!&lt;br /&gt;
* the Chrome changes UI thread in dev.apps.firefox seems to have wound down, will consolidate feedback and review later today and post back on that thread&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
* &#039;&#039;anything new from last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
* we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** need to come up with a strategy for handling this issue&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* working on getting machines for server&lt;br /&gt;
* lots of progress on server side code&lt;br /&gt;
* working on finishing client side tasks&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* Patch almost ready, testing now.&lt;br /&gt;
* No other news.&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* Fixed a regression&lt;br /&gt;
* Roc has a patch to observe OS network state on linux.  A similar patch exists in bugzilla for windows.  Might be worth it to get some of this into FF2.&lt;br /&gt;
* Other work remaining: refresh PAC automatically&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* [https://bugzilla.mozilla.org/show_bug.cgi?id=329292 bug 329292] filed to track the landing of Google&#039;s &amp;quot;Safe Browsing&amp;quot; code on branch&lt;br /&gt;
** to-dos include: opening up to other data providers, anonymizing data stream, creating generic API for other Mozilla products to use, renaming to &amp;quot;anti-phishing&amp;quot; (see [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c26 comment 26] and [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c28 comment 28])&lt;br /&gt;
* Sherman Dickman to take over this bit from cbeard, and investigate heuristic mechanisms as well as integration of this code from Google&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* &#039;&#039;any updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* &#039;&#039;any other business?&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18348</id>
		<title>Firefox2/StatusMeetings/2006-03-07</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-03-07&amp;diff=18348"/>
		<updated>2006-03-07T18:25:30Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Instrumentation / Exit Surveys */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-28|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-14|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
jhughes&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;now on trunk, ready for branch?&#039;&#039;&lt;br /&gt;
** &#039;&#039;estimated time remaining for A1 readiness&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039; pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;pushed to A2?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed and landed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;landed, no regressions&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;patch reviewed?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** &#039;&#039;enable this on branch by default? where do we package the dictionary file?&#039;&#039;&lt;br /&gt;
** (cbeard: we can do better, perhaps we can license or buy dictionaries and release under a compatible license? rebron is going to dive into this.  we should continue on the current path regardless.)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;landed on trunk?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** SAX parser [https://bugzilla.mozilla.org/show_bug.cgi?id=315826 bug 315826] and dependencies finally got reviewed. Documented and almost ready to land. [https://bugzilla.mozilla.org/show_bug.cgi?id=325080 bug 325080] contains working RSS2/RSS1 parser w/ some Atom support. Need to cover more pathological cases and finish Atom. [-RS]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;has this landed for branch?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release Issues &amp;amp; Timing ==&lt;br /&gt;
* version number for A1 will be 2.0a1, trunk will be 3.0a1 (see [http://forums.mozillazine.org/viewtopic.php?t=388559 MZ forums post by mscott])&lt;br /&gt;
* still have to make the patch to rename trunk/branch&lt;br /&gt;
** trunk will become browser/3.0a1, 1.8_BRANCH will become Bon Echo/2.0a1&lt;br /&gt;
* plan is to promote this as developer only release, low-key announce&lt;br /&gt;
* &#039;&#039;any updates from QA/Software Update questions raised last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
* Brett: have seen no new data loss bugs since re-turning on. Startup and PLT are reasonable.&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* started [http://groups.google.com/group/mozilla.dev.themes/browse_frm/thread/32c6e0c4fbc03fa5/1574dfb465b7fe8a#1574dfb465b7fe8a discussion in moz.dev.themes] about new theme for Firefox2; surprisingly low response!&lt;br /&gt;
* the Chrome changes UI thread in dev.apps.firefox seems to have wound down, will consolidate feedback and review later today and post back on that thread&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
* &#039;&#039;anything new from last week?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
* we are clear to ship en-US with the product&lt;br /&gt;
** all other dictionaries must be downloaded explicitly as XPIs, mscott maintains a [http://www.mozilla.com/thunderbird/dictionaries.html list of these extensions]; these are the same dictionaries/problems that OpenOffice has.&lt;br /&gt;
** need to come up with a strategy for handling this issue&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* working on getting machines for server&lt;br /&gt;
* lots of progress on server side code&lt;br /&gt;
* working on finishing client side tasks&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* Patch almost ready, testing now.&lt;br /&gt;
* No other news.&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* &#039;&#039;any other updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* [https://bugzilla.mozilla.org/show_bug.cgi?id=329292 bug 329292] filed to track the landing of Google&#039;s &amp;quot;Safe Browsing&amp;quot; code on branch&lt;br /&gt;
** to-dos include: opening up to other data providers, anonymizing data stream, creating generic API for other Mozilla products to use, renaming to &amp;quot;anti-phishing&amp;quot; (see [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c26 comment 26] and [https://bugzilla.mozilla.org/show_bug.cgi?id=329292#c28 comment 28])&lt;br /&gt;
* Sherman Dickman to take over this bit from cbeard, and investigate heuristic mechanisms as well as integration of this code from Google&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* &#039;&#039;any updates?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* &#039;&#039;any other business?&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18404</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18404"/>
		<updated>2006-03-04T00:49:55Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Remarks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: &amp;lt;code&amp;gt;nsIEventQueue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventQueueService&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nsIThread&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLEvent&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18199</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18199"/>
		<updated>2006-03-04T00:47:44Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadObserver */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadEventFilter ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadEventFilter : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called to determine whether or not an event may be accepted&lt;br /&gt;
    * by a &amp;quot;nested&amp;quot; event queue (see nsIThreadInternal::PushEventQueue).&lt;br /&gt;
    *&lt;br /&gt;
    * WARNING: This method must not make any calls on the thread object.&lt;br /&gt;
    */&lt;br /&gt;
   [notxpcom] boolean AcceptEvent(in nsIRunnable event);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18198</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18198"/>
		<updated>2006-03-04T00:46:58Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadObserver */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called after an event has been dispatched to the thread.&lt;br /&gt;
    * This method may be called from any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchedEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method is called (from nsIThread::ProcessNextEvent) before an event&lt;br /&gt;
    * is processed.  This method is only called on the target thread.&lt;br /&gt;
    *&lt;br /&gt;
    * @param thread&lt;br /&gt;
    *        The thread being asked to process another event.&lt;br /&gt;
    * @param mayWait&lt;br /&gt;
    *        Indicates whether or not the method is allowed to block the calling&lt;br /&gt;
    *        thread.  For example, this parameter is false during thread shutdown.&lt;br /&gt;
    */&lt;br /&gt;
   void onProcessNextEvent(in nsIThreadInternal thread,&lt;br /&gt;
                           in boolean mayWait);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18197</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18197"/>
		<updated>2006-03-04T00:45:18Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadInternal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread (may be null).  This attribute may&lt;br /&gt;
    * be read from any thread, but must only be set on the thread corresponding&lt;br /&gt;
    * to this thread object.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18196</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18196"/>
		<updated>2006-03-04T00:44:09Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadInternal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18195</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18195"/>
		<updated>2006-03-04T00:43:13Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadInternal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This method causes any events currently enqueued on the thread to be&lt;br /&gt;
    * suppressed until PopEventQueue is called.  Additionally, any new events&lt;br /&gt;
    * dispatched to the thread will only be processed if they are accepted by&lt;br /&gt;
    * the given filter.  If the filter is null, then new events are accepted.&lt;br /&gt;
    * Calls to PushEventQueue may be nested and must each be paired with a call&lt;br /&gt;
    * to PopEventQueue in order to restore the original state of the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void pushEventQueue(in nsIThreadEventFilter filter);&lt;br /&gt;
                                                                                                                                                                         &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Revert a call to PushEventQueue.  When an event queue is popped, any&lt;br /&gt;
    * events remaining in the queue are appended to the elder queue.&lt;br /&gt;
    */&lt;br /&gt;
   void popEventQueue();&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18194</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18194"/>
		<updated>2006-03-04T00:40:41Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* nsIThreadManager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18193</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18193"/>
		<updated>2006-03-01T19:27:05Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Set an external nsIThread instance (or null) as the nsIThread for the&lt;br /&gt;
    * current thread.  If a nsIThread is already associated with the calling&lt;br /&gt;
    * thread, then this function will replace it with the given nsIThread.  If&lt;br /&gt;
    * the given nsIThread is non-null, then its name attribute must be unique.&lt;br /&gt;
    * Its name may be equal to the name of the nsIThread being replaced.  This&lt;br /&gt;
    * method returns the nsIThread that was replaced by this method call or null&lt;br /&gt;
    * if there was no previous nsIThread associated with the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread setCurrentThread(in nsIThread thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18006</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18006"/>
		<updated>2006-03-01T19:14:03Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Set an external nsIThread instance (or null) as the nsIThread for the&lt;br /&gt;
    * current thread.  If a nsIThread is already associated with the calling&lt;br /&gt;
    * thread, then this function will replace it with the given nsIThread.  If&lt;br /&gt;
    * the given nsIThread is non-null, then its name attribute must be unique.&lt;br /&gt;
    * Its name may be equal to the name of the nsIThread being replaced.  This&lt;br /&gt;
    * method returns the nsIThread that was replaced by this method call or null&lt;br /&gt;
    * if there was no previous nsIThread associated with the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread setCurrentThread(in nsIThread thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Process all pending events for the given thread before returning.  This&lt;br /&gt;
  * method simply calls ProcessNextEvent on the thread while HasPendingEvents&lt;br /&gt;
  * continues to return true and the time spent in NS_ProcessPendingEvents&lt;br /&gt;
  * does not exceed the given timeout value.&lt;br /&gt;
  *&lt;br /&gt;
  * @param thread&lt;br /&gt;
  *        The thread object for which to process pending events.  If null,&lt;br /&gt;
  *        then events will be processed for the current thread.&lt;br /&gt;
  * @param timeout&lt;br /&gt;
  *        The maximum number of milliseconds to spend processing pending&lt;br /&gt;
  *        events.  Events are not pre-empted to honor this timeout.  Rather,&lt;br /&gt;
  *        the timeout value is simply used to determine whether or not to&lt;br /&gt;
  *        process another event.  Pass PR_INTERVAL_NO_TIMEOUT to specify no&lt;br /&gt;
  *        timeout.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_ProcessPendingEvents(nsIThread *thread = nsnull,&lt;br /&gt;
                                   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18005</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18005"/>
		<updated>2006-03-01T19:04:07Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Set an external nsIThread instance (or null) as the nsIThread for the&lt;br /&gt;
    * current thread.  If a nsIThread is already associated with the calling&lt;br /&gt;
    * thread, then this function will replace it with the given nsIThread.  If&lt;br /&gt;
    * the given nsIThread is non-null, then its name attribute must be unique.&lt;br /&gt;
    * Its name may be equal to the name of the nsIThread being replaced.  This&lt;br /&gt;
    * method returns the nsIThread that was replaced by this method call or null&lt;br /&gt;
    * if there was no previous nsIThread associated with the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread setCurrentThread(in nsIThread thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToCurrentThread(nsIRunnable *event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Dispatch the given event to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The event to dispatch.&lt;br /&gt;
  * @param dispatchFlags&lt;br /&gt;
  *        The flags to pass to the main thread&#039;s dispatch method.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_DispatchToMainThread(nsIRunnable *event,&lt;br /&gt;
                                   PRUint32 dispatchFlags = NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18004</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18004"/>
		<updated>2006-03-01T19:01:31Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Set an external nsIThread instance (or null) as the nsIThread for the&lt;br /&gt;
    * current thread.  If a nsIThread is already associated with the calling&lt;br /&gt;
    * thread, then this function will replace it with the given nsIThread.  If&lt;br /&gt;
    * the given nsIThread is non-null, then its name attribute must be unique.&lt;br /&gt;
    * Its name may be equal to the name of the nsIThread being replaced.  This&lt;br /&gt;
    * method returns the nsIThread that was replaced by this method call or null&lt;br /&gt;
    * if there was no previous nsIThread associated with the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread setCurrentThread(in nsIThread thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * Create a new thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the thread (must be unique) or the empty string to&lt;br /&gt;
  *        create an anonymous thread.&lt;br /&gt;
  * @param event&lt;br /&gt;
  *        The initial event to run on this thread.  This can be null.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the current thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Get a reference to the thread with the given name.&lt;br /&gt;
  *&lt;br /&gt;
  * @param name&lt;br /&gt;
  *        The name of the requested thread.  Must be non-empty.&lt;br /&gt;
  * @param result&lt;br /&gt;
  *        The resulting nsIThread object.&lt;br /&gt;
  */&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 /**&lt;br /&gt;
  * Test to see if the current thread is the main thread.&lt;br /&gt;
  *&lt;br /&gt;
  * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE&lt;br /&gt;
  * otherwise.&lt;br /&gt;
  */&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17969</id>
		<title>Firefox2/StatusMeetings/2006-02-28</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17969"/>
		<updated>2006-03-01T04:51:32Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Features */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-21|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-07|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
brettw, linus, annie, darin, ben, jhughes, brakowski, timr, rob_strong, dveditz, rebron, Axel, gavin_, autonome, bsmedberg, markp, mconnor&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** performance (Tp, Ts) has gotten better, close to status quo if not better&lt;br /&gt;
** problems with memory leak on balsa that we&#039;re trying to track down; this is blocking us as we can&#039;t turn it on. We&#039;re not sure that this is even Places that&#039;s doing it.&lt;br /&gt;
*** dveditz: the whole point of &amp;quot;WARN_IF_FALSE&amp;quot; was to warn instead of fail on an assertion.&lt;br /&gt;
*** darin: I&#039;m gonna rack that up to maybe a typo in nsDebug.h?&lt;br /&gt;
*** ben: maybe we can flip places on?&lt;br /&gt;
*** beltzner: will post to devnews tonight, then flip it on for Weds morning&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** at a hard decision about what approach to take&lt;br /&gt;
*** either hide-the-tab, try to leverage bfcache, or just try to preserve form data retention&lt;br /&gt;
** will be able to get it ready for A1 based on one of these directions, assuming we still want to&lt;br /&gt;
*** beltzner: I think we should get at least one of these directions in place&lt;br /&gt;
** darin: why would we use bfcache?&lt;br /&gt;
** bsmedberg: it might help persist full state while not allowing plugins and media to run in the background (which would happen with hide-the-tab)&lt;br /&gt;
** darin: need to be careful about &amp;lt;code&amp;gt;onunload&amp;lt;/code&amp;gt; handlers and other things that disable bfcache&lt;br /&gt;
** mconnor: if I can&#039;t figure out a way to make it work consistently, we might want to push this off to A2 or even extension-land&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** patch waiting for review&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** landed, no regressions&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** review going well, working through Ben&#039;s comments&lt;br /&gt;
** not going to move to toolkit based on feedback in d-a-f&lt;br /&gt;
** looking to have a new patch for review soon (today/tomorrow)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** it&#039;s on trunk already (without the dictionary) --enable-extension: spellcheck? there are instructions in the enable spell check bug&lt;br /&gt;
** still blocked on licensing, who do I talk to about this? mscott for starters.&lt;br /&gt;
** ben: where does the dictionary file? what needs to happen with the build system to get it included?&lt;br /&gt;
** bsmedberg: point me to that please and we can get this started&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** good progress on getting server infrastructure up and running&lt;br /&gt;
** should move this off to A2&lt;br /&gt;
** the exit survey will be in place for Firefox 1.5.0.2, morgamic is doing the final bits of work for the web app&lt;br /&gt;
*** also thinking about entrance survey&lt;br /&gt;
*** action &#039;&#039;&#039;beltzner&#039;&#039;&#039; cc darin on bug 314119&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** ben needs to check in with robert, think it&#039;s stuck waiting for a review&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** we &#039;&#039;think&#039;&#039; we&#039;re good here; not in darin&#039;s review queue anymore, at any rate&lt;br /&gt;
&lt;br /&gt;
== Blockers ==&lt;br /&gt;
* version number / branding&lt;br /&gt;
** currently set at 1.5, should it be 2.0a1?&lt;br /&gt;
** benjamin: yes, that&#039;s what mscott&#039;s doing&lt;br /&gt;
** dveditz: should we also change the trunk, which is currently 1.6a1?&lt;br /&gt;
** benjamin: mscott has all of these under proposal&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; beltzner to take this as an action&lt;br /&gt;
* davel: when we push 2.0a1 to the beta-update channel, will these users get a choice?&lt;br /&gt;
** darin: yes, if we set something as a &amp;quot;major&amp;quot; release, they&#039;ll get a choice&lt;br /&gt;
** bsmedberg: it would be a good idea to test this code path on the nightly?&lt;br /&gt;
** annie: I think there&#039;s a lot of users who don&#039;t realize that they&#039;re on a beta channel right now, so we shouldn&#039;t be pushing the alpha onto the 1.5 beta channel&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; for darin to synch up with preed(?) to make sure that everyone&#039;s up to speed&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; for QA to test the 1.5.x update logic for user choice&lt;br /&gt;
* ben: release notes? documentation for MDC?&lt;br /&gt;
** promote it as a developer release&lt;br /&gt;
** mconnor: do we even want to promote it as that? some of these APIs are going to change?&lt;br /&gt;
** beltzner: but we want that feedback, don&#039;t we?&lt;br /&gt;
** mconnor: I&#039;m worried about getting dugg, and getting bug feedback that we don&#039;t really care about anyway&lt;br /&gt;
** ben: maybe do it invite only?&lt;br /&gt;
** mconnor: get the release download numbers from Asa&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
* performance was good, no known data corruption issues&lt;br /&gt;
* annie&#039;s prepared some solid estimates, I need to do that and get it from the rest of the team&lt;br /&gt;
* &#039;&#039;&#039;action&#039;&#039;&#039; ben to meet with schrep next monday&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* nothing beyond what&#039;s been discussed&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* Extension Dependencies - phase 1 landed - no regressions so far&lt;br /&gt;
* Extension Blacklisting - patch ready for review last Friday&lt;br /&gt;
* Extension Locales - started&lt;br /&gt;
* Extension UI - mockups and proof of concept started&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* Windows Installer - nothing new other than work on this will start again this week&lt;br /&gt;
** bsmedberg: is DOM Inspector part of the product or not?&lt;br /&gt;
** first requirement is to be able to provide variable paths for distribution and packaging of our installer&lt;br /&gt;
** now we&#039;re starting to talk about creating various levels of stub install: stub with full code, stub with all code but not optional code, stub with no code.&lt;br /&gt;
*** bsmedberg: but do we consider DOM inspector part of the application or not?&lt;br /&gt;
*** rob_strong: put it on AMO?&lt;br /&gt;
*** beltzner: we need to figure out a way to make sure that it&#039;s there for users who need it, but not there for users who aren&#039;t there&lt;br /&gt;
* Branding and Locale installer customization - nothing new&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
*Back end work complete&lt;br /&gt;
*Updated patch today or tomorrow - needs review from mconnor&lt;br /&gt;
**Addressed ben&#039;s SR comments&lt;br /&gt;
*Code to remain in /browser per discussion on dev.apps.firefox&lt;br /&gt;
*Re-factoring of the Sherlock parsing code to be completed seperately if time permits (low priority)&lt;br /&gt;
*Need to discuss search plugin format further&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* requirements for the visual refresh are [[FX2_Visual_Update|on the wiki]]&lt;br /&gt;
** will be creating a new space for discussion of this theme (dev.apps.firefox.newtheme) and trying to figure out some place to provide hosting for mockups and images &lt;br /&gt;
* met with ben and jhughes yesterday to discuss changes to the default chrome for the browser window, the outcome of which was posted to [http://groups.google.com/group/mozilla.dev.apps.firefox dev.apps.firefox]&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
&lt;br /&gt;
* SVG textPath needs to get an answer and attention in the next 2 weeks, thus I make a commitment here that I will produce a landing scenario for them by March 10.&lt;br /&gt;
&lt;br /&gt;
* no new status on UTF-16 XPCOM I/O fixes.&lt;br /&gt;
&lt;br /&gt;
* schedule for platform uplift deadlines no longer clear due to schedule strategy shift; will try to build something new there for next week.&lt;br /&gt;
&lt;br /&gt;
* need to produce a plan for tracking 1.8.1 approval queues and setting expectations there appropriately.&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
Waiting for clarification on licensing.&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* Mostly working on server backend.  Not much new status to report.&lt;br /&gt;
* {{bug|189570}} is fixed on the trunk.&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
* SessionStore service mostly working in Bon Echo&lt;br /&gt;
* Currently pulling from cache or reloading, not dump/restoring DOM&lt;br /&gt;
* This week: define and document API, finish code review and post patch&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* need to check in with robert sayre&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* patch is in, waiting for branch approval&lt;br /&gt;
* continuing to investigate low hanging fruit&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* fritz, darin, neils, mmc and brakowski meeting this afternoon to talk about ways of bundling/integrating Google phishing protector&lt;br /&gt;
* also investigating heuristic-based approaches and UI rendering for warnings about phishing&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* schrep&#039;s out of town, but is still planning to kick off a meeting on collecting better performance data on daily builds to continually monitor this issue&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* annie: maybe use Google&#039;s QA to help us here&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; annie and timr to talk about this&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17961</id>
		<title>Firefox2/StatusMeetings/2006-02-28</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17961"/>
		<updated>2006-03-01T04:51:07Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Features */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-21|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-07|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
brettw, linus, annie, darin, ben, jhughes, brakowski, timr, rob_strong, dveditz, rebron, Axel, gavin_, autonome, bsmedberg, markp, mconnor&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
** performance (Tp, Ts) has gotten better, close to status quo if not better&lt;br /&gt;
** problems with memory leak on balsa that we&#039;re trying to track down; this is blocking us as we can&#039;t turn it on. We&#039;re not sure that this is even Places that&#039;s doing it.&lt;br /&gt;
*** dveditz: the whole point of &amp;quot;WARN_IF_FALSE&amp;quot; was to warn instead of fail on an assertion.&lt;br /&gt;
*** darin: I&#039;m gonna rack that up to maybe a typo in nsDebug.h?&lt;br /&gt;
*** ben: maybe we can flip places on?&lt;br /&gt;
*** beltzner: will post to devnews tonight, then flip it on for Weds morning&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
** at a hard decision about what approach to take&lt;br /&gt;
*** either hide-the-tab, try to leverage bfcache, or just try to preserve form data retention&lt;br /&gt;
** will be able to get it ready for A1 based on one of these directions, assuming we still want to&lt;br /&gt;
*** beltzner: I think we should get at least one of these directions in place&lt;br /&gt;
** darin: why would we use bfcache?&lt;br /&gt;
** bsmedberg: it might help persist full state while not allowing plugins and media to run in the background (which would happen with hide-the-tab)&lt;br /&gt;
** darin: need to be careful about onunload() handlers&lt;br /&gt;
** mconnor: if I can&#039;t figure out a way to make it work consistently, we might want to push this off to A2 or even extension-land&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
** &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
** patch waiting for review&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
** landed, no regressions&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
** review going well, working through Ben&#039;s comments&lt;br /&gt;
** not going to move to toolkit based on feedback in d-a-f&lt;br /&gt;
** looking to have a new patch for review soon (today/tomorrow)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
** it&#039;s on trunk already (without the dictionary) --enable-extension: spellcheck? there are instructions in the enable spell check bug&lt;br /&gt;
** still blocked on licensing, who do I talk to about this? mscott for starters.&lt;br /&gt;
** ben: where does the dictionary file? what needs to happen with the build system to get it included?&lt;br /&gt;
** bsmedberg: point me to that please and we can get this started&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
** good progress on getting server infrastructure up and running&lt;br /&gt;
** should move this off to A2&lt;br /&gt;
** the exit survey will be in place for Firefox 1.5.0.2, morgamic is doing the final bits of work for the web app&lt;br /&gt;
*** also thinking about entrance survey&lt;br /&gt;
*** action &#039;&#039;&#039;beltzner&#039;&#039;&#039; cc darin on bug 314119&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
** ben needs to check in with robert, think it&#039;s stuck waiting for a review&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
** we &#039;&#039;think&#039;&#039; we&#039;re good here; not in darin&#039;s review queue anymore, at any rate&lt;br /&gt;
&lt;br /&gt;
== Blockers ==&lt;br /&gt;
* version number / branding&lt;br /&gt;
** currently set at 1.5, should it be 2.0a1?&lt;br /&gt;
** benjamin: yes, that&#039;s what mscott&#039;s doing&lt;br /&gt;
** dveditz: should we also change the trunk, which is currently 1.6a1?&lt;br /&gt;
** benjamin: mscott has all of these under proposal&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; beltzner to take this as an action&lt;br /&gt;
* davel: when we push 2.0a1 to the beta-update channel, will these users get a choice?&lt;br /&gt;
** darin: yes, if we set something as a &amp;quot;major&amp;quot; release, they&#039;ll get a choice&lt;br /&gt;
** bsmedberg: it would be a good idea to test this code path on the nightly?&lt;br /&gt;
** annie: I think there&#039;s a lot of users who don&#039;t realize that they&#039;re on a beta channel right now, so we shouldn&#039;t be pushing the alpha onto the 1.5 beta channel&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; for darin to synch up with preed(?) to make sure that everyone&#039;s up to speed&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; for QA to test the 1.5.x update logic for user choice&lt;br /&gt;
* ben: release notes? documentation for MDC?&lt;br /&gt;
** promote it as a developer release&lt;br /&gt;
** mconnor: do we even want to promote it as that? some of these APIs are going to change?&lt;br /&gt;
** beltzner: but we want that feedback, don&#039;t we?&lt;br /&gt;
** mconnor: I&#039;m worried about getting dugg, and getting bug feedback that we don&#039;t really care about anyway&lt;br /&gt;
** ben: maybe do it invite only?&lt;br /&gt;
** mconnor: get the release download numbers from Asa&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
* performance was good, no known data corruption issues&lt;br /&gt;
* annie&#039;s prepared some solid estimates, I need to do that and get it from the rest of the team&lt;br /&gt;
* &#039;&#039;&#039;action&#039;&#039;&#039; ben to meet with schrep next monday&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
* nothing beyond what&#039;s been discussed&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* Extension Dependencies - phase 1 landed - no regressions so far&lt;br /&gt;
* Extension Blacklisting - patch ready for review last Friday&lt;br /&gt;
* Extension Locales - started&lt;br /&gt;
* Extension UI - mockups and proof of concept started&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* Windows Installer - nothing new other than work on this will start again this week&lt;br /&gt;
** bsmedberg: is DOM Inspector part of the product or not?&lt;br /&gt;
** first requirement is to be able to provide variable paths for distribution and packaging of our installer&lt;br /&gt;
** now we&#039;re starting to talk about creating various levels of stub install: stub with full code, stub with all code but not optional code, stub with no code.&lt;br /&gt;
*** bsmedberg: but do we consider DOM inspector part of the application or not?&lt;br /&gt;
*** rob_strong: put it on AMO?&lt;br /&gt;
*** beltzner: we need to figure out a way to make sure that it&#039;s there for users who need it, but not there for users who aren&#039;t there&lt;br /&gt;
* Branding and Locale installer customization - nothing new&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
*Back end work complete&lt;br /&gt;
*Updated patch today or tomorrow - needs review from mconnor&lt;br /&gt;
**Addressed ben&#039;s SR comments&lt;br /&gt;
*Code to remain in /browser per discussion on dev.apps.firefox&lt;br /&gt;
*Re-factoring of the Sherlock parsing code to be completed seperately if time permits (low priority)&lt;br /&gt;
*Need to discuss search plugin format further&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* requirements for the visual refresh are [[FX2_Visual_Update|on the wiki]]&lt;br /&gt;
** will be creating a new space for discussion of this theme (dev.apps.firefox.newtheme) and trying to figure out some place to provide hosting for mockups and images &lt;br /&gt;
* met with ben and jhughes yesterday to discuss changes to the default chrome for the browser window, the outcome of which was posted to [http://groups.google.com/group/mozilla.dev.apps.firefox dev.apps.firefox]&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
&lt;br /&gt;
* SVG textPath needs to get an answer and attention in the next 2 weeks, thus I make a commitment here that I will produce a landing scenario for them by March 10.&lt;br /&gt;
&lt;br /&gt;
* no new status on UTF-16 XPCOM I/O fixes.&lt;br /&gt;
&lt;br /&gt;
* schedule for platform uplift deadlines no longer clear due to schedule strategy shift; will try to build something new there for next week.&lt;br /&gt;
&lt;br /&gt;
* need to produce a plan for tracking 1.8.1 approval queues and setting expectations there appropriately.&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
Waiting for clarification on licensing.&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
* Mostly working on server backend.  Not much new status to report.&lt;br /&gt;
* {{bug|189570}} is fixed on the trunk.&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
* SessionStore service mostly working in Bon Echo&lt;br /&gt;
* Currently pulling from cache or reloading, not dump/restoring DOM&lt;br /&gt;
* This week: define and document API, finish code review and post patch&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
* need to check in with robert sayre&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
* patch is in, waiting for branch approval&lt;br /&gt;
* continuing to investigate low hanging fruit&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* fritz, darin, neils, mmc and brakowski meeting this afternoon to talk about ways of bundling/integrating Google phishing protector&lt;br /&gt;
* also investigating heuristic-based approaches and UI rendering for warnings about phishing&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* schrep&#039;s out of town, but is still planning to kick off a meeting on collecting better performance data on daily builds to continually monitor this issue&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;br /&gt;
* annie: maybe use Google&#039;s QA to help us here&lt;br /&gt;
** &#039;&#039;&#039;action&#039;&#039;&#039; annie and timr to talk about this&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17943</id>
		<title>Firefox2/StatusMeetings/2006-02-28</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=Firefox2/StatusMeetings/2006-02-28&amp;diff=17943"/>
		<updated>2006-02-28T19:54:10Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* Offline mode / better use of cache */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;small&amp;gt;[[Firefox2/StatusMeetings/2006-02-21|&amp;lt;&amp;lt; previous week]] | [[Firefox2/StatusMeetings|index]] | [[Firefox2/StatusMeetings/2006-03-07|next week&amp;gt;&amp;gt;]]&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= In Attendance =&lt;br /&gt;
&lt;br /&gt;
= Agenda =&lt;br /&gt;
# Alpha 1 Status&lt;br /&gt;
# Firefox 2 Feature Status Roundtable&lt;br /&gt;
# Any other business&lt;br /&gt;
&lt;br /&gt;
= Alpha 1 Status =&lt;br /&gt;
== Features ==&lt;br /&gt;
* &#039;&#039;&#039;Places infrastructure (performance, stability, toolbar drag &amp;amp; drop)&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Undo Close Tab&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Tab Overflow&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Extension Blacklisting&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Extension Dependencies&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Search Plugin Format Changeover (with sherlock import)&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Spell-As-You-Type (english only)&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Instrumentation Infrastructure&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;RSS parser&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;RSS content detection (?)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Blockers ==&lt;br /&gt;
* version number / branding&lt;br /&gt;
** currently set at 1.5, should it be 2.0a1?&lt;br /&gt;
* &#039;&#039;any others?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Release ==&lt;br /&gt;
* &#039;&#039;should we start the countdown?&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Status Updates =&lt;br /&gt;
== Places ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;update from ben&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Brett: &amp;quot;Performance is good, no known data corruption issues.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Tabbed Browsing ==&lt;br /&gt;
&#039;&#039;update from mconnor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Extension Manager Enhancements ==&lt;br /&gt;
* Extension Dependencies - phase 1 landed - no regressions so far&lt;br /&gt;
* Extension Blacklisting - patch ready for review last Friday&lt;br /&gt;
* Extension Locales - started&lt;br /&gt;
* Extension UI - mockups and proof of concept started&lt;br /&gt;
&lt;br /&gt;
== Installer ==&lt;br /&gt;
* Windows Installer - nothing new other than work on this will start again this week&lt;br /&gt;
* Branding and Locale installer customization - nothing new&lt;br /&gt;
&lt;br /&gt;
== Search Engine UI ==&lt;br /&gt;
*Back end work complete&lt;br /&gt;
*Updated patch today or tomorrow - needs review from mconnor&lt;br /&gt;
**Addressed ben&#039;s SR comments&lt;br /&gt;
*Code to remain in /browser per discussion on dev.apps.firefox&lt;br /&gt;
*Re-factoring of the Sherlock parsing code to be completed seperately if time permits (low priority)&lt;br /&gt;
*Need to discuss search plugin format further&lt;br /&gt;
&lt;br /&gt;
== Visual/UI Refresh ==&lt;br /&gt;
* requirements for the visual refresh are [[FX2_Visual_Update|on the wiki]]&lt;br /&gt;
** will be creating a new space for discussion of this theme (dev.apps.firefox.newtheme) and trying to figure out some place to provide hosting for mockups and images &lt;br /&gt;
* met with ben and jhughes yesterday to discuss changes to the default chrome for the browser window, the outcome of which was posted to [http://groups.google.com/group/mozilla.dev.apps.firefox dev.apps.firefox]&lt;br /&gt;
&lt;br /&gt;
== Platform Uplift ==&lt;br /&gt;
&lt;br /&gt;
* SVG textPath needs to get an answer and attention in the next 2 weeks, thus I make a commitment here that I will produce a landing scenario for them by March 10.&lt;br /&gt;
&lt;br /&gt;
* no new status on UTF-16 XPCOM I/O fixes.&lt;br /&gt;
&lt;br /&gt;
* schedule for platform uplift deadlines no longer clear due to schedule strategy shift; will try to build something new there for next week.&lt;br /&gt;
&lt;br /&gt;
* need to produce a plan for tracking 1.8.1 approval queues and setting expectations there appropriately.&lt;br /&gt;
&lt;br /&gt;
== Inline Spell Check ==&lt;br /&gt;
Waiting for clarification on licensing.&lt;br /&gt;
&lt;br /&gt;
== Instrumentation / Exit Surveys ==&lt;br /&gt;
Mostly working on server backend.  Not much new status to report.&lt;br /&gt;
&lt;br /&gt;
== Session Saver ==&lt;br /&gt;
&lt;br /&gt;
* SessionStore service mostly working in Bon Echo&lt;br /&gt;
* Currently pulling from cache or reloading, not dump/restoring DOM&lt;br /&gt;
* This week: define and document API, finish code review and post patch&lt;br /&gt;
&lt;br /&gt;
== Branding &amp;amp; Update Systems ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== RSS ==&lt;br /&gt;
&#039;&#039;update from ben&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Offline mode / better use of cache ==&lt;br /&gt;
&lt;br /&gt;
{{bug|189570}} is fixed on the trunk.&lt;br /&gt;
&lt;br /&gt;
== Anti-Phishing ==&lt;br /&gt;
* fritz, darin, neils, mmc and brakowski meeting this afternoon to talk about ways of bundling/integrating Google phishing protector&lt;br /&gt;
* also investigating heuristic-based approaches and UI rendering for warnings about phishing&lt;br /&gt;
&lt;br /&gt;
== EULA ==&lt;br /&gt;
* nothing new here&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
* schrep&#039;s out of town, but is still planning to kick off a meeting on collecting better performance data on daily builds to continually monitor this issue&lt;br /&gt;
&lt;br /&gt;
= Other Business =&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
	<entry>
		<id>https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18003</id>
		<title>XPCOM:nsIThreadManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.mozilla.org/index.php?title=XPCOM:nsIThreadManager&amp;diff=18003"/>
		<updated>2006-02-24T23:46:26Z</updated>

		<summary type="html">&lt;p&gt;Darin: /* biesi: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In a world without nested event queues, the concept of a thread and an event queue merge...&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
=== nsIThreadManager ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadManager : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Create a new named thread (a global, user PRThread).  If the name is&lt;br /&gt;
    * non-empty, then the name of the thread must be unique.  Specifying an&lt;br /&gt;
    * empty name results in an anonymous thread that cannot be found later on&lt;br /&gt;
    * using the getThread method.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread newThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Find a named thread.  If no thread exists by the given name, then null&lt;br /&gt;
    * is returned.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread getThread(in ACString name);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the nsIThread object (if any) corresponding to the given PRThread.&lt;br /&gt;
    * This method returns null if there is no corresponding nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] nsIThread getThreadFromPRThread(in PRThread thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the main thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread mainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute nsIThread currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * This attribute is true if the calling thread is the main thread of the&lt;br /&gt;
    * application process.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute boolean isMainThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Set an external nsIThread instance (or null) as the nsIThread for the&lt;br /&gt;
    * current thread.  If a nsIThread is already associated with the calling&lt;br /&gt;
    * thread, then this function will replace it with the given nsIThread.  If&lt;br /&gt;
    * the given nsIThread is non-null, then its name attribute must be unique.&lt;br /&gt;
    * Its name may be equal to the name of the nsIThread being replaced.  This&lt;br /&gt;
    * method returns the nsIThread that was replaced by this method call or null&lt;br /&gt;
    * if there was no previous nsIThread associated with the current thread.&lt;br /&gt;
    */&lt;br /&gt;
   nsIThread setCurrentThread(in nsIThread thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIEventTarget ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIEventTarget : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Dispatch an event to the target.  This function may be called from any&lt;br /&gt;
    * thread.  If flags specifies DISPATCH_SYNC, then the dispatch method&lt;br /&gt;
    * will not return until the event has been processed.  NOTE: Calling &lt;br /&gt;
    * dispatch with DISPATCH_SYNC, may have the side-effect of running other &lt;br /&gt;
    * events on the current thread while waiting for the given event to run&lt;br /&gt;
    * to completion.  This function is thread-safe and re-entrant.&lt;br /&gt;
    */&lt;br /&gt;
   void dispatch(in nsIRunnable event, in unsigned long flags);&lt;br /&gt;
   const unsigned long DISPATCH_NORMAL = 0;&lt;br /&gt;
   const unsigned long DISPATCH_SYNC   = 1;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if events dispatched to this target will run on the&lt;br /&gt;
    * current thread (i.e., the thread calling this method).&lt;br /&gt;
    */&lt;br /&gt;
   boolean isOnCurrentThread();&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 %{C++&lt;br /&gt;
 // convenient aliases:&lt;br /&gt;
 #define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL&lt;br /&gt;
 #define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC&lt;br /&gt;
 %}&lt;br /&gt;
&lt;br /&gt;
=== nsIThread ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThread : nsIEventTarget {&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the name of the thread, which may be empty if this thread is&lt;br /&gt;
    * anonymous.&lt;br /&gt;
    */&lt;br /&gt;
   readonly attribute ACString name;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns the PRThread object corresponding to this nsIThread.&lt;br /&gt;
    */&lt;br /&gt;
   [noscript] PRThread getPRThread();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread.  This method may not be executed from the thread&lt;br /&gt;
    * itself.  Instead, it is meant to be executed from another thread (usually&lt;br /&gt;
    * the thread that created this thread).  When this function returns, the&lt;br /&gt;
    * thread will be shutdown, and it will no longer be possible to dispatch&lt;br /&gt;
    * events to the thread.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Returns true if this thread has one or more pending events.&lt;br /&gt;
    */&lt;br /&gt;
   boolean hasPendingEvents();&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Process the next event.  If there are no pending events, then this&lt;br /&gt;
    * method will wait until an event is dispatched to this thread.  This&lt;br /&gt;
    * method is re-entrant but may only be called if this thread is the&lt;br /&gt;
    * current thread.&lt;br /&gt;
    */&lt;br /&gt;
   void processNextEvent();&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadInternal ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadInternal : nsIThread {&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set an observer for this thread.&lt;br /&gt;
    */&lt;br /&gt;
   attribute nsIThreadObserver observer;&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadObserver ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadObserver : nsISupports {&lt;br /&gt;
   /**&lt;br /&gt;
    * Called when an event is dispatched to the thread.  This method&lt;br /&gt;
    * may be called on any thread.&lt;br /&gt;
    */&lt;br /&gt;
   void onDispatchEvent(in nsIThreadInternal thread,&lt;br /&gt;
                        in unsigned long flags);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the beginning of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onEnterProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Called at the end of nsIThread::processNextEvent.&lt;br /&gt;
    */&lt;br /&gt;
   void onLeaveProcessNextEvent(in nsIThreadInternal thread);&lt;br /&gt;
 };&lt;br /&gt;
=== nsIThreadPool ===&lt;br /&gt;
 [scriptable, uuid(...)]&lt;br /&gt;
 interface nsIThreadPool : nsIEventTarget&lt;br /&gt;
 {&lt;br /&gt;
   /**&lt;br /&gt;
    * Shutdown the thread pool.  This method may not be executed from any&lt;br /&gt;
    * thread in the thread pool.  Instead, it is meant to be executed from&lt;br /&gt;
    * another thread (usually the thread that created this thread pool).&lt;br /&gt;
    * When this function returns, the thread pool and all of its threads will&lt;br /&gt;
    * be shutdown, and it will no longer be possible to dispatch tasks to the&lt;br /&gt;
    * thread pool.&lt;br /&gt;
    */&lt;br /&gt;
   void shutdown()&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of threads allowed at one time in this pool.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long threadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the maximum number of idle threads kept alive.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadLimit;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   /**&lt;br /&gt;
    * Get/set the amount of time in milliseconds before an idle thread is&lt;br /&gt;
    * destroyed.&lt;br /&gt;
    */&lt;br /&gt;
   attribute unsigned long idleThreadTimeout;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== C++ Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
nsThreadUtils.h defines the following helper functions:&lt;br /&gt;
&lt;br /&gt;
 NS_METHOD NS_NewThread(const nsACString &amp;amp;name, nsIRunnable *event,&lt;br /&gt;
                        nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 NS_METHOD NS_GetCurrentThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 NS_METHOD NS_GetMainThread(nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 NS_METHOD NS_GetThread(const nsACString &amp;amp;name, nsIThread **result);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 PRBool NS_IsMainThread();&lt;br /&gt;
&lt;br /&gt;
=== nsCOMPtr helpers ===&lt;br /&gt;
The following nsCOMPtr helpers are defined to simplify things further:&lt;br /&gt;
&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetCurrentThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetMainThread();&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 already_AddRefed&amp;lt;nsIThread&amp;gt; do_GetThread(const nsACString &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
=== nsRunnable ===&lt;br /&gt;
The class &amp;lt;code&amp;gt;nsRunnable&amp;lt;/code&amp;gt; is also defined to simplify the&lt;br /&gt;
implementation of new event types.  For example, to define a new&lt;br /&gt;
event all you need to do is write code like this:&lt;br /&gt;
&lt;br /&gt;
 class MyEvent : public nsRunnable {&lt;br /&gt;
 public:&lt;br /&gt;
   MyEvent(... params ...);&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   NS_IMETHOD Run() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
     return NS_OK;&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Dispatching &amp;lt;code&amp;gt;MyEvent&amp;lt;/code&amp;gt; is then as simple as:&lt;br /&gt;
&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIThread&amp;gt; thread = do_GetCurrentThread();&lt;br /&gt;
 NS_ENSURE_STATE(thread);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 nsCOMPtr&amp;lt;nsIRunnable&amp;gt; event = new MyEvent();&lt;br /&gt;
 NS_ENSURE_STATE(event);&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 thread-&amp;gt;Dispatch(event, NS_DISPATCH_NORMAL);&lt;br /&gt;
&lt;br /&gt;
== From JS ==&lt;br /&gt;
&lt;br /&gt;
=== Event Dispatch ===&lt;br /&gt;
Threads and Thread Manager implement &amp;lt;code&amp;gt;nsIClassInfo&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 function MyEvent() {&lt;br /&gt;
 }&lt;br /&gt;
 MyEvent.prototype = {&lt;br /&gt;
   QueryInterface: function(iid) {&lt;br /&gt;
     if (iid.equals(Components.interfaces.nsIRunnable) ||&lt;br /&gt;
         iid.equals(Components.interfaces.nsISupports))&lt;br /&gt;
       return this;&lt;br /&gt;
     throw Components.results.NS_ERROR_NO_INTERFACE;&lt;br /&gt;
   },&lt;br /&gt;
   run: function() {&lt;br /&gt;
     // do stuff&lt;br /&gt;
   }&lt;br /&gt;
 };&lt;br /&gt;
 &amp;amp;nbsp;&lt;br /&gt;
 function DispatchMyEvent() {&lt;br /&gt;
   var target = &lt;br /&gt;
       Components.classes[&amp;quot;@mozilla.org/thread-manager;1&amp;quot;].&lt;br /&gt;
       getService().currentThread;&lt;br /&gt;
   &amp;amp;nbsp;&lt;br /&gt;
   target.dispatch(new MyEvent(), target.DISPATCH_NORMAL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Remarks ==&lt;br /&gt;
&lt;br /&gt;
* Thread priority for native threads can be exposed via &amp;lt;code&amp;gt;nsISupportsPriority&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Thread names must be unique.&lt;br /&gt;
* The Necko I/O thread pool will be replaced by a generic thread pool implementation provided by XPCOM.  The thread pool will implement &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, allowing events to be dispatched to any thread in the thread pool.  We may even wish to define a &amp;lt;code&amp;gt;nsIThreadPool&amp;lt;/code&amp;gt; interface and have it implement that as well.  That interface would define methods to adjust the limits on the number of threads in the thread pool and so on.&lt;br /&gt;
* We will need an alternative for &amp;lt;code&amp;gt;nsIEventQueue::RevokeEvents&amp;lt;/code&amp;gt;.  There are several possibilities: (1) make consumers hold references to their nsIRunnable&#039;s so they can &amp;quot;disconnect&amp;quot; them manually, or (2) expose an enumeration/visitor API that allows consumers to walk the list of pending tasks and remove arbitrary tasks.  I&#039;m not sure what is best yet.  The first option or something similar based on weak references is probably best as it avoids the costly O(n) &amp;lt;code&amp;gt;RevokeEvents&amp;lt;/code&amp;gt; call.&lt;br /&gt;
* The following interfaces/classes would go away or be modified heavily: nsIEventQueue, nsIEventQueueService, nsIEventTarget, nsIThread, PLEvent.&lt;br /&gt;
* Issue: Perhaps we should support calling &amp;lt;code&amp;gt;nsIThread::Shutdown&amp;lt;/code&amp;gt; from the thread itself.  That would probably have to be implemented by posting an event to the main thread, and having that thread call shutdown.  However, &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; also has the property that it does not return until the thread is gone.  That obvious can&#039;t happen if &amp;lt;code&amp;gt;Shutdown&amp;lt;/code&amp;gt; is called on the thread itself.&lt;br /&gt;
&lt;br /&gt;
=== What about &amp;quot;native&amp;quot; event queues? ===&lt;br /&gt;
The main thread where UI events are processed and the socket transport thread will use the observer interface defined by &amp;lt;code&amp;gt;nsIThreadInternal&amp;lt;/code&amp;gt;.  The main thread will interact with the &amp;quot;native&amp;quot; event system during calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;.  Likewise, the socket transport thread will similarly need to poll sockets and perform I/O operations.  By observing calls to &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, observers can wait on a native event queue (or poll on a set of file descriptors) instead of waiting on the thread&#039;s internal event queue monitor.  When they observe a call to &amp;lt;code&amp;gt;Dispatch&amp;lt;/code&amp;gt;, they can use whatever mechanism is appropriate to unblock the thread that is waiting on the native event queue.&lt;br /&gt;
&lt;br /&gt;
=== How do synchronous events work? ===&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;Dispatch(event, DISPATCH_SYNC)&amp;lt;/code&amp;gt; is called on a &amp;lt;code&amp;gt;nsIEventTarget&amp;lt;/code&amp;gt;, it first checks to see if the current thread is the same as the thread where the event would be run.  If it is, then it just runs the event directly without queuing it up.  However, if not, then it must queue the event to be run when the dispatch target next processes its events.  To avoid returning to the caller immediately, the method gets the current thread and calls its &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; method in a loop until it receives acknowledgement that the queued event has been run.&lt;br /&gt;
&lt;br /&gt;
== Development ==&lt;br /&gt;
&lt;br /&gt;
Development is occuring on the THREADS_20060213_BRANCH.  See also {{bug|326273}}.&lt;br /&gt;
&lt;br /&gt;
== Comments ==&lt;br /&gt;
&lt;br /&gt;
=== biesi: ===&lt;br /&gt;
* What happens if shutdown is called while an event is being processed? I assume that this event will be processed to its end, no further events are accepted, and then the thread is shut down. right?&lt;br /&gt;
** What happens to events that were already dispatched to this thread, but not run?&lt;br /&gt;
* Is it a good idea to allow other events to run on the current thread while in dispatch?&lt;br /&gt;
* Who is expected to call ProcessNextEvent?&lt;br /&gt;
&lt;br /&gt;
==== darin: ====&lt;br /&gt;
* When asked to shutdown, a thread would finish dispatching all queued events, and refuse to accept any new events.  Once all queued events run to completion, the thread would terminate.  This is consistent with how event queues work today.&lt;br /&gt;
* If you are sync dispatching, then it is necessary to pump events on the calling thread or else you could end up in a dead-lock situation.  For example, if thread A sync dispatches an event to thread B, which cannot complete its job without dispatching an event back to thread A, then the system will dead-lock unless thread A continues to dispatch pending events.&lt;br /&gt;
* &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; may be called by anybody that wishes to implement the concept of a &amp;quot;modal event loop.&amp;quot;  For example, XMLHttpRequest (in sync configuration) would sit in a loop calling &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; while waiting for the underlying HTTP transaction to complete.  The key difference between &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;nsIEventQueue::ProcessPendingEvents&amp;lt;/code&amp;gt; is that &amp;lt;code&amp;gt;ProcessNextEvent&amp;lt;/code&amp;gt;, when called on the UI thread, will process UI events as well.  And, it will also wait (block the thread of execution) if there are no UI events or pending &amp;lt;code&amp;gt;nsIRunnable&amp;lt;/code&amp;gt; events.&lt;/div&gt;</summary>
		<author><name>Darin</name></author>
	</entry>
</feed>