summaryrefslogtreecommitdiff
path: root/lib/rake/promise.rb
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-15 21:59:37 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-15 21:59:37 +0000
commit9c66bad9f3d522d50d4a45ef8a3a92abbf93229f (patch)
tree8fc1ae219e41bdd711442b1d35149da4f45dfa8a /lib/rake/promise.rb
parentbfc95c6e1639edc909338ef4d20d990caf6f630e (diff)
* lib/rake*: Updated to rake 0.9.3
* test/rake*: ditto * bin/rake: ditto * NEWS: ditto git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37664 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rake/promise.rb')
-rw-r--r--lib/rake/promise.rb99
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/rake/promise.rb b/lib/rake/promise.rb
new file mode 100644
index 0000000000..3258b91139
--- /dev/null
+++ b/lib/rake/promise.rb
@@ -0,0 +1,99 @@
+module Rake
+
+ # A Promise object represents a promise to do work (a chore) in the
+ # future. The promise is created with a block and a list of
+ # arguments for the block. Calling value will return the value of
+ # the promised chore.
+ #
+ # Used by ThreadPool.
+ #
+ class Promise # :nodoc: all
+ NOT_SET = Object.new.freeze # :nodoc:
+
+ attr_accessor :recorder
+
+ # Create a promise to do the chore specified by the block.
+ def initialize(args, &block)
+ @mutex = Mutex.new
+ @result = NOT_SET
+ @error = NOT_SET
+ @args = args.collect { |a| begin; a.dup; rescue; a; end }
+ @block = block
+ end
+
+ # Return the value of this promise.
+ #
+ # If the promised chore is not yet complete, then do the work
+ # synchronously. We will wait.
+ def value
+ unless complete?
+ stat :sleeping_on, :item_id => object_id
+ @mutex.synchronize do
+ stat :has_lock_on, :item_id => object_id
+ chore
+ stat :releasing_lock_on, :item_id => object_id
+ end
+ end
+ error? ? raise(@error) : @result
+ end
+
+ # If no one else is working this promise, go ahead and do the chore.
+ def work
+ stat :attempting_lock_on, :item_id => object_id
+ if @mutex.try_lock
+ stat :has_lock_on, :item_id => object_id
+ chore
+ stat :releasing_lock_on, :item_id => object_id
+ @mutex.unlock
+ else
+ stat :bailed_on, :item_id => object_id
+ end
+ end
+
+ private
+
+ # Perform the chore promised
+ def chore
+ if complete?
+ stat :found_completed, :item_id => object_id
+ return
+ end
+ stat :will_execute, :item_id => object_id
+ begin
+ @result = @block.call(*@args)
+ rescue Exception => e
+ @error = e
+ end
+ stat :did_execute, :item_id => object_id
+ discard
+ end
+
+ # Do we have a result for the promise
+ def result?
+ ! @result.equal?(NOT_SET)
+ end
+
+ # Did the promise throw an error
+ def error?
+ ! @error.equal?(NOT_SET)
+ end
+
+ # Are we done with the promise
+ def complete?
+ result? || error?
+ end
+
+ # free up these items for the GC
+ def discard
+ @args = nil
+ @block = nil
+ end
+
+ # Record execution statistics if there is a recorder
+ def stat(*args)
+ @recorder.call(*args) if @recorder
+ end
+
+ end
+
+end