home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / jsmodules / GeneratorThread.jsm < prev    next >
Text File  |  2012-06-08  |  11KB  |  361 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set sw=2 :miv */
  3. /*
  4. //
  5. // BEGIN SONGBIRD GPL
  6. //
  7. // This file is part of the Songbird web player.
  8. //
  9. // Copyright(c) 2005-2008 POTI, Inc.
  10. // http://songbirdnest.com
  11. //
  12. // This file may be licensed under the terms of of the
  13. // GNU General Public License Version 2 (the "GPL").
  14. //
  15. // Software distributed under the License is distributed
  16. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  17. // express or implied. See the GPL for the specific language
  18. // governing rights and limitations.
  19. //
  20. // You should have received a copy of the GPL along with this
  21. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  22. // or write to the Free Software Foundation, Inc.,
  23. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  24. //
  25. // END SONGBIRD GPL
  26. //
  27. */
  28.  
  29. /**
  30.  * \file  GeneratorThread.jsm
  31.  * \brief Javascript source for the generator thread services.
  32.  */
  33.  
  34. //------------------------------------------------------------------------------
  35. //
  36. // Generator thread configuration.
  37. //
  38. //------------------------------------------------------------------------------
  39.  
  40. EXPORTED_SYMBOLS = [ "GeneratorThread" ];
  41.  
  42.  
  43. //------------------------------------------------------------------------------
  44. //
  45. // Generator thread defs.
  46. //
  47. //------------------------------------------------------------------------------
  48.  
  49. const Cc = Components.classes;
  50. const Ci = Components.interfaces;
  51. const Cr = Components.results;
  52. const Cu = Components.utils;
  53.  
  54.  
  55. //------------------------------------------------------------------------------
  56. //
  57. // GeneratorThread class.
  58. //
  59. //   This class implements pseudo-threads using Javascript generators.  These
  60. // threads provide support for cooperative multitasking within the main thread.
  61. //   The entry point for a generator thread is a generator-iterator.  The
  62. // generator-iterator is scheduled for execution on a periodic basis.  The
  63. // scheduling period is set with the thread period field.
  64. //   The thread generator-iterator may use the yield keyword to allow other
  65. // threads to run.  In this case, no value should be provided with the yield
  66. // keyword.
  67. //   If the generator-iterator entry point provides another generator-iterator
  68. // with the yield keyword, the new generator-iterator will be pushed onto a
  69. // thread generator-iterator stack.  When the thread is scheduled for execution,
  70. // the generator-iterator on the top of the stack will be run.
  71. //   The generator-iterators on the stack will be run until a generator-iterator
  72. // yields with no new generator-iterator or until the stack is empty.
  73. //   The generator-iterator should use the yieldIfShould class method to yield
  74. // if the thread's allocated CPU percentage has been consumed.  The maximum CPU
  75. // percentage can be set with the thread maxPctCPU field.  The yieldIfShould
  76. // method is a generator, so it should be used as follows:
  77. //
  78. //   yield GeneratorThread.yieldIfShould();
  79. //
  80. //   If the thread should not yield, the generator-iterator will continue to be
  81. // run.
  82. //
  83. //   For more on generators, see
  84. // http://developer.mozilla.org/en/New_in_JavaScript_1.7
  85. //
  86. //------------------------------------------------------------------------------
  87.  
  88. /**
  89.  * Construct an GeneratorThread object with the thread entry point
  90.  * generator-iterator specified by aEntryPoint.
  91.  *
  92.  * \param aEntryPoint           Thread entry point.
  93.  */
  94.  
  95. function GeneratorThread(aEntryPoint) {
  96.   // Push the entry point onto the generator-iterator stack.
  97.   this._genIterStack = [];
  98.   this._genIterStack.push(aEntryPoint);
  99. }
  100.  
  101.  
  102. //
  103. // Pseudo-thread class fields.
  104. //
  105. //   currentThread              Currently scheduled thread.
  106. //
  107.  
  108. GeneratorThread.currentThread = null;
  109.  
  110.  
  111. /**
  112.  * Terminate the current thread.
  113.  */
  114.  
  115. GeneratorThread.terminateCurrentThread =
  116.   function GeneratorThread_terminateCurrentThread() {
  117.   if (this.currentThread)
  118.     this.currentThread.terminate();
  119. }
  120.  
  121.  
  122. /**
  123.  * Return true if the current thread should yield.
  124.  *
  125.  * \return True if current thread should yield.
  126.  */
  127.  
  128. GeneratorThread.shouldYield = function GeneratorThread_shouldYield() {
  129.   // Get the current thread info.
  130.   var yieldThreshold = this.currentThread._yieldThreshold;
  131.   var scheduleStartTime = this.currentThread._scheduleStartTime;
  132.  
  133.   // Get the current time.
  134.   var currentTime = (new Date()).getTime();
  135.  
  136.   // Determine whether the thread should yield.
  137.   if ((currentTime - scheduleStartTime) >= yieldThreshold)
  138.     return true;
  139.   return false;
  140. }
  141.  
  142.  
  143. /**
  144.  * Yield if the current thread should yield.
  145.  */
  146.  
  147. GeneratorThread.yieldIfShould = function GeneratorThread_yieldIfShould() {
  148.   if (GeneratorThread.shouldYield())
  149.     yield;
  150. }
  151.  
  152.  
  153. // Define the class instance services.
  154. GeneratorThread.prototype = {
  155.   // Set the constructor.
  156.   constructor: GeneratorThread,
  157.  
  158.   //
  159.   // Public object fields.
  160.   //
  161.   //   period                   Thread scheduling period in milliseconds.
  162.   //   maxPctCPU                Maximum thread CPU execution percentage (0 -
  163.   //                            100).
  164.   //
  165.  
  166.   period: 50,
  167.   maxPctCPU: 50,
  168.  
  169.  
  170.   //
  171.   // Internal object fields.
  172.   //
  173.   //   _genIterStack            Thread generator-iterator stack.
  174.   //   _timer                   Thread scheduling timer.
  175.   //   _yieldThreshold          Execution time threshold in milliseconds after
  176.   //                            which thread should yield.
  177.   //   _scheduleStartTime       Time when thread scheduling started.
  178.   //
  179.  
  180.   _genIterStack: null,
  181.   _timer: null,
  182.   _yieldThreshold: 0,
  183.   _scheduleStartTime: 0,
  184.  
  185.  
  186.   //----------------------------------------------------------------------------
  187.   //
  188.   // Public services.
  189.   //
  190.   //----------------------------------------------------------------------------
  191.  
  192.   /**
  193.    * Start running the thread.
  194.    */
  195.  
  196.   start: function GeneratorThread_start() {
  197.     // Compute the yield time threshold.
  198.     this._yieldThreshold = (this.period * this.maxPctCPU) / 100;
  199.  
  200.     // Create a thread scheduling timer.
  201.     this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  202.  
  203.     // Set up to periodically run the thread.
  204.     var _this = this;
  205.     var func = function() { _this._run(); };
  206.     this._timer.initWithCallback(func,
  207.                                  this.period,
  208.                                  Ci.nsITimer.TYPE_REPEATING_SLACK);
  209.   },
  210.  
  211.  
  212.   /**
  213.    * Terminate the thread.
  214.    */
  215.  
  216.   terminate: function GeneratorThread_terminate() {
  217.     // Close all of the generators in the stack.
  218.     var genIter;
  219.     while (genIter = this._genIterStack.pop()) {
  220.       genIter.close();
  221.     }
  222.  
  223.     // Dispose of the scheduling timer.
  224.     if (this._timer) {
  225.       this._timer.cancel();
  226.       this._timer = null;
  227.     }
  228.  
  229.     // Remove object references.
  230.     this._genIterStack = [];
  231.   },
  232.  
  233.  
  234.   //----------------------------------------------------------------------------
  235.   //
  236.   // Internal services.
  237.   //
  238.   //----------------------------------------------------------------------------
  239.  
  240.   /**
  241.    * This function runs the thread.
  242.    */
  243.  
  244.   _run: function GeneratorThread__run() {
  245.     // Schedule the thread.
  246.     this._scheduleStartTime = (new Date()).getTime();
  247.     GeneratorThread.currentThread = this;
  248.  
  249.     // Run the generator stack.
  250.     this._runStack();
  251.  
  252.     // Unschedule the thread.
  253.     GeneratorThread.currentThread = null;
  254.  
  255.     // Terminate the thread if the generator-iterator stack is empty.
  256.     if (this._genIterStack.length == 0)
  257.       this.terminate();
  258.  
  259.     // Adjust the thread timer period.
  260.     this._adjustTimer();
  261.   },
  262.  
  263.  
  264.   /**
  265.    * Run the generator-iterator stack.
  266.    *
  267.    * Continue running the generator-iterator on the top of the stack until one
  268.    * yields without a new generator-iterator or until the stack is empty.
  269.    */
  270.  
  271.   _runStack: function GeneratorThread__runStack() {
  272.     // Start running with the generator-iterator on the top of the stack.
  273.     var nextGenIter = this._genIterStack[this._genIterStack.length - 1];
  274.  
  275.     // Keep running while there's a generator-iterator to run.
  276.     //XXXeps ideally, we'd check to see if the thread should yield.  However,
  277.     //XXXeps the check is expensive since creating a new Date object is
  278.     //XXXeps expensive.  Instead, we rely upon the thread to make periodic
  279.     //XXXeps checks.
  280.     var exception = null;
  281.     while (nextGenIter) {
  282.       // Get the next generator-iterator to run.
  283.       var genIter = nextGenIter;
  284.       nextGenIter = null;
  285.  
  286.       // Run the generator-iterator.
  287.       try {
  288.         // Run the generator-iterator.  If the generator-iterator yields a new
  289.         // generator-iterator, run it next.  If an unhandled exception occured,
  290.         // propagate it to the generator-iterator.
  291.         if (!exception) {
  292.           nextGenIter = genIter.next();
  293.         } else {
  294.           var throwException = exception;
  295.           exception = null;
  296.           nextGenIter = genIter.throw(throwException);
  297.         }
  298.  
  299.         // If the generator-iterator yielded a new generator-iterator, push it
  300.         // onto the stack.
  301.         if (nextGenIter)
  302.           this._genIterStack.push(nextGenIter);
  303.       } catch (ex) {
  304.         // Pop completed generator-iterator off of stack and run the next
  305.         // generator-iterator on the top of the stack.
  306.         this._genIterStack.pop();
  307.         if (this._genIterStack.length > 0)
  308.           nextGenIter = this._genIterStack[this._genIterStack.length - 1];
  309.         else
  310.           nextGenIter = null;
  311.  
  312.         // Propagate non-StopIteration exceptions.
  313.         if (!(ex instanceof StopIteration))
  314.           exception = ex;
  315.       }
  316.     }
  317.  
  318.     // Report unhandled exceptions.
  319.     if (exception) {
  320.       var msg = "GeneratorThread exception: " + exception +
  321.                 " at " + exception.fileName +
  322.                 ", line " + exception.lineNumber;
  323.       Cu.reportError(msg);
  324.       dump(msg + "\n");
  325.     }
  326.   },
  327.  
  328.  
  329.   /**
  330.    * Adjust the thread timer to maintain thread maximum CPU percentage.
  331.    */
  332.  
  333.   _adjustTimer: function GeneratorThread__adjustTimer() {
  334.     // Do nothing if no timer.
  335.     if (!this._timer)
  336.       return;
  337.  
  338.     // Get the thread scheduling end time.
  339.     var scheduleEndTime = (new Date()).getTime();
  340.  
  341.     // Adjust the scheduling period by the amount of excess time over the
  342.     // threshold.
  343.     var adjTime = scheduleEndTime -
  344.                   this._scheduleStartTime -
  345.                   this._yieldThreshold;
  346.     if (adjTime < 0)
  347.       adjTime = 0;
  348.  
  349.     // Limit the adjustment.
  350.     if (adjTime > 1000)
  351.       adjTime = 1000;
  352.  
  353.     // Update the scheduling timer period.
  354.     var newDelay = this.period + adjTime;
  355.     if (this._timer.delay != newDelay)
  356.       this._timer.delay = newDelay;
  357.   }
  358. };
  359.  
  360.  
  361.