Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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,},
28 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
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_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
139 struct wait_for_cond_data {
140 VALUE monitor;
141 VALUE cond;
142 VALUE timeout;
143 VALUE count;
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);
164 RB_OBJ_WRITE(data->monitor, &mc->owner, rb_thread_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
204 Init_monitor(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 }
rb_yield_values
#define rb_yield_values(argc,...)
Definition: rb_mjit_min_header-2.7.0.h:6584
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
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
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
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
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
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
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:923
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_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_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.0.h:6585
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.0.h:13254
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
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5212
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:1114
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