From ec4f66d9c129718807ccb5f66738275ac1ac2e64 Mon Sep 17 00:00:00 2001 From: rm155 Date: Fri, 30 Jul 2021 15:45:34 -0400 Subject: [PATCH 1/5] Improve Ractor-compliance; Create PerRactorSingleton --- lib/singleton.rb | 104 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/lib/singleton.rb b/lib/singleton.rb index 6da9391..577a7b8 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -93,21 +93,25 @@ # module Singleton VERSION = "0.2.0" + VERSION.freeze - # Raises a TypeError to prevent cloning. - def clone - raise TypeError, "can't clone instance of singleton #{self.class}" - end + module SingletonInstanceMethods + # Raises a TypeError to prevent cloning. + def clone + raise TypeError, "can't clone instance of singleton #{self.class}" + end - # Raises a TypeError to prevent duping. - def dup - raise TypeError, "can't dup instance of singleton #{self.class}" - end + # Raises a TypeError to prevent duping. + def dup + raise TypeError, "can't dup instance of singleton #{self.class}" + end - # By default, do not retain any state when marshalling. - def _dump(depth = -1) - '' + # By default, do not retain any state when marshalling. + def _dump(depth = -1) + '' + end end + include SingletonInstanceMethods module SingletonClassMethods # :nodoc: @@ -121,7 +125,7 @@ def _load(str) end def instance # :nodoc: - @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new } + @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= set_instance(new) } end private @@ -130,22 +134,42 @@ def inherited(sub_klass) super Singleton.__init__(sub_klass) end + + def set_instance(val) + @singleton__instance__ = val + end + + def set_mutex(val) + @singleton__mutex__ = val + end end - class << Singleton # :nodoc: + def self.module_with_class_methods + SingletonClassMethods + end + + module SingletonClassProperties + + def self.included(c) + # extending an object with Singleton is a bad idea + c.undef_method :extend_object + end + + def self.extended(c) + # extending an object with Singleton is a bad idea + c.singleton_class.undef_method :extend_object + end + def __init__(klass) # :nodoc: klass.instance_eval { - @singleton__instance__ = nil - @singleton__mutex__ = Thread::Mutex.new + set_instance(nil) + set_mutex(Thread::Mutex.new) } klass end private - # extending an object with Singleton is a bad idea - undef_method :extend_object - def append_features(mod) # help out people counting on transitive mixins unless mod.instance_of?(Class) @@ -157,10 +181,11 @@ def append_features(mod) def included(klass) super klass.private_class_method :new, :allocate - klass.extend SingletonClassMethods + klass.extend module_with_class_methods Singleton.__init__(klass) end end + extend SingletonClassProperties ## # :singleton-method: _load @@ -170,3 +195,44 @@ def included(klass) # :singleton-method: instance # Returns the singleton instance. end + +module PerRactorSingleton + include Singleton::SingletonInstanceMethods + + module PerRactorSingletonClassMethods + include Singleton::SingletonClassMethods + def instance + set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil? + return Ractor.current[instance_key] if Ractor.current[instance_key] + Ractor.current[mutex_key].synchronize { + return Ractor.current[instance_key] if Ractor.current[instance_key] + set_instance(new()) + } + Ractor.current[instance_key] + end + + private + + def instance_key + :"__PerRactorSingleton_instance_with_class_id_#{object_id}__" + end + + def mutex_key + :"__PerRactorSingleton_mutex_with_class_id_#{object_id}__" + end + + def set_instance(val) + Ractor.current[instance_key] = val + end + + def set_mutex(val) + Ractor.current[mutex_key] = val + end + end + + def self.module_with_class_methods + PerRactorSingletonClassMethods + end + + extend Singleton::SingletonClassProperties +end From 1216a86303f9f519bdc323304c6a79d469745ec5 Mon Sep 17 00:00:00 2001 From: rm155 Date: Sat, 31 Jul 2021 16:17:55 -0400 Subject: [PATCH 2/5] Change PerRactorSingleton to RactorLocalSingleton --- lib/singleton.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/singleton.rb b/lib/singleton.rb index 577a7b8..4a47190 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -196,10 +196,10 @@ def included(klass) # Returns the singleton instance. end -module PerRactorSingleton +module RactorLocalSingleton include Singleton::SingletonInstanceMethods - module PerRactorSingletonClassMethods + module RactorLocalSingletonClassMethods include Singleton::SingletonClassMethods def instance set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil? @@ -214,11 +214,11 @@ def instance private def instance_key - :"__PerRactorSingleton_instance_with_class_id_#{object_id}__" + :"__RactorLocalSingleton_instance_with_class_id_#{object_id}__" end def mutex_key - :"__PerRactorSingleton_mutex_with_class_id_#{object_id}__" + :"__RactorLocalSingleton_mutex_with_class_id_#{object_id}__" end def set_instance(val) @@ -231,7 +231,7 @@ def set_mutex(val) end def self.module_with_class_methods - PerRactorSingletonClassMethods + RactorLocalSingletonClassMethods end extend Singleton::SingletonClassProperties From f684d36a4754cbbd619e5e0ac193ca7efc6947ff Mon Sep 17 00:00:00 2001 From: rm155 Date: Wed, 18 Aug 2021 16:51:13 -0400 Subject: [PATCH 3/5] Only use RactorLocalSingleton if Ractor is defined --- lib/singleton.rb | 60 +++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/singleton.rb b/lib/singleton.rb index 4a47190..924cbf1 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -196,43 +196,45 @@ def included(klass) # Returns the singleton instance. end -module RactorLocalSingleton - include Singleton::SingletonInstanceMethods - - module RactorLocalSingletonClassMethods - include Singleton::SingletonClassMethods - def instance - set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil? - return Ractor.current[instance_key] if Ractor.current[instance_key] - Ractor.current[mutex_key].synchronize { +if defined?(Ractor) + module RactorLocalSingleton + include Singleton::SingletonInstanceMethods + + module RactorLocalSingletonClassMethods + include Singleton::SingletonClassMethods + def instance + set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil? return Ractor.current[instance_key] if Ractor.current[instance_key] - set_instance(new()) - } - Ractor.current[instance_key] - end + Ractor.current[mutex_key].synchronize { + return Ractor.current[instance_key] if Ractor.current[instance_key] + set_instance(new()) + } + Ractor.current[instance_key] + end - private + private - def instance_key - :"__RactorLocalSingleton_instance_with_class_id_#{object_id}__" - end + def instance_key + :"__RactorLocalSingleton_instance_with_class_id_#{object_id}__" + end - def mutex_key - :"__RactorLocalSingleton_mutex_with_class_id_#{object_id}__" - end + def mutex_key + :"__RactorLocalSingleton_mutex_with_class_id_#{object_id}__" + end - def set_instance(val) - Ractor.current[instance_key] = val + def set_instance(val) + Ractor.current[instance_key] = val + end + + def set_mutex(val) + Ractor.current[mutex_key] = val + end end - def set_mutex(val) - Ractor.current[mutex_key] = val + def self.module_with_class_methods + RactorLocalSingletonClassMethods end - end - def self.module_with_class_methods - RactorLocalSingletonClassMethods + extend Singleton::SingletonClassProperties end - - extend Singleton::SingletonClassProperties end From f31334a736f644f53314e414b1f0fae4b6ca53b9 Mon Sep 17 00:00:00 2001 From: rm155 Date: Thu, 16 Sep 2021 22:42:45 -0400 Subject: [PATCH 4/5] Clean VERSION freezing --- lib/singleton.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/singleton.rb b/lib/singleton.rb index 924cbf1..0120f05 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true # The Singleton module implements the Singleton pattern. # @@ -93,7 +93,6 @@ # module Singleton VERSION = "0.2.0" - VERSION.freeze module SingletonInstanceMethods # Raises a TypeError to prevent cloning. From 0a77bb492d16e2c1972ba99d3441e4b990779365 Mon Sep 17 00:00:00 2001 From: rm155 Date: Mon, 8 Nov 2021 13:59:38 -0500 Subject: [PATCH 5/5] Make compatible with Ruby 2.4 --- lib/singleton.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singleton.rb b/lib/singleton.rb index 0120f05..afe669e 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -156,7 +156,7 @@ def self.included(c) def self.extended(c) # extending an object with Singleton is a bad idea - c.singleton_class.undef_method :extend_object + c.singleton_class.send(:undef_method, :extend_object) end def __init__(klass) # :nodoc: