Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
monitor.c
Go to the documentation of this file.
1 #include "ruby/ruby.h"
2 
3 /* Thread::Monitor */
4 
5 struct rb_monitor {
6  long count;
7  const VALUE owner;
8  const VALUE mutex;
9 };
10 
11 static void
12 monitor_mark(void *ptr)
13 {
14  struct rb_monitor *mc = ptr;
15  rb_gc_mark(mc->owner);
16  rb_gc_mark(mc->mutex);
17 }
18 
19 static size_t
20 monitor_memsize(const void *ptr)
21 {
22  return sizeof(struct rb_monitor);
23 }
24 
25 static const rb_data_type_t monitor_data_type = {
26  "monitor",
27  {monitor_mark, RUBY_TYPED_DEFAULT_FREE, monitor_memsize,},
29 };
30 
31 static VALUE
32 monitor_alloc(VALUE klass)
33 {
34  struct rb_monitor *mc;
35  VALUE obj;
36 
37  obj = TypedData_Make_Struct(klass, struct rb_monitor, &monitor_data_type, mc);
38  RB_OBJ_WRITE(obj, &mc->mutex, rb_mutex_new());
39  RB_OBJ_WRITE(obj, &mc->owner, Qnil);
40  mc->count = 0;
41 
42  return obj;
43 }
44 
45 static struct rb_monitor *
46 monitor_ptr(VALUE monitor)
47 {
48  struct rb_monitor *mc;
49  TypedData_Get_Struct(monitor, struct rb_monitor, &monitor_data_type, mc);
50  return mc;
51 }
52 
53 static int
54 mc_owner_p(struct rb_monitor *mc)
55 {
56  return mc->owner == rb_fiber_current();
57 }
58 
59 static VALUE
60 monitor_try_enter(VALUE monitor)
61 {
62  struct rb_monitor *mc = monitor_ptr(monitor);
63 
64  if (!mc_owner_p(mc)) {
65  if (!rb_mutex_trylock(mc->mutex)) {
66  return Qfalse;
67  }
68  RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
69  mc->count = 0;
70  }
71  mc->count += 1;
72  return Qtrue;
73 }
74 
75 static VALUE
76 monitor_enter(VALUE monitor)
77 {
78  struct rb_monitor *mc = monitor_ptr(monitor);
79  if (!mc_owner_p(mc)) {
80  rb_mutex_lock(mc->mutex);
81  RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
82  mc->count = 0;
83  }
84  mc->count++;
85  return Qnil;
86 }
87 
88 static VALUE
89 monitor_check_owner(VALUE monitor)
90 {
91  struct rb_monitor *mc = monitor_ptr(monitor);
92  if (!mc_owner_p(mc)) {
93  rb_raise(rb_eThreadError, "current fiber not owner");
94  }
95  return Qnil;
96 }
97 
98 static VALUE
99 monitor_exit(VALUE monitor)
100 {
101  monitor_check_owner(monitor);
102 
103  struct rb_monitor *mc = monitor_ptr(monitor);
104 
105  if (mc->count <= 0) rb_bug("monitor_exit: count:%d\n", (int)mc->count);
106  mc->count--;
107 
108  if (mc->count == 0) {
109  RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
110  rb_mutex_unlock(mc->mutex);
111  }
112  return Qnil;
113 }
114 
115 static VALUE
116 monitor_locked_p(VALUE monitor)
117 {
118  struct rb_monitor *mc = monitor_ptr(monitor);
119  return rb_mutex_locked_p(mc->mutex);
120 }
121 
122 static VALUE
123 monitor_owned_p(VALUE monitor)
124 {
125  struct rb_monitor *mc = monitor_ptr(monitor);
126  return (rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc)) ? Qtrue : Qfalse;
127 }
128 
129 static VALUE
130 monitor_exit_for_cond(VALUE monitor)
131 {
132  struct rb_monitor *mc = monitor_ptr(monitor);
133  long cnt = mc->count;
134  RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
135  mc->count = 0;
136  return LONG2NUM(cnt);
137 }
138 
144 };
145 
146 static VALUE
147 monitor_wait_for_cond_body(VALUE v)
148 {
149  struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
150  struct rb_monitor *mc = monitor_ptr(data->monitor);
151  // cond.wait(monitor.mutex, timeout)
152  VALUE signaled = rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
153  return RTEST(signaled) ? Qtrue : Qfalse;
154 }
155 
156 static VALUE
157 monitor_enter_for_cond(VALUE v)
158 {
159  // assert(rb_mutex_owned_p(mc->mutex) == Qtrue)
160  // but rb_mutex_owned_p is not exported...
161 
162  struct wait_for_cond_data *data = (struct wait_for_cond_data *)v;
163  struct rb_monitor *mc = monitor_ptr(data->monitor);
164  RB_OBJ_WRITE(data->monitor, &mc->owner, rb_fiber_current());
165  mc->count = NUM2LONG(data->count);
166  return Qnil;
167 }
168 
169 static VALUE
170 monitor_wait_for_cond(VALUE monitor, VALUE cond, VALUE timeout)
171 {
172  VALUE count = monitor_exit_for_cond(monitor);
173  struct wait_for_cond_data data = {
174  monitor,
175  cond,
176  timeout,
177  count,
178  };
179 
180  return rb_ensure(monitor_wait_for_cond_body, (VALUE)&data,
181  monitor_enter_for_cond, (VALUE)&data);
182 }
183 
184 static VALUE
185 monitor_sync_body(VALUE monitor)
186 {
187  return rb_yield_values(0);
188 }
189 
190 static VALUE
191 monitor_sync_ensure(VALUE monitor)
192 {
193  return monitor_exit(monitor);
194 }
195 
196 static VALUE
197 monitor_synchronize(VALUE monitor)
198 {
199  monitor_enter(monitor);
200  return rb_ensure(monitor_sync_body, monitor, monitor_sync_ensure, monitor);
201 }
202 
203 void
205 {
206 #ifdef HAVE_RB_EXT_RACTOR_SAFE
207  rb_ext_ractor_safe(true);
208 #endif
209 
210  VALUE rb_cMonitor = rb_define_class("Monitor", rb_cObject);
211  rb_define_alloc_func(rb_cMonitor, monitor_alloc);
212 
213  rb_define_method(rb_cMonitor, "try_enter", monitor_try_enter, 0);
214  rb_define_method(rb_cMonitor, "enter", monitor_enter, 0);
215  rb_define_method(rb_cMonitor, "exit", monitor_exit, 0);
216  rb_define_method(rb_cMonitor, "synchronize", monitor_synchronize, 0);
217 
218  /* internal methods for MonitorMixin */
219  rb_define_method(rb_cMonitor, "mon_locked?", monitor_locked_p, 0);
220  rb_define_method(rb_cMonitor, "mon_check_owner", monitor_check_owner, 0);
221  rb_define_method(rb_cMonitor, "mon_owned?", monitor_owned_p, 0);
222 
223  /* internal methods for MonitorMixin::ConditionVariable */
224  rb_define_method(rb_cMonitor, "wait_for_cond", monitor_wait_for_cond, 2);
225 }
wait_for_cond_data::timeout
VALUE timeout
Definition: monitor.c:142
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:759
Init_monitor
void Init_monitor(void)
Definition: monitor.c:204
rb_monitor::count
long count
Definition: monitor.c:6
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:784
rb_monitor
Definition: monitor.c:5
RUBY_TYPED_WB_PROTECTED
@ RUBY_TYPED_WB_PROTECTED
Definition: rtypeddata.h:64
LONG2NUM
#define LONG2NUM
Definition: long.h:50
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
Definition: rtypeddata.h:44
rb_monitor::owner
const VALUE owner
Definition: monitor.c:7
rb_mutex_locked_p
VALUE rb_mutex_locked_p(VALUE mutex)
Definition: thread_sync.c:184
ptr
struct RIMemo * ptr
Definition: debug.c:87
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
ruby.h
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:3022
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:50
rb_ext_ractor_safe
void rb_ext_ractor_safe(bool flag)
Definition: load.c:1039
Qfalse
#define Qfalse
Definition: special_consts.h:50
wait_for_cond_data::cond
VALUE cond
Definition: monitor.c:141
rb_mutex_new
VALUE rb_mutex_new(void)
Definition: thread_sync.c:172
Qnil
#define Qnil
Definition: special_consts.h:51
cnt
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:508
rb_eThreadError
VALUE rb_eThreadError
Definition: eval.c:957
wait_for_cond_data
Definition: monitor.c:139
RTEST
#define RTEST
Definition: special_consts.h:42
RB_OBJ_WRITE
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:107
Qtrue
#define Qtrue
Definition: special_consts.h:52
rb_mutex_lock
VALUE rb_mutex_lock(VALUE mutex)
Definition: thread_sync.c:395
wait_for_cond_data::monitor
VALUE monitor
Definition: monitor.c:140
VALUE
unsigned long VALUE
Definition: value.h:38
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:796
rb_mutex_unlock
VALUE rb_mutex_unlock(VALUE mutex)
Definition: thread_sync.c:468
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1113
rb_mutex_trylock
VALUE rb_mutex_trylock(VALUE mutex)
Definition: thread_sync.c:233
rb_fiber_current
VALUE rb_fiber_current(void)
Definition: cont.c:2201
NUM2LONG
#define NUM2LONG
Definition: long.h:51
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: rtypeddata.h:130
rb_data_type_struct
Definition: rtypeddata.h:70
wait_for_cond_data::count
VALUE count
Definition: monitor.c:143
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6836
count
int count
Definition: nkf.c:5055
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1144
rb_yield_values
VALUE rb_yield_values(int n,...)
Definition: vm_eval.c:1389
rb_monitor::mutex
const VALUE mutex
Definition: monitor.c:8