celluloid 0.12.1.pre → 0.12.1.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/celluloid.rb +22 -3
- data/lib/celluloid/actor.rb +15 -12
- data/lib/celluloid/boot.rb +4 -2
- data/lib/celluloid/fsm.rb +49 -16
- data/lib/celluloid/logging.rb +5 -0
- data/lib/celluloid/logging/incident.rb +21 -0
- data/lib/celluloid/logging/incident_logger.rb +129 -0
- data/lib/celluloid/logging/incident_reporter.rb +48 -0
- data/lib/celluloid/logging/log_event.rb +20 -0
- data/lib/celluloid/logging/ring_buffer.rb +65 -0
- data/lib/celluloid/stack_dumper.rb +45 -0
- data/lib/celluloid/task.rb +4 -1
- data/lib/celluloid/thread_handle.rb +5 -0
- data/lib/celluloid/version.rb +1 -1
- data/spec/support/actor_examples.rb +8 -0
- metadata +52 -35
- data/lib/celluloid/cpu_counter.rb +0 -18
data/lib/celluloid.rb
CHANGED
@@ -2,6 +2,7 @@ require 'logger'
|
|
2
2
|
require 'thread'
|
3
3
|
require 'timeout'
|
4
4
|
require 'set'
|
5
|
+
require 'facter'
|
5
6
|
|
6
7
|
module Celluloid
|
7
8
|
extend self # expose all instance methods as singleton methods
|
@@ -33,11 +34,18 @@ module Celluloid
|
|
33
34
|
|
34
35
|
# Obtain the number of CPUs in the system
|
35
36
|
def cores
|
36
|
-
|
37
|
+
core_count = Facter.fact(:processorcount).value
|
38
|
+
Integer(core_count)
|
37
39
|
end
|
38
40
|
alias_method :cpus, :cores
|
39
41
|
alias_method :ncpus, :cores
|
40
42
|
|
43
|
+
# Perform a stack dump of all actors to the given output object
|
44
|
+
def stack_dump(output = STDERR)
|
45
|
+
Celluloid::StackDumper.dump(output)
|
46
|
+
end
|
47
|
+
alias_method :dump, :stack_dump
|
48
|
+
|
41
49
|
# Define an exception handler for actor crashes
|
42
50
|
def exception_handler(&block)
|
43
51
|
Logger.exception_handler(&block)
|
@@ -73,7 +81,17 @@ module Celluloid
|
|
73
81
|
end
|
74
82
|
|
75
83
|
# Terminate all actors at exit
|
76
|
-
at_exit
|
84
|
+
at_exit do
|
85
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
|
86
|
+
# workaround for MRI bug losing exit status in at_exit block
|
87
|
+
# http://bugs.ruby-lang.org/issues/5218
|
88
|
+
exit_status = $!.status if $!.is_a?(SystemExit)
|
89
|
+
shutdown
|
90
|
+
exit exit_status if exit_status
|
91
|
+
else
|
92
|
+
shutdown
|
93
|
+
end
|
94
|
+
end
|
77
95
|
|
78
96
|
# Class methods added to classes which include Celluloid
|
79
97
|
module ClassMethods
|
@@ -402,7 +420,6 @@ require 'celluloid/version'
|
|
402
420
|
|
403
421
|
require 'celluloid/calls'
|
404
422
|
require 'celluloid/core_ext'
|
405
|
-
require 'celluloid/cpu_counter'
|
406
423
|
require 'celluloid/fiber'
|
407
424
|
require 'celluloid/fsm'
|
408
425
|
require 'celluloid/internal_pool'
|
@@ -414,6 +431,7 @@ require 'celluloid/receivers'
|
|
414
431
|
require 'celluloid/registry'
|
415
432
|
require 'celluloid/responses'
|
416
433
|
require 'celluloid/signals'
|
434
|
+
require 'celluloid/stack_dumper'
|
417
435
|
require 'celluloid/system_events'
|
418
436
|
require 'celluloid/task'
|
419
437
|
require 'celluloid/thread_handle'
|
@@ -430,5 +448,6 @@ require 'celluloid/pool_manager'
|
|
430
448
|
require 'celluloid/supervision_group'
|
431
449
|
require 'celluloid/supervisor'
|
432
450
|
require 'celluloid/notifications'
|
451
|
+
require 'celluloid/logging'
|
433
452
|
|
434
453
|
require 'celluloid/boot'
|
data/lib/celluloid/actor.rb
CHANGED
@@ -65,11 +65,9 @@ module Celluloid
|
|
65
65
|
raise DeadActorError, "attempted to call a dead actor"
|
66
66
|
end
|
67
67
|
|
68
|
-
if
|
69
|
-
# The current task will be automatically resumed when we get a response
|
68
|
+
if Thread.current[:task]
|
70
69
|
Task.suspend(:callwait).value
|
71
70
|
else
|
72
|
-
# Otherwise we're inside a normal thread or exclusive, so block
|
73
71
|
response = loop do
|
74
72
|
message = Thread.mailbox.receive do |msg|
|
75
73
|
msg.respond_to?(:call) and msg.call == call
|
@@ -221,10 +219,16 @@ module Celluloid
|
|
221
219
|
|
222
220
|
# Execute a code block in exclusive mode.
|
223
221
|
def exclusive
|
224
|
-
@exclusive
|
225
|
-
|
226
|
-
|
227
|
-
|
222
|
+
if @exclusive
|
223
|
+
yield
|
224
|
+
else
|
225
|
+
begin
|
226
|
+
@exclusive = true
|
227
|
+
yield
|
228
|
+
ensure
|
229
|
+
@exclusive = false
|
230
|
+
end
|
231
|
+
end
|
228
232
|
end
|
229
233
|
|
230
234
|
# Perform a linking request with another actor
|
@@ -302,12 +306,11 @@ module Celluloid
|
|
302
306
|
|
303
307
|
# Sleep for the given amount of time
|
304
308
|
def sleep(interval)
|
305
|
-
if
|
306
|
-
Kernel.sleep(interval)
|
307
|
-
else
|
308
|
-
task = Task.current
|
309
|
+
if task = Thread.current[:task]
|
309
310
|
@timers.after(interval) { task.resume }
|
310
311
|
Task.suspend :sleeping
|
312
|
+
else
|
313
|
+
Kernel.sleep(interval)
|
311
314
|
end
|
312
315
|
end
|
313
316
|
|
@@ -389,7 +392,7 @@ module Celluloid
|
|
389
392
|
if @exclusives && (@exclusives == :all || @exclusives.include?(method_name))
|
390
393
|
exclusive { block.call }
|
391
394
|
else
|
392
|
-
@task_class.new(
|
395
|
+
@task_class.new(task_type, &block).resume
|
393
396
|
end
|
394
397
|
end
|
395
398
|
end
|
data/lib/celluloid/boot.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Things to run after Celluloid is fully loaded
|
2
2
|
|
3
3
|
# Configure default systemwide settings
|
4
|
-
Celluloid.logger = Logger.new STDERR
|
5
4
|
Celluloid.task_class = Celluloid::TaskFiber
|
6
5
|
|
7
6
|
# Launch the notifications fanout actor
|
8
7
|
# FIXME: We should set up the supervision hierarchy here
|
9
|
-
Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
|
8
|
+
Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
|
9
|
+
|
10
|
+
Celluloid.logger = Celluloid::IncidentLogger.new
|
11
|
+
Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
|
data/lib/celluloid/fsm.rb
CHANGED
@@ -84,30 +84,71 @@ module Celluloid
|
|
84
84
|
#
|
85
85
|
# Note: making additional state transitions will cancel delayed transitions
|
86
86
|
def transition(state_name, options = {})
|
87
|
+
new_state = validate_and_sanitize_new_state(state_name)
|
88
|
+
return unless new_state
|
89
|
+
|
90
|
+
if handle_delayed_transitions(new_state, options[:delay])
|
91
|
+
return @delayed_transition
|
92
|
+
end
|
93
|
+
|
94
|
+
transition_with_callbacks!(new_state)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Immediate state transition with no sanity checks, or callbacks. "Dangerous!"
|
98
|
+
def transition!(state_name)
|
99
|
+
@state = state_name
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def validate_and_sanitize_new_state(state_name)
|
87
105
|
state_name = state_name.to_sym
|
88
|
-
current_state = self.class.states[@state]
|
89
106
|
|
90
|
-
return if
|
107
|
+
return if current_state_name == state_name
|
91
108
|
|
92
109
|
if current_state and not current_state.valid_transition? state_name
|
93
110
|
valid = current_state.transitions.map(&:to_s).join(", ")
|
94
111
|
raise ArgumentError, "#{self.class} can't change state from '#{@state}' to '#{state_name}', only to: #{valid}"
|
95
112
|
end
|
96
113
|
|
97
|
-
new_state =
|
114
|
+
new_state = states[state_name]
|
98
115
|
|
99
116
|
unless new_state
|
100
|
-
return if state_name ==
|
117
|
+
return if state_name == default_state
|
101
118
|
raise ArgumentError, "invalid state for #{self.class}: #{state_name}"
|
102
119
|
end
|
103
120
|
|
104
|
-
|
121
|
+
new_state
|
122
|
+
end
|
123
|
+
|
124
|
+
def transition_with_callbacks!(state_name)
|
125
|
+
transition! state_name.name
|
126
|
+
state_name.call(self)
|
127
|
+
end
|
128
|
+
|
129
|
+
def states
|
130
|
+
self.class.states
|
131
|
+
end
|
132
|
+
|
133
|
+
def default_state
|
134
|
+
self.class.default_state
|
135
|
+
end
|
136
|
+
|
137
|
+
def current_state
|
138
|
+
states[@state]
|
139
|
+
end
|
140
|
+
|
141
|
+
def current_state_name
|
142
|
+
current_state && current_state.name || ''
|
143
|
+
end
|
144
|
+
|
145
|
+
def handle_delayed_transitions(new_state, delay)
|
146
|
+
if delay
|
105
147
|
raise UnattachedError, "can't delay unless attached" unless @actor
|
106
148
|
@delayed_transition.cancel if @delayed_transition
|
107
149
|
|
108
|
-
@delayed_transition = @actor.after(
|
109
|
-
|
110
|
-
new_state.call(self)
|
150
|
+
@delayed_transition = @actor.after(delay) do
|
151
|
+
transition_with_callbacks!(new_state)
|
111
152
|
end
|
112
153
|
|
113
154
|
return @delayed_transition
|
@@ -117,14 +158,6 @@ module Celluloid
|
|
117
158
|
@delayed_transition.cancel
|
118
159
|
@delayed_transition = nil
|
119
160
|
end
|
120
|
-
|
121
|
-
transition! new_state.name
|
122
|
-
new_state.call(self)
|
123
|
-
end
|
124
|
-
|
125
|
-
# Immediate state transition with no sanity checks. "Dangerous!"
|
126
|
-
def transition!(state_name)
|
127
|
-
@state = state_name
|
128
161
|
end
|
129
162
|
|
130
163
|
# FSM states as declared by Celluloid::FSM.state
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# Wraps all events and context for a single incident.
|
3
|
+
class Incident
|
4
|
+
attr_accessor :pid
|
5
|
+
attr_accessor :events, :triggering_event
|
6
|
+
|
7
|
+
def initialize(events, triggering_event=nil)
|
8
|
+
@events = events
|
9
|
+
@triggering_event = triggering_event
|
10
|
+
@pid = $$
|
11
|
+
end
|
12
|
+
|
13
|
+
# Merge two incidents together. This may be useful if two incidents occur at the same time.
|
14
|
+
def merge(*other_incidents)
|
15
|
+
merged_events = other_incidents.flatten.inject(events) do |events, incident|
|
16
|
+
events += incident.events
|
17
|
+
end
|
18
|
+
Incident.new(merged_events.sort, triggering_event)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Celluloid
|
3
|
+
# A logger that holds all messages in circular buffers, then flushes the buffers
|
4
|
+
# when an event occurs at a configurable severity threshold.
|
5
|
+
#
|
6
|
+
# Unlike ruby's Logger, this class only supports a single progname.
|
7
|
+
class IncidentLogger
|
8
|
+
module Severity
|
9
|
+
include ::Logger::Severity
|
10
|
+
|
11
|
+
TRACE = -1
|
12
|
+
|
13
|
+
def severity_to_string(severity)
|
14
|
+
case severity
|
15
|
+
when TRACE then 'TRACE'
|
16
|
+
when DEBUG then 'DEBUG'
|
17
|
+
when INFO then 'INFO'
|
18
|
+
when WARN then 'WARN'
|
19
|
+
when ERROR then 'ERROR'
|
20
|
+
when FATAL then 'FATAL'
|
21
|
+
when UNKNOWN then 'UNKNOWN'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
include Severity
|
27
|
+
|
28
|
+
# The progname (facility) for this instance.
|
29
|
+
attr_accessor :progname
|
30
|
+
|
31
|
+
# The logging level. Messages below this severity will not be logged at all.
|
32
|
+
attr_accessor :level
|
33
|
+
|
34
|
+
# The incident threshold. Messages at or above this severity will generate an
|
35
|
+
# incident and be published to incident reporters.
|
36
|
+
attr_accessor :threshold
|
37
|
+
|
38
|
+
# The buffer size limit. Each log level will retain this number of messages
|
39
|
+
# at maximum.
|
40
|
+
attr_accessor :sizelimit
|
41
|
+
|
42
|
+
attr_accessor :buffers
|
43
|
+
|
44
|
+
# Create a new IncidentLogger.
|
45
|
+
def initialize(progname=nil, options={})
|
46
|
+
@progname = progname || "default"
|
47
|
+
@level = options[:level] || DEBUG
|
48
|
+
@threshold = options[:threshold] || ERROR
|
49
|
+
@sizelimit = options[:sizelimit] || 100
|
50
|
+
|
51
|
+
@buffer_mutex = Mutex.new
|
52
|
+
@buffers = Hash.new do |progname_hash, progname|
|
53
|
+
@buffer_mutex.synchronize do
|
54
|
+
progname_hash[progname] = Hash.new do |severity_hash, severity|
|
55
|
+
severity_hash[severity] = RingBuffer.new(@sizelimit)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# When the IncidentLogger itself encounters an error, it falls back to logging to stderr
|
61
|
+
@fallback_logger = ::Logger.new(STDERR)
|
62
|
+
@fallback_logger.progname = "FALLBACK"
|
63
|
+
end
|
64
|
+
|
65
|
+
# add an event.
|
66
|
+
def add(severity, message=nil, progname=nil, &block)
|
67
|
+
progname ||= @progname
|
68
|
+
severity ||= UNKNOWN
|
69
|
+
|
70
|
+
if severity < @level
|
71
|
+
return event.id
|
72
|
+
end
|
73
|
+
|
74
|
+
if message.nil? && !block_given?
|
75
|
+
message = progname
|
76
|
+
progname = @progname
|
77
|
+
end
|
78
|
+
|
79
|
+
event = LogEvent.new(severity, message, progname, &block)
|
80
|
+
|
81
|
+
@buffers[progname][severity] << event
|
82
|
+
|
83
|
+
if severity >= @threshold
|
84
|
+
begin
|
85
|
+
Celluloid::Notifications.notifier.async.publish(incident_topic, create_incident(event))
|
86
|
+
rescue => ex
|
87
|
+
@fallback_logger.error(ex)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
event.id
|
91
|
+
end
|
92
|
+
alias :log :add
|
93
|
+
|
94
|
+
# See docs for Logger#info
|
95
|
+
def trace (progname=nil, &block); add(TRACE, nil, progname, &block); end
|
96
|
+
def debug (progname=nil, &block); add(DEBUG, nil, progname, &block); end
|
97
|
+
def info (progname=nil, &block); add(INFO, nil, progname, &block); end
|
98
|
+
def warn (progname=nil, &block); add(WARN, nil, progname, &block); end
|
99
|
+
def error (progname=nil, &block); add(ERROR, nil, progname, &block); end
|
100
|
+
def fatal (progname=nil, &block); add(FATAL, nil, progname, &block); end
|
101
|
+
def unknown (progname=nil, &block); add(UNKNOWN, nil, progname, &block); end
|
102
|
+
|
103
|
+
def flush
|
104
|
+
messages = []
|
105
|
+
@buffer_mutex.synchronize do
|
106
|
+
@buffers.each do |progname, severities|
|
107
|
+
severities.each do |severity, buffer|
|
108
|
+
messages += buffer.flush
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
messages.sort
|
113
|
+
end
|
114
|
+
|
115
|
+
def clear
|
116
|
+
@buffer_mutex.synchronize do
|
117
|
+
@buffers.each { |buffer| buffer.clear }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def create_incident(event=nil)
|
122
|
+
Incident.new(flush, event)
|
123
|
+
end
|
124
|
+
|
125
|
+
def incident_topic
|
126
|
+
"log.incident.#{@progname}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Celluloid
|
3
|
+
# Subscribes to log incident topics to report on them.
|
4
|
+
class IncidentReporter
|
5
|
+
include Celluloid
|
6
|
+
include Celluloid::Notifications
|
7
|
+
|
8
|
+
# get the time from the event
|
9
|
+
class Formatter < ::Logger::Formatter
|
10
|
+
def call(severity, time, progname, msg)
|
11
|
+
super(severity, msg.time, progname, msg.message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
subscribe(/log\.incident/, :report)
|
17
|
+
@logger = ::Logger.new(*args)
|
18
|
+
@logger.formatter = Formatter.new
|
19
|
+
@silenced = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def report(topic, incident)
|
23
|
+
return if @silenced
|
24
|
+
|
25
|
+
header = "INCIDENT"
|
26
|
+
header << " AT #{incident.triggering_event.time}" if incident.triggering_event
|
27
|
+
@logger << header
|
28
|
+
@logger << "\n"
|
29
|
+
@logger << "====================\n"
|
30
|
+
incident.events.each do |event|
|
31
|
+
@logger.add(event.severity, event, event.progname)
|
32
|
+
end
|
33
|
+
@logger << "====================\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def silence
|
37
|
+
@silenced = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def unsilence
|
41
|
+
@silenced = false
|
42
|
+
end
|
43
|
+
|
44
|
+
def silenced?
|
45
|
+
@silenced
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# Wraps a single log event.
|
3
|
+
class LogEvent
|
4
|
+
attr_accessor :id, :severity, :message, :progname, :time
|
5
|
+
|
6
|
+
def initialize(severity, message, progname, time=Time.now, &block)
|
7
|
+
# This id should be ordered. For now relies on Celluloid::UUID to be ordered.
|
8
|
+
# May want to use a generation/counter strategy for independence of uuid.
|
9
|
+
@id = Celluloid::UUID.generate
|
10
|
+
@severity = severity
|
11
|
+
@message = block_given? ? yield : message
|
12
|
+
@progname = progname
|
13
|
+
@time = time
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
@id <=> other.id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Celluloid
|
2
|
+
class RingBuffer
|
3
|
+
def initialize(size)
|
4
|
+
@size = size
|
5
|
+
@start = 0
|
6
|
+
@count = 0
|
7
|
+
@buffer = Array.new(size)
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def full?
|
12
|
+
@count == @size
|
13
|
+
end
|
14
|
+
|
15
|
+
def empty?
|
16
|
+
@count == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def push(value)
|
20
|
+
@mutex.synchronize do
|
21
|
+
stop = (@start + @count) % @size
|
22
|
+
@buffer[stop] = value
|
23
|
+
if full?
|
24
|
+
@start = (@start + 1) % @size
|
25
|
+
else
|
26
|
+
@count += 1
|
27
|
+
end
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias :<< :push
|
32
|
+
|
33
|
+
def shift
|
34
|
+
@mutex.synchronize do
|
35
|
+
remove_element
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def flush
|
40
|
+
values = []
|
41
|
+
@mutex.synchronize do
|
42
|
+
while !empty?
|
43
|
+
values << remove_element
|
44
|
+
end
|
45
|
+
end
|
46
|
+
values
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear
|
50
|
+
@buffer = Array.new(@size)
|
51
|
+
@start = 0
|
52
|
+
@count = 0
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def remove_element
|
58
|
+
return nil if empty?
|
59
|
+
value, @buffer[@start] = @buffer[@start], nil
|
60
|
+
@start = (@start + 1) % @size
|
61
|
+
@count -= 1
|
62
|
+
value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Celluloid
|
2
|
+
module StackDumper
|
3
|
+
def self.dump(output = STDERR)
|
4
|
+
actors = {}
|
5
|
+
threads = []
|
6
|
+
|
7
|
+
Thread.list.each do |thread|
|
8
|
+
if actor = thread[:actor]
|
9
|
+
actors[actor.subject.object_id] = actor
|
10
|
+
else
|
11
|
+
threads << thread
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
actors.each do |_, actor|
|
16
|
+
output << "Celluloid::Actor 0x#{actor.subject.object_id.to_s(16)}: #{actor.subject.class}"
|
17
|
+
output << " [#{actor.name}]" if actor.name
|
18
|
+
output << "\n"
|
19
|
+
|
20
|
+
tasks = actor.tasks
|
21
|
+
if tasks.empty?
|
22
|
+
output << "State: Idle (waiting for messages)\n"
|
23
|
+
else
|
24
|
+
output << "State: Running (executing tasks)\n"
|
25
|
+
output << "Tasks:\n"
|
26
|
+
|
27
|
+
tasks.each_with_index do |task, i|
|
28
|
+
output << " #{i+1}) #{task.class}: #{task.status}\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
display_backtrace actor.thread, output
|
33
|
+
end
|
34
|
+
|
35
|
+
threads.each do |thread|
|
36
|
+
output << "Thread 0x#{object_id.to_s(16)}:\n"
|
37
|
+
display_backtrace thread, output
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.display_backtrace(thread, output)
|
42
|
+
output << "\t" << thread.backtrace.join("\n\t") << "\n\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/celluloid/task.rb
CHANGED
@@ -2,6 +2,9 @@ require 'celluloid/tasks/task_fiber'
|
|
2
2
|
require 'celluloid/tasks/task_thread'
|
3
3
|
|
4
4
|
module Celluloid
|
5
|
+
# Asked to do task-related things outside a task
|
6
|
+
class NotTaskError < StandardError; end
|
7
|
+
|
5
8
|
# Trying to resume a dead task
|
6
9
|
class DeadTaskError < StandardError; end
|
7
10
|
|
@@ -11,7 +14,7 @@ module Celluloid
|
|
11
14
|
|
12
15
|
# Obtain the current task
|
13
16
|
def self.current
|
14
|
-
Thread.current[:task] or raise "not within a task context"
|
17
|
+
Thread.current[:task] or raise NotTaskError, "not within a task context"
|
15
18
|
end
|
16
19
|
|
17
20
|
# Suspend the running task, deferring to the scheduler
|
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Celluloid
|
2
4
|
# An abstraction around threads from the InternalPool which ensures we don't
|
3
5
|
# accidentally do things to threads which have been returned to the pool,
|
4
6
|
# such as, say, killing them
|
5
7
|
class ThreadHandle
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :@thread, :backtrace
|
10
|
+
|
6
11
|
def initialize
|
7
12
|
@mutex = Mutex.new
|
8
13
|
@join = ConditionVariable.new
|
data/lib/celluloid/version.rb
CHANGED
@@ -422,12 +422,20 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
422
422
|
exclusive?
|
423
423
|
end
|
424
424
|
exclusive :exclusive_example
|
425
|
+
|
426
|
+
def nested_exclusive_example
|
427
|
+
exclusive { exclusive { nil }; Celluloid.exclusive? }
|
428
|
+
end
|
425
429
|
end.new
|
426
430
|
end
|
427
431
|
|
428
432
|
it "supports exclusive methods" do
|
429
433
|
subject.exclusive_example.should be_true
|
430
434
|
end
|
435
|
+
|
436
|
+
it "remains in exclusive mode inside nested blocks" do
|
437
|
+
subject.nested_exclusive_example.should be_true
|
438
|
+
end
|
431
439
|
end
|
432
440
|
|
433
441
|
context "exclusive classes" do
|
metadata
CHANGED
@@ -1,62 +1,72 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: celluloid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.1.pre
|
5
4
|
prerelease: 7
|
5
|
+
version: 0.12.1.pre2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tony Arcieri
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-10 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: timers
|
16
|
-
|
17
|
-
none: false
|
16
|
+
version_requirements: &2056 !ruby/object:Gem::Requirement
|
18
17
|
requirements:
|
19
18
|
- - ! '>='
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: 1.0.0
|
21
|
+
none: false
|
22
|
+
requirement: *2056
|
23
|
+
prerelease: false
|
22
24
|
type: :runtime
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: facter
|
27
|
+
version_requirements: &2074 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.6.12
|
32
|
+
none: false
|
33
|
+
requirement: *2074
|
23
34
|
prerelease: false
|
24
|
-
|
35
|
+
type: :runtime
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: rake
|
27
|
-
|
28
|
-
none: false
|
38
|
+
version_requirements: &2090 !ruby/object:Gem::Requirement
|
29
39
|
requirements:
|
30
40
|
- - ! '>='
|
31
41
|
- !ruby/object:Gem::Version
|
32
42
|
version: '0'
|
33
|
-
|
43
|
+
none: false
|
44
|
+
requirement: *2090
|
34
45
|
prerelease: false
|
35
|
-
|
46
|
+
type: :development
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: rspec
|
38
|
-
|
39
|
-
none: false
|
49
|
+
version_requirements: &2108 !ruby/object:Gem::Requirement
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
42
52
|
- !ruby/object:Gem::Version
|
43
53
|
version: '0'
|
44
|
-
|
54
|
+
none: false
|
55
|
+
requirement: *2108
|
45
56
|
prerelease: false
|
46
|
-
|
57
|
+
type: :development
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: benchmark_suite
|
49
|
-
|
50
|
-
none: false
|
60
|
+
version_requirements: &2124 !ruby/object:Gem::Requirement
|
51
61
|
requirements:
|
52
62
|
- - ! '>='
|
53
63
|
- !ruby/object:Gem::Version
|
54
64
|
version: '0'
|
55
|
-
|
65
|
+
none: false
|
66
|
+
requirement: *2124
|
56
67
|
prerelease: false
|
57
|
-
|
58
|
-
description: Celluloid enables people to build concurrent programs out of concurrent
|
59
|
-
objects just as easily as they build sequential programs out of sequential objects
|
68
|
+
type: :development
|
69
|
+
description: Celluloid enables people to build concurrent programs out of concurrent objects just as easily as they build sequential programs out of sequential objects
|
60
70
|
email:
|
61
71
|
- tony.arcieri@gmail.com
|
62
72
|
executables: []
|
@@ -64,40 +74,46 @@ extensions: []
|
|
64
74
|
extra_rdoc_files: []
|
65
75
|
files:
|
66
76
|
- README.md
|
77
|
+
- lib/celluloid.rb
|
67
78
|
- lib/celluloid/actor.rb
|
68
79
|
- lib/celluloid/boot.rb
|
69
80
|
- lib/celluloid/calls.rb
|
70
81
|
- lib/celluloid/core_ext.rb
|
71
|
-
- lib/celluloid/cpu_counter.rb
|
72
82
|
- lib/celluloid/fiber.rb
|
73
83
|
- lib/celluloid/fsm.rb
|
74
84
|
- lib/celluloid/future.rb
|
75
85
|
- lib/celluloid/internal_pool.rb
|
76
86
|
- lib/celluloid/links.rb
|
77
87
|
- lib/celluloid/logger.rb
|
88
|
+
- lib/celluloid/logging.rb
|
78
89
|
- lib/celluloid/mailbox.rb
|
79
90
|
- lib/celluloid/method.rb
|
80
91
|
- lib/celluloid/notifications.rb
|
81
92
|
- lib/celluloid/pool_manager.rb
|
82
|
-
- lib/celluloid/proxies/abstract_proxy.rb
|
83
|
-
- lib/celluloid/proxies/actor_proxy.rb
|
84
|
-
- lib/celluloid/proxies/async_proxy.rb
|
85
|
-
- lib/celluloid/proxies/future_proxy.rb
|
86
93
|
- lib/celluloid/receivers.rb
|
87
94
|
- lib/celluloid/registry.rb
|
88
95
|
- lib/celluloid/responses.rb
|
89
96
|
- lib/celluloid/rspec.rb
|
90
97
|
- lib/celluloid/signals.rb
|
98
|
+
- lib/celluloid/stack_dumper.rb
|
91
99
|
- lib/celluloid/supervision_group.rb
|
92
100
|
- lib/celluloid/supervisor.rb
|
93
101
|
- lib/celluloid/system_events.rb
|
94
102
|
- lib/celluloid/task.rb
|
95
|
-
- lib/celluloid/tasks/task_fiber.rb
|
96
|
-
- lib/celluloid/tasks/task_thread.rb
|
97
103
|
- lib/celluloid/thread_handle.rb
|
98
104
|
- lib/celluloid/uuid.rb
|
99
105
|
- lib/celluloid/version.rb
|
100
|
-
- lib/celluloid.rb
|
106
|
+
- lib/celluloid/logging/incident.rb
|
107
|
+
- lib/celluloid/logging/incident_logger.rb
|
108
|
+
- lib/celluloid/logging/incident_reporter.rb
|
109
|
+
- lib/celluloid/logging/log_event.rb
|
110
|
+
- lib/celluloid/logging/ring_buffer.rb
|
111
|
+
- lib/celluloid/proxies/abstract_proxy.rb
|
112
|
+
- lib/celluloid/proxies/actor_proxy.rb
|
113
|
+
- lib/celluloid/proxies/async_proxy.rb
|
114
|
+
- lib/celluloid/proxies/future_proxy.rb
|
115
|
+
- lib/celluloid/tasks/task_fiber.rb
|
116
|
+
- lib/celluloid/tasks/task_thread.rb
|
101
117
|
- spec/support/actor_examples.rb
|
102
118
|
- spec/support/example_actor_class.rb
|
103
119
|
- spec/support/mailbox_examples.rb
|
@@ -105,27 +121,28 @@ files:
|
|
105
121
|
homepage: https://github.com/celluloid/celluloid
|
106
122
|
licenses:
|
107
123
|
- MIT
|
108
|
-
post_install_message:
|
124
|
+
post_install_message:
|
109
125
|
rdoc_options: []
|
110
126
|
require_paths:
|
111
127
|
- lib
|
112
128
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
129
|
requirements:
|
115
130
|
- - ! '>='
|
116
131
|
- !ruby/object:Gem::Version
|
117
132
|
version: 1.9.2
|
118
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
133
|
none: false
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
135
|
requirements:
|
121
136
|
- - ! '>='
|
122
137
|
- !ruby/object:Gem::Version
|
123
138
|
version: 1.3.6
|
139
|
+
none: false
|
124
140
|
requirements: []
|
125
|
-
rubyforge_project:
|
126
|
-
rubygems_version: 1.8.
|
127
|
-
signing_key:
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 1.8.15
|
143
|
+
signing_key:
|
128
144
|
specification_version: 3
|
129
145
|
summary: Actor-based concurrent object framework for Ruby
|
130
146
|
test_files: []
|
131
|
-
has_rdoc:
|
147
|
+
has_rdoc:
|
148
|
+
...
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rbconfig'
|
2
|
-
|
3
|
-
module Celluloid
|
4
|
-
module CPUCounter
|
5
|
-
case RbConfig::CONFIG['host_os'][/^[A-Za-z]+/]
|
6
|
-
when 'darwin'
|
7
|
-
@cores = Integer(`sysctl hw.ncpu`[/\d+/])
|
8
|
-
when 'linux'
|
9
|
-
@cores = File.read("/proc/cpuinfo").scan(/core id\s+: \d+/).uniq.size
|
10
|
-
when 'mingw', 'mswin'
|
11
|
-
@cores = Integer(`SET NUMBER_OF_PROCESSORS`[/\d+/])
|
12
|
-
else
|
13
|
-
@cores = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.cores; @cores; end
|
17
|
-
end
|
18
|
-
end
|