Groonga 3.0.9 Source Code Document
Main Page
Related Pages
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Pages
groonga
vendor
mruby-eeac4be
mrbgems
mruby-fiber
src
fiber.c
Go to the documentation of this file.
1
#include "
mruby.h
"
2
#include "
mruby/array.h
"
3
#include "
mruby/class.h
"
4
#include "
mruby/proc.h
"
5
6
#define FIBER_STACK_INIT_SIZE 64
7
#define FIBER_CI_INIT_SIZE 8
8
9
/*
10
* call-seq:
11
* Fiber.new{...} -> obj
12
*
13
* Creates a fiber, whose execution is suspend until it is explicitly
14
* resumed using <code>Fiber#resume</code> method.
15
* The code running inside the fiber can give up control by calling
16
* <code>Fiber.yield</code> in which case it yields control back to caller
17
* (the caller of the <code>Fiber#resume</code>).
18
*
19
* Upon yielding or termination the Fiber returns the value of the last
20
* executed expression
21
*
22
* For instance:
23
*
24
* fiber = Fiber.new do
25
* Fiber.yield 1
26
* 2
27
* end
28
*
29
* puts fiber.resume
30
* puts fiber.resume
31
* puts fiber.resume
32
*
33
* <em>produces</em>
34
*
35
* 1
36
* 2
37
* resuming dead fiber (RuntimeError)
38
*
39
* The <code>Fiber#resume</code> method accepts an arbitrary number of
40
* parameters, if it is the first call to <code>resume</code> then they
41
* will be passed as block arguments. Otherwise they will be the return
42
* value of the call to <code>Fiber.yield</code>
43
*
44
* Example:
45
*
46
* fiber = Fiber.new do |first|
47
* second = Fiber.yield first + 2
48
* end
49
*
50
* puts fiber.resume 10
51
* puts fiber.resume 14
52
* puts fiber.resume 18
53
*
54
* <em>produces</em>
55
*
56
* 12
57
* 14
58
* resuming dead fiber (RuntimeError)
59
*
60
*/
61
static
mrb_value
62
fiber_init(
mrb_state
*mrb,
mrb_value
self
)
63
{
64
static
const
struct
mrb_context
mrb_context_zero = { 0 };
65
struct
RFiber
*f = (
struct
RFiber
*)
mrb_ptr
(
self
);
66
struct
mrb_context
*c;
67
struct
RProc
*p;
68
mrb_callinfo
*ci;
69
mrb_value
blk;
70
71
mrb_get_args
(mrb,
"&"
, &blk);
72
73
if
(
mrb_nil_p
(blk)) {
74
mrb_raise
(mrb,
E_ARGUMENT_ERROR
,
"tried to create Fiber object without a block"
);
75
}
76
p =
mrb_proc_ptr
(blk);
77
if
(
MRB_PROC_CFUNC_P
(p)) {
78
mrb_raise
(mrb,
E_ARGUMENT_ERROR
,
"tried to create Fiber from C defined method"
);
79
}
80
81
f->
cxt
= (
struct
mrb_context
*)
mrb_malloc
(mrb,
sizeof
(
struct
mrb_context
));
82
*f->
cxt
= mrb_context_zero;
83
c = f->
cxt
;
84
85
/* initialize VM stack */
86
c->
stbase
= (
mrb_value
*)
mrb_calloc
(mrb,
FIBER_STACK_INIT_SIZE
,
sizeof
(
mrb_value
));
87
c->
stend
= c->
stbase
+
FIBER_STACK_INIT_SIZE
;
88
c->
stack
= c->
stbase
;
89
90
/* copy receiver from a block */
91
c->
stack
[0] = mrb->
c
->
stack
[0];
92
93
/* initialize callinfo stack */
94
c->
cibase
= (
mrb_callinfo
*)
mrb_calloc
(mrb,
FIBER_CI_INIT_SIZE
,
sizeof
(
mrb_callinfo
));
95
c->
ciend
= c->
cibase
+
FIBER_CI_INIT_SIZE
;
96
c->
ci
= c->
cibase
;
97
98
/* adjust return callinfo */
99
ci = c->
ci
;
100
ci->
target_class
= p->
target_class
;
101
ci->
proc
= p;
102
ci->
pc
= p->
body
.
irep
->
iseq
;
103
ci->
nregs
= p->
body
.
irep
->
nregs
;
104
ci[1] = ci[0];
105
c->
ci
++;
/* push dummy callinfo */
106
107
c->
fib
= f;
108
c->
status
=
MRB_FIBER_CREATED
;
109
110
return
self
;
111
}
112
113
static
struct
mrb_context
*
114
fiber_check(
mrb_state
*mrb,
mrb_value
fib
)
115
{
116
struct
RFiber
*f = (
struct
RFiber
*)
mrb_ptr
(fib);
117
118
if
(!f->
cxt
) {
119
mrb_raise
(mrb,
E_ARGUMENT_ERROR
,
"uninitialized Fiber"
);
120
}
121
return
f->
cxt
;
122
}
123
124
static
mrb_value
125
fiber_result(
mrb_state
*mrb,
mrb_value
*a,
int
len)
126
{
127
if
(len == 0)
return
mrb_nil_value();
128
if
(len == 1)
return
a[0];
129
return
mrb_ary_new_from_values
(mrb, len, a);
130
}
131
132
/* mark return from context modifying method */
133
#define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL
134
135
/*
136
* call-seq:
137
* fiber.resume(args, ...) -> obj
138
*
139
* Resumes the fiber from the point at which the last <code>Fiber.yield</code>
140
* was called, or starts running it if it is the first call to
141
* <code>resume</code>. Arguments passed to resume will be the value of
142
* the <code>Fiber.yield</code> expression or will be passed as block
143
* parameters to the fiber's block if this is the first <code>resume</code>.
144
*
145
* Alternatively, when resume is called it evaluates to the arguments passed
146
* to the next <code>Fiber.yield</code> statement inside the fiber's block
147
* or to the block value if it runs to completion without any
148
* <code>Fiber.yield</code>
149
*/
150
static
mrb_value
151
fiber_resume(
mrb_state
*mrb,
mrb_value
self
)
152
{
153
struct
mrb_context
*c = fiber_check(mrb,
self
);
154
mrb_value
*a;
155
int
len;
156
157
if
(c->
status
==
MRB_FIBER_RESUMED
) {
158
mrb_raise
(mrb,
E_RUNTIME_ERROR
,
"double resume"
);
159
}
160
if
(c->
status
==
MRB_FIBER_TERMINATED
) {
161
mrb_raise
(mrb,
E_RUNTIME_ERROR
,
"resuming dead fiber"
);
162
}
163
mrb_get_args
(mrb,
"*"
, &a, &len);
164
mrb->
c
->
status
=
MRB_FIBER_RESUMED
;
165
if
(c->
status
==
MRB_FIBER_CREATED
) {
166
mrb_value
*
b
= c->
stack
+1;
167
mrb_value
*e = b + len;
168
169
while
(b<e) {
170
*b++ = *a++;
171
}
172
c->
cibase
->
argc
= len;
173
c->
prev
= mrb->
c
;
174
if
(c->
prev
->
fib
)
175
mrb_field_write_barrier
(mrb, (
struct
RBasic
*)c->
fib
, (
struct
RBasic
*)c->
prev
->
fib
);
176
mrb_write_barrier
(mrb, (
struct
RBasic
*)c->
fib
);
177
c->
status
=
MRB_FIBER_RUNNING
;
178
mrb->
c
= c;
179
180
MARK_CONTEXT_MODIFY
(c);
181
return
c->
ci
->
proc
->
env
->
stack
[0];
182
}
183
MARK_CONTEXT_MODIFY
(c);
184
c->
prev
= mrb->
c
;
185
if
(c->
prev
->
fib
)
186
mrb_field_write_barrier
(mrb, (
struct
RBasic
*)c->
fib
, (
struct
RBasic
*)c->
prev
->
fib
);
187
mrb_write_barrier
(mrb, (
struct
RBasic
*)c->
fib
);
188
c->
status
=
MRB_FIBER_RUNNING
;
189
mrb->
c
= c;
190
return
fiber_result(mrb, a, len);
191
}
192
193
/*
194
* call-seq:
195
* fiber.alive? -> true or false
196
*
197
* Returns true if the fiber can still be resumed. After finishing
198
* execution of the fiber block this method will always return false.
199
*/
200
static
mrb_value
201
fiber_alive_p(
mrb_state
*mrb,
mrb_value
self
)
202
{
203
struct
mrb_context
*c = fiber_check(mrb,
self
);
204
return
mrb_bool_value(c->
status
!=
MRB_FIBER_TERMINATED
);
205
}
206
207
/*
208
* call-seq:
209
* Fiber.yield(args, ...) -> obj
210
*
211
* Yields control back to the context that resumed the fiber, passing
212
* along any arguments that were passed to it. The fiber will resume
213
* processing at this point when <code>resume</code> is called next.
214
* Any arguments passed to the next <code>resume</code> will be the
215
* value that this <code>Fiber.yield</code> expression evaluates to.
216
*/
217
static
mrb_value
218
fiber_yield(
mrb_state
*mrb,
mrb_value
self
)
219
{
220
struct
mrb_context
*c = mrb->
c
;
221
mrb_value
*a;
222
int
len;
223
224
if
(!c->
prev
) {
225
mrb_raise
(mrb,
E_ARGUMENT_ERROR
,
"can't yield from root fiber"
);
226
}
227
mrb_get_args
(mrb,
"*"
, &a, &len);
228
c->
prev
->
status
=
MRB_FIBER_RUNNING
;
229
mrb->
c
= c->
prev
;
230
c->
prev
= NULL;
231
MARK_CONTEXT_MODIFY
(mrb->
c
);
232
return
fiber_result(mrb, a, len);
233
}
234
235
void
236
mrb_mruby_fiber_gem_init
(
mrb_state
* mrb)
237
{
238
struct
RClass
*c;
239
240
c =
mrb_define_class
(mrb,
"Fiber"
, mrb->
object_class
);
241
MRB_SET_INSTANCE_TT
(c,
MRB_TT_FIBER
);
242
243
mrb_define_method
(mrb, c,
"initialize"
, fiber_init,
MRB_ARGS_NONE
());
244
mrb_define_method
(mrb, c,
"resume"
, fiber_resume,
MRB_ARGS_ANY
());
245
mrb_define_method
(mrb, c,
"alive?"
, fiber_alive_p,
MRB_ARGS_NONE
());
246
247
mrb_define_class_method
(mrb, c,
"yield"
, fiber_yield,
MRB_ARGS_ANY
());
248
}
249
250
void
251
mrb_mruby_fiber_gem_final
(
mrb_state
* mrb)
252
{
253
}
Generated on Sun Nov 10 2013 09:49:05 for Groonga 3.0.9 Source Code Document by
1.8.1.2