Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .rdoc_options
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ exclude:
- \.gemspec\z
- lib/set/subclass_compatible.rb

generator_name: aliki

autolink_excluded_words:
- Box
- Class
Expand Down
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ The following bundled gems are promoted from default gems.
* pstore 0.2.0
* benchmark 0.5.0
* logger 1.7.0
* rdoc 6.17.0
* rdoc 7.0.1
* win32ole 1.9.2
* irb 1.16.0
* reline 0.6.3
Expand Down
37 changes: 23 additions & 14 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "internal/variable.h"
#include "ruby/st.h"
#include "vm_core.h"
#include "ruby/ractor.h"
#include "yjit.h"
#include "zjit.h"

Expand Down Expand Up @@ -2823,7 +2824,7 @@ rb_special_singleton_class(VALUE obj)
* consistency of the metaclass hierarchy.
*/
static VALUE
singleton_class_of(VALUE obj)
singleton_class_of(VALUE obj, bool ensure_eigenclass)
{
VALUE klass;

Expand Down Expand Up @@ -2851,13 +2852,26 @@ singleton_class_of(VALUE obj)
}
}

klass = METACLASS_OF(obj);
if (!(RCLASS_SINGLETON_P(klass) &&
RCLASS_ATTACHED_OBJECT(klass) == obj)) {
klass = rb_make_metaclass(obj, klass);
bool needs_lock = rb_multi_ractor_p() && rb_ractor_shareable_p(obj);
unsigned int lev;
if (needs_lock) {
RB_VM_LOCK_ENTER_LEV(&lev);
}
{
klass = METACLASS_OF(obj);
if (!(RCLASS_SINGLETON_P(klass) &&
RCLASS_ATTACHED_OBJECT(klass) == obj)) {
klass = rb_make_metaclass(obj, klass);
}
RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
if (ensure_eigenclass && RB_TYPE_P(obj, T_CLASS)) {
/* ensures an exposed class belongs to its own eigenclass */
(void)ENSURE_EIGENCLASS(klass);
}
}
if (needs_lock) {
RB_VM_LOCK_LEAVE_LEV(&lev);
}

RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));

return klass;
}
Expand Down Expand Up @@ -2900,12 +2914,7 @@ rb_singleton_class_get(VALUE obj)
VALUE
rb_singleton_class(VALUE obj)
{
VALUE klass = singleton_class_of(obj);

/* ensures an exposed class belongs to its own eigenclass */
if (RB_TYPE_P(obj, T_CLASS)) (void)ENSURE_EIGENCLASS(klass);

return klass;
return singleton_class_of(obj, true);
}

/*!
Expand All @@ -2923,7 +2932,7 @@ rb_singleton_class(VALUE obj)
void
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
{
rb_define_method(singleton_class_of(obj), name, func, argc);
rb_define_method(singleton_class_of(obj, false), name, func, argc);
}

#ifdef rb_define_module_function
Expand Down
1 change: 1 addition & 0 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,7 @@ class.$(OBJEXT): {$(VPATH)}missing.h
class.$(OBJEXT): {$(VPATH)}node.h
class.$(OBJEXT): {$(VPATH)}onigmo.h
class.$(OBJEXT): {$(VPATH)}oniguruma.h
class.$(OBJEXT): {$(VPATH)}ractor.h
class.$(OBJEXT): {$(VPATH)}ruby_assert.h
class.$(OBJEXT): {$(VPATH)}ruby_atomic.h
class.$(OBJEXT): {$(VPATH)}rubyparser.h
Expand Down
2 changes: 1 addition & 1 deletion gems/bundled_gems
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ostruct 0.6.3 https://github.com/ruby/ostruct
pstore 0.2.0 https://github.com/ruby/pstore
benchmark 0.5.0 https://github.com/ruby/benchmark
logger 1.7.0 https://github.com/ruby/logger
rdoc 6.17.0 https://github.com/ruby/rdoc
rdoc 7.0.1 https://github.com/ruby/rdoc
win32ole 1.9.2 https://github.com/ruby/win32ole
irb 1.16.0 https://github.com/ruby/irb
reline 0.6.3 https://github.com/ruby/reline
Expand Down
15 changes: 15 additions & 0 deletions test/ruby/test_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -930,4 +930,19 @@ def test_safe_multi_ractor_subclasses_list_mutation
end.each(&:join)
end;
end

def test_safe_multi_ractor_singleton_class_access
assert_ractor "#{<<~"begin;"}\n#{<<~'end;'}"
begin;
class A; end
4.times.map do
Ractor.new do
a = A
100.times do
a = a.singleton_class
end
end
end.each(&:join)
end;
end
end
10 changes: 5 additions & 5 deletions thread_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ static VALUE rb_eClosedQueueError;
/* Mutex */
typedef struct rb_mutex_struct {
rb_serial_t ec_serial;
VALUE thread; // even if the fiber is collected, we might need access to the thread in mutex_free
rb_thread_t *th; // even if the fiber is collected, we might need access to the thread in mutex_free
struct rb_mutex_struct *next_mutex;
struct ccan_list_head waitq; /* protected by GVL */
} rb_mutex_t;
Expand Down Expand Up @@ -133,7 +133,7 @@ mutex_free(void *ptr)
{
rb_mutex_t *mutex = ptr;
if (mutex_locked_p(mutex)) {
const char *err = rb_mutex_unlock_th(mutex, rb_thread_ptr(mutex->thread), 0);
const char *err = rb_mutex_unlock_th(mutex, mutex->th, 0);
if (err) rb_bug("%s", err);
}
ruby_xfree(ptr);
Expand Down Expand Up @@ -223,7 +223,7 @@ thread_mutex_remove(rb_thread_t *thread, rb_mutex_t *mutex)
static void
mutex_set_owner(rb_mutex_t *mutex, rb_thread_t *th, rb_serial_t ec_serial)
{
mutex->thread = th->self;
mutex->th = th;
mutex->ec_serial = ec_serial;
}

Expand Down Expand Up @@ -340,7 +340,7 @@ do_mutex_lock(struct mutex_args *args, int interruptible_p)
}
}
else {
if (!th->vm->thread_ignore_deadlock && rb_thread_ptr(mutex->thread) == th) {
if (!th->vm->thread_ignore_deadlock && mutex->th == th) {
rb_raise(rb_eThreadError, "deadlock; lock already owned by another fiber belonging to the same thread");
}

Expand Down Expand Up @@ -391,7 +391,7 @@ do_mutex_lock(struct mutex_args *args, int interruptible_p)
/* release mutex before checking for interrupts...as interrupt checking
* code might call rb_raise() */
if (mutex->ec_serial == ec_serial) {
mutex->thread = Qfalse;
mutex->th = NULL;
mutex->ec_serial = 0;
}
RUBY_VM_CHECK_INTS_BLOCKING(th->ec); /* may release mutex */
Expand Down