empathy 0.0.1.RC0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +135 -0
- data/Rakefile +33 -0
- data/TESTING.rdoc +11 -0
- data/empathy.gemspec +23 -0
- data/empathy.mspec +34 -0
- data/lib/empathy.rb +162 -0
- data/lib/empathy/em/condition_variable.rb +57 -0
- data/lib/empathy/em/mutex.rb +70 -0
- data/lib/empathy/em/queue.rb +84 -0
- data/lib/empathy/em/thread.rb +363 -0
- data/lib/empathy/object.rb +19 -0
- data/lib/empathy/thread.rb +8 -0
- data/lib/empathy/version.rb +3 -0
- data/mspec/lib/mspec/empathy.rb +19 -0
- data/mspec/lib/mspec/guards/empathy.rb +10 -0
- data/rubyspec/core/kernel/fixtures/__method__.rb +25 -0
- data/rubyspec/core/kernel/fixtures/autoload_b.rb +5 -0
- data/rubyspec/core/kernel/fixtures/autoload_c.rb +5 -0
- data/rubyspec/core/kernel/fixtures/autoload_d.rb +5 -0
- data/rubyspec/core/kernel/fixtures/caller_fixture1.rb +42 -0
- data/rubyspec/core/kernel/fixtures/caller_fixture2.rb +26 -0
- data/rubyspec/core/kernel/fixtures/chomp.rb +4 -0
- data/rubyspec/core/kernel/fixtures/chomp_f.rb +4 -0
- data/rubyspec/core/kernel/fixtures/chop.rb +4 -0
- data/rubyspec/core/kernel/fixtures/chop_f.rb +4 -0
- data/rubyspec/core/kernel/fixtures/classes.rb +410 -0
- data/rubyspec/core/kernel/fixtures/eval_locals.rb +6 -0
- data/rubyspec/core/kernel/fixtures/eval_return_with_lambda.rb +12 -0
- data/rubyspec/core/kernel/fixtures/eval_return_without_lambda.rb +14 -0
- data/rubyspec/core/kernel/fixtures/test.rb +362 -0
- data/rubyspec/core/kernel/sleep_spec.rb +43 -0
- data/rubyspec/core/mutex/lock_spec.rb +8 -0
- data/rubyspec/core/mutex/locked_spec.rb +8 -0
- data/rubyspec/core/mutex/sleep_spec.rb +56 -0
- data/rubyspec/core/mutex/synchronize_spec.rb +8 -0
- data/rubyspec/core/mutex/try_lock_spec.rb +8 -0
- data/rubyspec/core/mutex/unlock_spec.rb +8 -0
- data/rubyspec/core/thread/abort_on_exception_spec.rb +126 -0
- data/rubyspec/core/thread/add_trace_func_spec.rb +7 -0
- data/rubyspec/core/thread/alive_spec.rb +60 -0
- data/rubyspec/core/thread/allocate_spec.rb +9 -0
- data/rubyspec/core/thread/backtrace_spec.rb +7 -0
- data/rubyspec/core/thread/critical_spec.rb +96 -0
- data/rubyspec/core/thread/current_spec.rb +15 -0
- data/rubyspec/core/thread/element_reference_spec.rb +53 -0
- data/rubyspec/core/thread/element_set_spec.rb +46 -0
- data/rubyspec/core/thread/exclusive_spec.rb +20 -0
- data/rubyspec/core/thread/exit_spec.rb +21 -0
- data/rubyspec/core/thread/fixtures/classes.rb +291 -0
- data/rubyspec/core/thread/fork_spec.rb +9 -0
- data/rubyspec/core/thread/group_spec.rb +5 -0
- data/rubyspec/core/thread/initialize_spec.rb +26 -0
- data/rubyspec/core/thread/inspect_spec.rb +48 -0
- data/rubyspec/core/thread/join_spec.rb +63 -0
- data/rubyspec/core/thread/key_spec.rb +64 -0
- data/rubyspec/core/thread/keys_spec.rb +47 -0
- data/rubyspec/core/thread/kill_spec.rb +21 -0
- data/rubyspec/core/thread/list_spec.rb +38 -0
- data/rubyspec/core/thread/main_spec.rb +10 -0
- data/rubyspec/core/thread/new_spec.rb +56 -0
- data/rubyspec/core/thread/pass_spec.rb +8 -0
- data/rubyspec/core/thread/priority_spec.rb +9 -0
- data/rubyspec/core/thread/raise_spec.rb +225 -0
- data/rubyspec/core/thread/run_spec.rb +9 -0
- data/rubyspec/core/thread/safe_level_spec.rb +6 -0
- data/rubyspec/core/thread/set_trace_func_spec.rb +7 -0
- data/rubyspec/core/thread/shared/exit.rb +173 -0
- data/rubyspec/core/thread/shared/start.rb +51 -0
- data/rubyspec/core/thread/shared/wakeup.rb +59 -0
- data/rubyspec/core/thread/start_spec.rb +9 -0
- data/rubyspec/core/thread/status_spec.rb +48 -0
- data/rubyspec/core/thread/stop_spec.rb +66 -0
- data/rubyspec/core/thread/terminate_spec.rb +11 -0
- data/rubyspec/core/thread/value_spec.rb +36 -0
- data/rubyspec/core/thread/wakeup_spec.rb +7 -0
- data/rubyspec/empathy_spec.rb +26 -0
- data/rubyspec/library/conditionvariable/broadcast_spec.rb +62 -0
- data/rubyspec/library/conditionvariable/signal_spec.rb +64 -0
- data/rubyspec/library/conditionvariable/wait_spec.rb +21 -0
- data/rubyspec/library/mutex/lock_spec.rb +10 -0
- data/rubyspec/library/mutex/locked_spec.rb +10 -0
- data/rubyspec/library/mutex/synchronize_spec.rb +10 -0
- data/rubyspec/library/mutex/try_lock_spec.rb +10 -0
- data/rubyspec/library/mutex/unlock_spec.rb +10 -0
- data/rubyspec/library/queue/append_spec.rb +7 -0
- data/rubyspec/library/queue/clear_spec.rb +15 -0
- data/rubyspec/library/queue/deq_spec.rb +7 -0
- data/rubyspec/library/queue/empty_spec.rb +15 -0
- data/rubyspec/library/queue/enq_spec.rb +7 -0
- data/rubyspec/library/queue/length_spec.rb +7 -0
- data/rubyspec/library/queue/num_waiting_spec.rb +19 -0
- data/rubyspec/library/queue/pop_spec.rb +7 -0
- data/rubyspec/library/queue/push_spec.rb +7 -0
- data/rubyspec/library/queue/shared/deque.rb +37 -0
- data/rubyspec/library/queue/shared/enque.rb +10 -0
- data/rubyspec/library/queue/shared/length.rb +9 -0
- data/rubyspec/library/queue/shift_spec.rb +7 -0
- data/rubyspec/library/queue/size_spec.rb +7 -0
- data/rubyspec/shared/kernel/raise.rb +68 -0
- data/rubyspec/shared/mutex/lock.rb +52 -0
- data/rubyspec/shared/mutex/locked.rb +31 -0
- data/rubyspec/shared/mutex/synchronize.rb +23 -0
- data/rubyspec/shared/mutex/try_lock.rb +30 -0
- data/rubyspec/shared/mutex/unlock.rb +35 -0
- data/rubyspec/spec_helper.rb +48 -0
- data/spec/empathy_spec.rb +129 -0
- data/spec/library_spec.rb +79 -0
- data/spec/spec_helper.rb +6 -0
- metadata +222 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Grant Gardner
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
= empathy
|
2
|
+
|
3
|
+
Empathy
|
4
|
+
|
5
|
+
http://rubygems.org/gems/empathy
|
6
|
+
|
7
|
+
Make EventMachine behave like standard Ruby
|
8
|
+
|
9
|
+
== Empathic Threads
|
10
|
+
|
11
|
+
Empathy::EM module uses Fibers to provide Thread, Queue, Mutex, ConditionVariable and MonitorMixin classes that behave like the native ruby ones.
|
12
|
+
|
13
|
+
require 'eventmachine'
|
14
|
+
require 'empathy'
|
15
|
+
|
16
|
+
# start eventmachine and a main EM::Thread
|
17
|
+
Empathy.run do
|
18
|
+
thread = Empathy::EM::Thread.new do
|
19
|
+
my_thread = Empathy::EM::Thread.current
|
20
|
+
|
21
|
+
#local storage
|
22
|
+
Empathy::EM::Thread.current[:my_key] = "some value"
|
23
|
+
|
24
|
+
#pass control elsewhere
|
25
|
+
Empathy::EM::Thread.pass
|
26
|
+
|
27
|
+
Empathy::EM::Kernel.sleep(1)
|
28
|
+
|
29
|
+
1 + 2
|
30
|
+
end
|
31
|
+
|
32
|
+
thread.join
|
33
|
+
thread.value # => 3
|
34
|
+
end
|
35
|
+
|
36
|
+
Almost all Thread behaviour is provided except that one thread will never see another as "running". Where ruby's thread API raises ThreadError, Empathy::EM will raise FiberError.
|
37
|
+
|
38
|
+
== Empathic code outside of the EventMachine reactor
|
39
|
+
|
40
|
+
If your code may run inside or outside the reactor the Empathy module itself provides a set of submodules that delegate to either the native ruby class when called outside of the reactor, or to the Empathy:EM class when called inside the reactor.
|
41
|
+
|
42
|
+
require 'eventmachine'
|
43
|
+
require 'empathy'
|
44
|
+
Empathy::Thread.current.inspect # => "Thread<...>"
|
45
|
+
|
46
|
+
# normal Kernel.sleep
|
47
|
+
Empathy::Thread.sleep(1)
|
48
|
+
|
49
|
+
Empathy.event_machine? # => false
|
50
|
+
|
51
|
+
Empathy.run do
|
52
|
+
|
53
|
+
Empathy.event_machine? # => true
|
54
|
+
|
55
|
+
Empathy::Thread.new do
|
56
|
+
|
57
|
+
Empathy::Thread.current.inspect #=> "Empathy::EM::Thread<...>"
|
58
|
+
|
59
|
+
Empathy::Kernel.sleep(1)
|
60
|
+
|
61
|
+
begin
|
62
|
+
#...do something with threads...
|
63
|
+
rescue Empathy::ThreadError
|
64
|
+
# ...
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Note that since Empathy::Thread and friends are modules, you cannot subclass them
|
70
|
+
|
71
|
+
== Empathise with all ruby code
|
72
|
+
|
73
|
+
Seamlessly Replace Ruby's native classes with the Empathy:EM ones (redefines constants), plus monkey patching of
|
74
|
+
Object#sleep and Object#at_exit
|
75
|
+
|
76
|
+
require 'empathy/thread'
|
77
|
+
# do not run any code that uses threads outside of the reactor after the above require
|
78
|
+
|
79
|
+
Empathy.run do
|
80
|
+
t = Thread.new { 1 + 2 }
|
81
|
+
|
82
|
+
t.inspect # => "Empathy::EM::Thread<.....>"
|
83
|
+
|
84
|
+
# this will be a Fiber+EM sleep, not Kernel.sleep
|
85
|
+
sleep(4)
|
86
|
+
|
87
|
+
t.join
|
88
|
+
end
|
89
|
+
|
90
|
+
Caveat: Take care with code that subclasses Thread. This can work as long as the classes are defined after
|
91
|
+
'empathy/thread' is required.
|
92
|
+
|
93
|
+
Q: But doesn't eventmachine need to use normal threads?
|
94
|
+
A: Indeed, 'empathy/thread' also defines constants in the EventMachine namespace that refer to the original Ruby classes
|
95
|
+
|
96
|
+
== Empathise a library module
|
97
|
+
|
98
|
+
module MyLibary
|
99
|
+
def create_thread
|
100
|
+
Thread.new { Thread.current.inspect }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# If library will only be used inside the reactor
|
105
|
+
Empathy::EM::empathise(MyLibrary)
|
106
|
+
|
107
|
+
# If library is used both inside and outside the reactor
|
108
|
+
Empathy.empathise((MyLibrary)
|
109
|
+
|
110
|
+
In both cases constants are defined in the MyLibrary namespace so that Thread, Queue etc, refer to either Empathy modules
|
111
|
+
or Empathy:EM classes. Note that any call to empathise will have the side-effect of monkey patching Object to provide EM
|
112
|
+
safe #sleep and #at_exit.
|
113
|
+
|
114
|
+
Caveat: MyLibrary must not subclass Thread etc...
|
115
|
+
|
116
|
+
== Empathy::EM::IO - Implement Ruby's Socket API over EventMachine
|
117
|
+
|
118
|
+
Work in progress - see experimental socket-io branch
|
119
|
+
|
120
|
+
== Contributing to empathy
|
121
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
122
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
123
|
+
* Fork the project
|
124
|
+
* Start a feature/bugfix branch
|
125
|
+
* Commit and push until you are happy with your contribution
|
126
|
+
* Make sure to add specs, preferably based on ruby-spec
|
127
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
128
|
+
|
129
|
+
== Copyright
|
130
|
+
|
131
|
+
Copyright (c) 2011 Christopher J. Bottaro. (Original fiber+EM concept in "strand" library)
|
132
|
+
Copyright (c) 2012,2013 Grant Gardner.
|
133
|
+
|
134
|
+
See LICENSE.txt for further details.
|
135
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rdoc/task'
|
6
|
+
require 'rake/clean'
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
RDoc::Task.new do |rdoc|
|
11
|
+
rdoc.main = "README.rdoc"
|
12
|
+
rdoc.rdoc_files.include("README.rdoc", "CHANGELOG","lib/**/*.rb")
|
13
|
+
rdoc.title = "Empathy"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create the test task.
|
17
|
+
desc 'Run mspec'
|
18
|
+
task :mspec do
|
19
|
+
sh "mspec -B empathy.mspec -r 'mspec/empathy' -f spec"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Run specs against ruby
|
23
|
+
desc "Run tests on native ruby"
|
24
|
+
task :mspec_ruby do
|
25
|
+
sh "mspec -B empathy.mspec"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Run tests"
|
29
|
+
task :test => [ :spec, :mspec ]
|
30
|
+
|
31
|
+
task :default => [ :test, :build ]
|
32
|
+
CLOBBER.include [ "pkg/" ]
|
33
|
+
|
data/TESTING.rdoc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
= Empathy Testing
|
2
|
+
|
3
|
+
== Empathy::EM
|
4
|
+
|
5
|
+
Classes in Empathy::EM module are tested using the fully empathic method - replacing Ruby's ::Thread constant with one that points to Empathy::EM::Thread etc, and then running against the subset of rubyspec to do with threads. The rubyspecs are not changed at all. Some tests are skipped (see *.mspec)
|
6
|
+
|
7
|
+
This also tests Empathy.run and the class replacement approach (including subclassing)
|
8
|
+
|
9
|
+
== Empathy module - reactor aware
|
10
|
+
|
11
|
+
We just test that the delegation works as expected, with explicit specs run under rspec
|
data/empathy.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'empathy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "empathy"
|
8
|
+
gem.version = Empathy::VERSION
|
9
|
+
gem.authors = ["Grant Gardner","Christopher J. Bottaro"]
|
10
|
+
gem.email = ["grant@lastweekend.com.au"]
|
11
|
+
gem.description = %q{Empathic Eventmachine}
|
12
|
+
gem.summary = %q{Make EventMachine behave like ruby}
|
13
|
+
gem.homepage = "http://rubygems.org/gems/empathy"
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.test_files = `git ls-files -- {spec,rubyspec}/*`.split($/)
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.licenses = %q{MIT}
|
18
|
+
|
19
|
+
gem.add_development_dependency 'mspec', '>= 1.5.18'
|
20
|
+
gem.add_development_dependency 'rspec'
|
21
|
+
gem.add_development_dependency 'rr'
|
22
|
+
gem.add_development_dependency 'eventmachine', '~> 1.0.0'
|
23
|
+
end
|
data/empathy.mspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'mspec/runner/formatters'
|
4
|
+
|
5
|
+
class MSpecScript
|
6
|
+
# An ordered list of the directories containing specs to run
|
7
|
+
set :files, ['rubyspec']
|
8
|
+
|
9
|
+
# The default implementation to run the specs.
|
10
|
+
set :target, 'ruby'
|
11
|
+
|
12
|
+
irrelevant_class_methods = [
|
13
|
+
"Thread.fork","Thread.allocate","Thread.abort_on_exception","Thread.exclusive"
|
14
|
+
]
|
15
|
+
|
16
|
+
irrelevant_instance_methods = [
|
17
|
+
"Thread#abort_on_exception"
|
18
|
+
]
|
19
|
+
|
20
|
+
# and some intentionally not compliant
|
21
|
+
non_compliant = [
|
22
|
+
"running","interrupt Kernel#sleep","thread group","Mutex#lock raises a ThreadError when used recursively",
|
23
|
+
]
|
24
|
+
|
25
|
+
# Exclude IO specs not relevant to IO::Like
|
26
|
+
set :excludes, irrelevant_class_methods + irrelevant_instance_methods + non_compliant
|
27
|
+
|
28
|
+
# These are options that are passed to the ruby interpreter running the tests
|
29
|
+
# to test io like "-r io/like" must be passed on the command line to mspec
|
30
|
+
set :requires, [
|
31
|
+
"-I", File.expand_path("../lib", __FILE__),
|
32
|
+
"-I", File.expand_path("../mspec/lib", __FILE__),
|
33
|
+
]
|
34
|
+
end
|
data/lib/empathy.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'empathy/version'
|
2
|
+
require 'thread'
|
3
|
+
require 'fiber'
|
4
|
+
|
5
|
+
# This module provides a shim between using standard ruby Threads
|
6
|
+
# and the thread-like behaviour for Fibers provided by classes in
|
7
|
+
# the Empathy::EM module
|
8
|
+
#
|
9
|
+
# # For the Empathy::EM classes to be available
|
10
|
+
# # you must first load EventMachine
|
11
|
+
# 'require eventmachine'
|
12
|
+
#
|
13
|
+
# 'require empathy'
|
14
|
+
#
|
15
|
+
# t = Empathy::Thread.new() do
|
16
|
+
# begin
|
17
|
+
# # "t" is a standard ::Thread
|
18
|
+
# ...something...
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# EventMachine.run do
|
22
|
+
# t = Empathy::Thread.new() do
|
23
|
+
# # "t" is a ::Empathy::EM::Thread
|
24
|
+
# # which wraps a ::Fiber
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # Outside of event machine
|
29
|
+
# t = Empathy::Thread.new() do
|
30
|
+
# # "t" is a raw ::Thread
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# Code using Empathy that may be used in both Fiber or Thread contexts
|
34
|
+
# should take care to rescue *Empathy::Errors which is shorthand for
|
35
|
+
# *[FiberError,ThreadError]
|
36
|
+
#
|
37
|
+
# def maybe_em_method
|
38
|
+
# # some code
|
39
|
+
# rescue *Empathy::Errors
|
40
|
+
#
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# {::Thread} methods not implemented by Empathy
|
44
|
+
# * #exclusive - not implemented
|
45
|
+
# * #critical - not implemented
|
46
|
+
# * #set_trace_func - not implemented
|
47
|
+
# * #safe_level - not implemented
|
48
|
+
# * #priority - not implemented
|
49
|
+
module Empathy
|
50
|
+
|
51
|
+
class ThreadError < StandardError
|
52
|
+
def self.===(other)
|
53
|
+
super || ::FiberError === other || ::ThreadError === other
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Start EventMachine and run reactor block within a surrounding Empathy::EM::Thread (Fiber).
|
58
|
+
# The reactor loop is terminated when the supplied block finishes
|
59
|
+
def self.run
|
60
|
+
reload()
|
61
|
+
exception = nil
|
62
|
+
value = nil
|
63
|
+
EventMachine.run do
|
64
|
+
EM::Thread.new do
|
65
|
+
begin
|
66
|
+
value = yield
|
67
|
+
rescue Exception => ex
|
68
|
+
exception = ex
|
69
|
+
ensure
|
70
|
+
EventMachine.stop
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
raise exception if exception
|
75
|
+
value
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.empathise(*modules)
|
79
|
+
modules.each do |m|
|
80
|
+
map_classes(m, self, "Thread","Queue","Mutex","ConditionVariable", "ThreadError")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#@api private
|
85
|
+
def self.map_classes(into,from,*class_names)
|
86
|
+
# Make Object reactor aware
|
87
|
+
require 'empathy/object'
|
88
|
+
class_names.each do |cname|
|
89
|
+
case cname
|
90
|
+
when Hash
|
91
|
+
cname.each { |cn,replace_class| replace_class_constant(into,cn,replace_class) }
|
92
|
+
else
|
93
|
+
replace_class_constant(into,cname,from.const_get(cname))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.replace_class_constant(into,cname,replace_class)
|
99
|
+
if into != Object && into.const_defined?(cname,false)
|
100
|
+
existing_const = into.const_get(cname)
|
101
|
+
if !existing_const.is_a?(Module) || existing_const.name.start_with?(into.name)
|
102
|
+
warn "mmpathy: Skipping replacement of #{into.name}::#{cname}"
|
103
|
+
return nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
warn "empathy: Defined fake class constant #{into}::#{cname} => #{replace_class.name}"
|
108
|
+
into.const_set(cname,replace_class)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Test whether we have real fibers or a thread based fiber implmentation
|
112
|
+
t = Thread.current
|
113
|
+
ft = nil
|
114
|
+
Fiber.new { ft = Thread.current }.resume
|
115
|
+
|
116
|
+
ROOT_FIBER = Fiber.current
|
117
|
+
REAL_FIBERS = ( t == ft )
|
118
|
+
|
119
|
+
# Specifically try to enable use of Eventmachine if it is now available
|
120
|
+
def self.reload()
|
121
|
+
@loaded ||= false
|
122
|
+
if !@loaded && defined?(EventMachine)
|
123
|
+
require 'empathy/em/thread.rb'
|
124
|
+
require 'empathy/em/queue.rb'
|
125
|
+
@loaded = true
|
126
|
+
end
|
127
|
+
return @loaded
|
128
|
+
end
|
129
|
+
|
130
|
+
# If EM already required then enable it, otherwise defer until first use
|
131
|
+
reload()
|
132
|
+
|
133
|
+
# Are we running in the EventMachine reactor thread
|
134
|
+
#
|
135
|
+
# For JRuby or other interpreters where fibers are implemented with threads
|
136
|
+
# this will return true if the reactor is running and the code is called from
|
137
|
+
# *any* fiber other than the root fiber
|
138
|
+
def self.event_machine?
|
139
|
+
@loaded ||= false
|
140
|
+
@loaded && EventMachine.reactor_running? &&
|
141
|
+
( EventMachine.reactor_thread? || (!REAL_FIBERS && ROOT_FIBER != Fiber.current))
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def self.create_delegate_module(cname,*methods)
|
146
|
+
mod = Module.new
|
147
|
+
self.const_set(cname,mod)
|
148
|
+
methods.each do |m|
|
149
|
+
mod.define_singleton_method(m) do |*args,&block|
|
150
|
+
parent = Empathy.event_machine? ? Empathy::EM : Object
|
151
|
+
delegate = parent.const_get(cname)
|
152
|
+
delegate.send(m,*args,&block)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
create_delegate_module('Kernel',:sleep,:at_exit)
|
158
|
+
create_delegate_module('Thread',:new, :list, :current, :stop, :pass, :main)
|
159
|
+
create_delegate_module('Queue',:new)
|
160
|
+
create_delegate_module('ConditionVariable',:new)
|
161
|
+
create_delegate_module('Mutex',:new)
|
162
|
+
end
|