OLD | NEW |
(Empty) | |
| 1 let {Logger} = require( "logger" ); |
| 2 |
| 3 /** |
| 4 * This task just counts. |
| 5 * |
| 6 * @param count |
| 7 * The number of iterations. |
| 8 * @param count_notifier |
| 9 * The count notifier is called once at each iteration with this current lo
op counter. |
| 10 * @param completion_notifier |
| 11 * The completion notifier is called when the task is finished. Because a l
ong running task does not run |
| 12 * synchronously, we need some kind of notification system. |
| 13 * @param {Boolean} [use_slow_version=true] |
| 14 */ |
| 15 var Counting_Task = exports.Counting_Task = function( count, count_notifier, com
pletion_notifier, variant ) |
| 16 { |
| 17 this.count = count; |
| 18 this.count_notifier = count_notifier; |
| 19 this.completion_notifier = completion_notifier; |
| 20 |
| 21 this.logger = new Logger( "Counting_Task" ); |
| 22 |
| 23 switch ( variant.type ) |
| 24 { |
| 25 case "segmented fast": |
| 26 this.segmented = true; |
| 27 this._dispatch_self = function() |
| 28 { |
| 29 this.thread_manager.currentThread.dispatch( { run: this.land }, Ci.nsIEv
entTarget.DISPATCH_NORMAL ); |
| 30 }; |
| 31 /** |
| 32 * Thread manager is used to make counting an asynchronous operation. |
| 33 * @type {nsIThreadManager} |
| 34 */ |
| 35 this.thread_manager = Cc["@mozilla.org/thread-manager;1"].createInstance(
Ci.nsIThreadManager ); |
| 36 break; |
| 37 case "segmented slow": |
| 38 this.segmented = true; |
| 39 this._dispatch_self = function() |
| 40 { |
| 41 this.timer.initWithCallback( this.land.bind( this ), 100, Ci.nsITimer.TY
PE_ONE_SHOT ); |
| 42 }; |
| 43 /** |
| 44 * This task uses a timer to slow down the count in order to provide a sim
ulation of a slow task to exercise |
| 45 * pause-resume functionality. |
| 46 * @type {*} |
| 47 */ |
| 48 this.timer = Cc["@mozilla.org/timer;1"].createInstance( Ci.nsITimer ); |
| 49 break; |
| 50 case "continuous": |
| 51 this.segmented = false; |
| 52 break; |
| 53 default: |
| 54 throw "Unknown Counting_task variant"; |
| 55 } |
| 56 this.logger.make_log()( "using " + variant.type + " variant" ); |
| 57 }; |
| 58 |
| 59 /** |
| 60 * The generator for the task. |
| 61 * |
| 62 * @param {Function} pause |
| 63 * @param {Function} resume |
| 64 */ |
| 65 Counting_Task.prototype.generator = function( pause, resume ) |
| 66 { |
| 67 var log = this.logger.make_log( "task" ); |
| 68 log( "begin" ); |
| 69 |
| 70 /** |
| 71 * Flag indicating if there's a pending asynchronous operation. |
| 72 * @type {Boolean} |
| 73 */ |
| 74 var pending = false; |
| 75 |
| 76 /** |
| 77 * Internal landing function for segmented variants. Defined here to gain acce
ss to the scope variables in the chain |
| 78 * of the present invocation of the function. |
| 79 */ |
| 80 this.land = function() |
| 81 { |
| 82 pending = false; |
| 83 resume(); |
| 84 }; |
| 85 |
| 86 var j; |
| 87 for ( j = 0 ; j < this.count ; ++j ) |
| 88 { |
| 89 if ( this.segmented && !pending ) |
| 90 { |
| 91 this._dispatch_self(); |
| 92 pause(); |
| 93 pending = true; |
| 94 } |
| 95 /* |
| 96 * The rvalue of a yield statement is the argument to 'send()' called on the
generator. The task runner |
| 97 * calls 'send( true )' to indicated cancellation. 'next()' is a synonym for
'send( undefined )'. Thus, |
| 98 * the possible values for 'cancelled' are 'true' and 'undefined'. |
| 99 */ |
| 100 var cancelled = yield false; |
| 101 if ( cancelled ) |
| 102 { |
| 103 log( "cancelled" ); |
| 104 break; |
| 105 } |
| 106 if ( this.count_notifier ) |
| 107 this.count_notifier( j ); |
| 108 } |
| 109 if ( j == this.count ) |
| 110 { |
| 111 // Assert the loop terminated in the 'for' statement, not with a cancellatio
n. |
| 112 log( "finished" ) |
| 113 } |
| 114 if ( this.completion_notifier ) |
| 115 this.completion_notifier(); |
| 116 log( "end" ); |
| 117 }; |
OLD | NEW |