GeneratorThread.jsm
Go to the documentation of this file.
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 
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 
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 
115 GeneratorThread.terminateCurrentThread =
116  function GeneratorThread_terminateCurrentThread() {
117  if (this.currentThread)
118  this.currentThread.terminate();
119 }
120 
121 
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 
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.
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 
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 
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 
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 
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 
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 
function start(ch)
GeneratorThread currentThread
function GeneratorThread(aEntryPoint)
const Ci
EXPORTED_SYMBOLS
const Cu
sbDeviceFirmwareAutoCheckForUpdate prototype _timer
DataRemote prototype constructor
var _this
return null
Definition: FeedWriter.js:1143
const Cr
function msg
const Cc