Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
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);
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_thread_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_thread_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_thread_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 thread 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  rb_funcall(data->cond, rb_intern("wait"), 2, mc->mutex, data->timeout);
153  return Qtrue;
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);
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  VALUE rb_cMonitor = rb_define_class("Monitor", rb_cObject);
207  rb_define_alloc_func(rb_cMonitor, monitor_alloc);
208 
209  rb_define_method(rb_cMonitor, "try_enter", monitor_try_enter, 0);
210  rb_define_method(rb_cMonitor, "enter", monitor_enter, 0);
211  rb_define_method(rb_cMonitor, "exit", monitor_exit, 0);
212  rb_define_method(rb_cMonitor, "synchronize", monitor_synchronize, 0);
213 
214  /* internal methods for MonitorMixin */
215  rb_define_method(rb_cMonitor, "mon_locked?", monitor_locked_p, 0);
216  rb_define_method(rb_cMonitor, "mon_check_owner", monitor_check_owner, 0);
217  rb_define_method(rb_cMonitor, "mon_owned?", monitor_owned_p, 0);
218 
219  /* internal methods for MonitorMixin::ConditionalVariable */
220  rb_define_method(rb_cMonitor, "wait_for_cond", monitor_wait_for_cond, 2);
221 }
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:649
Init_monitor
void Init_monitor(void)
Definition: monitor.c:204
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.1.h:5703
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
rb_monitor::count
long count
Definition: monitor.c:6
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.1.h:13179
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.1.h:6546
rb_mutex_trylock
VALUE rb_mutex_trylock(VALUE mutex)
Definition: thread_sync.c:203
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:679
rb_monitor
Definition: monitor.c:5
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_intern
#define rb_intern(str)
rb_mutex_locked_p
VALUE rb_mutex_locked_p(VALUE mutex)
Definition: thread_sync.c:177
rb_thread_current
VALUE rb_thread_current(void)
Definition: thread.c:2676
rb_monitor::owner
const VALUE owner
Definition: monitor.c:7
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
ptr
struct RIMemo * ptr
Definition: debug.c:74
Qfalse
#define Qfalse
Definition: ruby.h:467
ruby.h
rb_mutex_lock
VALUE rb_mutex_lock(VALUE mutex)
Definition: thread_sync.c:333
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
Definition: ruby.h:1203
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1644
wait_for_cond_data::cond
VALUE cond
Definition: monitor.c:141
cnt
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:503
rb_mutex_unlock
VALUE rb_mutex_unlock(VALUE mutex)
Definition: thread_sync.c:403
rb_eThreadError
VALUE rb_eThreadError
Definition: eval.c:924
wait_for_cond_data
Definition: monitor.c:139
RB_OBJ_WRITE
#define RB_OBJ_WRITE(a, slot, b)
Definition: ruby.h:1508
wait_for_cond_data::monitor
VALUE monitor
Definition: monitor.c:140
rb_yield_values
#define rb_yield_values(argc,...)
Definition: rb_mjit_min_header-2.7.1.h:6545
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1252
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
rb_data_type_struct
Definition: ruby.h:1148
wait_for_cond_data::count
VALUE count
Definition: monitor.c:143
v
int VALUE v
Definition: rb_mjit_min_header-2.7.1.h:12257
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5214
count
int count
Definition: encoding.c:57
Qtrue
#define Qtrue
Definition: ruby.h:468
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:1115
Qnil
#define Qnil
Definition: ruby.h:469
rb_mutex_new
VALUE rb_mutex_new(void)
Definition: thread_sync.c:165
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_WB_PROTECTED
Definition: ruby.h:1208
rb_monitor::mutex
const VALUE mutex
Definition: monitor.c:8