~ubuntu-branches/ubuntu/trusty/jruby/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/ruby/1.8/singleton.rb

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Delafond
  • Date: 2009-12-10 12:34:42 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20091210123442-df7t1v36qtfkj5df
Tags: 1.4.0-1
* New upstream release.
* Updated watch file.
* Updated copyright file to reflect addition of new third-party jars.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
# *  Klass.new and Klass.allocate - as private
31
31
#
32
32
# Providing (or modifying) the class methods
33
 
# *  Klass.inherited(sub_klass) and Klass.clone()  - 
 
33
# *  Klass.inherited(sub_klass) and Klass.clone()  -
34
34
#    to ensure that the Singleton pattern is properly
35
35
#    inherited and cloned.
36
36
#
44
44
#
45
45
# *  Klass._load(str)  -  calling Klass.instance()
46
46
#
 
47
# *  Klass._instantiate?()  -  returning ``the instance'' or
 
48
#    nil. This hook method puts a second (or nth) thread calling
 
49
#    Klass.instance() on a waiting loop. The return value
 
50
#    signifies the successful completion or premature termination
 
51
#    of the first, or more generally, current "instantiation thread".
 
52
#
47
53
#
48
54
# The instance method of Singleton are
49
55
# * clone and dup - raising TypeErrors to prevent cloning or duping
54
60
#    and _dump(depth) hooks allows the (partially) resurrections of
55
61
#    a previous state of ``the instance''.
56
62
 
57
 
require 'thread'
 
63
 
58
64
 
59
65
module Singleton
60
66
  #  disable build-in copying methods
64
70
  def dup
65
71
    raise TypeError, "can't dup instance of singleton #{self.class}"
66
72
  end
67
 
  
68
 
  private 
 
73
 
69
74
  #  default marshalling strategy
70
 
  def _dump(depth=-1) 
 
75
  def _dump(depth=-1)
71
76
    ''
72
77
  end
73
78
end
74
79
 
75
80
 
76
81
class << Singleton
77
 
  module SingletonClassMethods  
 
82
  #  Method body of first instance call.
 
83
  FirstInstanceCall = proc do
 
84
    #  @__instance__ takes on one of the following values
 
85
    #  * nil     -  before and after a failed creation
 
86
    #  * false  -  during creation
 
87
    #  * sub_class instance  -  after a successful creation
 
88
    #  the form makes up for the lack of returns in progs
 
89
    Thread.critical = true
 
90
    if  @__instance__.nil?
 
91
      @__instance__  = false
 
92
      Thread.critical = false
 
93
      begin
 
94
        @__instance__ = new
 
95
      ensure
 
96
        if @__instance__
 
97
          class <<self
 
98
            remove_method :instance
 
99
            def instance; @__instance__ end
 
100
          end
 
101
        else
 
102
          @__instance__ = nil #  failed instance creation
 
103
        end
 
104
      end
 
105
    elsif  _instantiate?()
 
106
      Thread.critical = false
 
107
    else
 
108
      @__instance__  = false
 
109
      Thread.critical = false
 
110
      begin
 
111
        @__instance__ = new
 
112
      ensure
 
113
        if @__instance__
 
114
          class <<self
 
115
            remove_method :instance
 
116
            def instance; @__instance__ end
 
117
          end
 
118
        else
 
119
          @__instance__ = nil
 
120
        end
 
121
      end
 
122
    end
 
123
    @__instance__
 
124
  end
 
125
 
 
126
  module SingletonClassMethods
78
127
    # properly clone the Singleton pattern - did you know
79
 
    # that duping doesn't copy class methods?  
 
128
    # that duping doesn't copy class methods?
80
129
    def clone
81
130
      Singleton.__init__(super)
82
131
    end
83
 
    
 
132
 
 
133
    def _load(str)
 
134
      instance
 
135
    end
 
136
 
84
137
    private
85
 
    
86
 
    #  ensure that the Singleton pattern is properly inherited   
 
138
 
 
139
    #  ensure that the Singleton pattern is properly inherited
87
140
    def inherited(sub_klass)
88
141
      super
89
142
      Singleton.__init__(sub_klass)
90
143
    end
91
 
    
92
 
    def _load(str) 
93
 
      instance 
 
144
 
 
145
    # waiting-loop hook
 
146
    def _instantiate?()
 
147
      while false.equal?(@__instance__)
 
148
        Thread.critical = false
 
149
        sleep(0.08)   # timeout
 
150
        Thread.critical = true
 
151
      end
 
152
      @__instance__
94
153
    end
95
154
  end
96
 
  
 
155
 
97
156
  def __init__(klass)
98
157
    klass.instance_eval { @__instance__ = nil }
99
 
 
100
 
    # the mutex can get GCed once "instance" is redefined
101
 
    mutex = Mutex.new
102
 
 
103
 
    (class << klass ; self ; end).instance_eval do
104
 
      define_method(:instance) do ||
105
 
 
106
 
        # note that there is no good way to support the _instantiate? hook
107
 
        # in a backwards-compatible way without forcing the use of
108
 
        # Thread.critical, which is the very thing we are trying to avoid
109
 
        # with this rewrite
110
 
 
111
 
        mutex.synchronize do
112
 
          unless @__instance__
113
 
            @__instance__ = new
114
 
 
115
 
            # redefining the method establishes a happens-before edge to
116
 
            # callers of the redefined method, so that they will see a
117
 
            # properly initialized @__instance__ without needing to
118
 
            # synchronize on the mutex
119
 
            class << self
120
 
              def instance ; @__instance__ ; end
121
 
            end
122
 
          end
123
 
          @__instance__
124
 
        end
125
 
      end
 
158
    class << klass
 
159
      define_method(:instance,FirstInstanceCall)
126
160
    end
127
161
    klass
128
162
  end
129
 
  
 
163
 
130
164
  private
131
165
  #  extending an object with Singleton is a bad idea
132
166
  undef_method :extend_object
133
 
  
 
167
 
134
168
  def append_features(mod)
135
169
    #  help out people counting on transitive mixins
136
170
    unless mod.instance_of?(Class)
138
172
    end
139
173
    super
140
174
  end
141
 
  
 
175
 
142
176
  def included(klass)
143
177
    super
144
178
    klass.private_class_method  :new, :allocate
146
180
    Singleton.__init__(klass)
147
181
  end
148
182
end
149
 
 
 
183
 
150
184
 
151
185
 
152
186
if __FILE__ == $0
153
187
 
154
188
def num_of_instances(klass)
155
189
    "#{ObjectSpace.each_object(klass){}} #{klass} instance(s)"
156
 
end 
 
190
end
157
191
 
158
192
# The basic and most important example.
159
193
 
160
194
class SomeSingletonClass
161
195
  include Singleton
162
196
end
163
 
puts "There are #{num_of_instances(SomeSingletonClass)}" 
 
197
puts "There are #{num_of_instances(SomeSingletonClass)}"
164
198
 
165
199
a = SomeSingletonClass.instance
166
200
b = SomeSingletonClass.instance # a and b are same object
174
208
 
175
209
 
176
210
 
177
 
puts "\nThreaded example with exception"; p
 
211
puts "\nThreaded example with exception and customized #_instantiate?() hook"; p
178
212
Thread.abort_on_exception = false
179
213
 
180
214
class Ups < SomeSingletonClass
183
217
    puts "initialize called by thread ##{Thread.current[:i]}"
184
218
  end
185
219
end
186
 
  
 
220
 
187
221
class << Ups
 
222
  def _instantiate?
 
223
    @enter.push Thread.current[:i]
 
224
    while false.equal?(@__instance__)
 
225
      Thread.critical = false
 
226
      sleep 0.08
 
227
      Thread.critical = true
 
228
    end
 
229
    @leave.push Thread.current[:i]
 
230
    @__instance__
 
231
  end
 
232
 
188
233
  def __sleep
189
234
    sleep(rand(0.08))
190
235
  end
191
 
  
 
236
 
192
237
  def new
193
238
    begin
194
239
      __sleep
200
245
      end
201
246
    end
202
247
  end
203
 
  
 
248
 
204
249
  def instantiate_all
205
 
    1.upto(9) {|i|  
206
 
      Thread.new { 
 
250
    @enter = []
 
251
    @leave = []
 
252
    1.upto(9) {|i|
 
253
      Thread.new {
207
254
        begin
208
255
          Thread.current[:i] = i
209
256
          __sleep
216
263
    puts "Before there were #{num_of_instances(self)}"
217
264
    sleep 3
218
265
    puts "Now there is #{num_of_instances(self)}"
 
266
    puts "#{@enter.join '; '} was the order of threads entering the waiting loop"
 
267
    puts "#{@leave.join '; '} was the order of threads leaving the waiting loop"
219
268
  end
220
269
end
221
270
 
291
340
class Down < Middle; end
292
341
 
293
342
puts  "and basic \"Down test\" is #{Down.instance == Down.instance}\n
294
 
Various exceptions"  
 
343
Various exceptions"
295
344
 
296
345
begin
297
346
  module AModule