Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mruby
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
mruby
Commits
e854a0e8
Commit
e854a0e8
authored
Mar 21, 2014
by
take_cheeze
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make Fiber#transfer compatible with CRuby
parent
d4d4f1b0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
126 additions
and
32 deletions
+126
-32
include/mruby.h
include/mruby.h
+1
-0
mrbgems/mruby-fiber/src/fiber.c
mrbgems/mruby-fiber/src/fiber.c
+47
-27
mrbgems/mruby-fiber/test/fiber.rb
mrbgems/mruby-fiber/test/fiber.rb
+78
-5
No files found.
include/mruby.h
View file @
e854a0e8
...
...
@@ -72,6 +72,7 @@ enum mrb_fiber_state {
MRB_FIBER_RUNNING
,
MRB_FIBER_RESUMING
,
MRB_FIBER_SUSPENDED
,
MRB_FIBER_TRANSFERRED
,
MRB_FIBER_TERMINATED
,
};
...
...
mrbgems/mruby-fiber/src/fiber.c
View file @
e854a0e8
...
...
@@ -136,27 +136,10 @@ fiber_result(mrb_state *mrb, mrb_value *a, int len)
/* mark return from context modifying method */
#define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL
/*
* call-seq:
* fiber.resume(args, ...) -> obj
*
* Resumes the fiber from the point at which the last <code>Fiber.yield</code>
* was called, or starts running it if it is the first call to
* <code>resume</code>. Arguments passed to resume will be the value of
* the <code>Fiber.yield</code> expression or will be passed as block
* parameters to the fiber's block if this is the first <code>resume</code>.
*
* Alternatively, when resume is called it evaluates to the arguments passed
* to the next <code>Fiber.yield</code> statement inside the fiber's block
* or to the block value if it runs to completion without any
* <code>Fiber.yield</code>
*/
static
mrb_value
fiber_
resume
(
mrb_state
*
mrb
,
mrb_value
self
)
fiber_
switch
(
mrb_state
*
mrb
,
mrb_value
self
,
int
len
,
const
mrb_value
*
a
,
mrb_bool
resume
)
{
struct
mrb_context
*
c
=
fiber_check
(
mrb
,
self
);
mrb_value
*
a
;
int
len
;
mrb_callinfo
*
ci
;
for
(
ci
=
c
->
ci
;
ci
>=
c
->
cibase
;
ci
--
)
{
...
...
@@ -164,6 +147,9 @@ fiber_resume(mrb_state *mrb, mrb_value self)
mrb_raise
(
mrb
,
E_FIBER_ERROR
,
"can't cross C function boundary"
);
}
}
if
(
resume
&&
c
->
status
==
MRB_FIBER_TRANSFERRED
)
{
mrb_raise
(
mrb
,
E_FIBER_ERROR
,
"resuming transfered fiber"
);
}
if
(
c
->
status
==
MRB_FIBER_RUNNING
||
c
->
status
==
MRB_FIBER_RESUMING
)
{
mrb_raise
(
mrb
,
E_FIBER_ERROR
,
"double resume"
);
}
...
...
@@ -171,7 +157,8 @@ fiber_resume(mrb_state *mrb, mrb_value self)
mrb_raise
(
mrb
,
E_FIBER_ERROR
,
"resuming dead fiber"
);
}
mrb_get_args
(
mrb
,
"*"
,
&
a
,
&
len
);
mrb
->
c
->
status
=
MRB_FIBER_RESUMING
;
mrb
->
c
->
status
=
resume
?
MRB_FIBER_RESUMING
:
MRB_FIBER_TRANSFERRED
;
c
->
prev
=
resume
?
mrb
->
c
:
(
c
->
prev
?
c
->
prev
:
mrb
->
root_c
);
if
(
c
->
status
==
MRB_FIBER_CREATED
)
{
mrb_value
*
b
=
c
->
stack
+
1
;
mrb_value
*
e
=
b
+
len
;
...
...
@@ -180,7 +167,6 @@ fiber_resume(mrb_state *mrb, mrb_value self)
*
b
++
=
*
a
++
;
}
c
->
cibase
->
argc
=
len
;
c
->
prev
=
mrb
->
c
;
if
(
c
->
prev
->
fib
)
mrb_field_write_barrier
(
mrb
,
(
struct
RBasic
*
)
c
->
fib
,
(
struct
RBasic
*
)
c
->
prev
->
fib
);
mrb_write_barrier
(
mrb
,
(
struct
RBasic
*
)
c
->
fib
);
...
...
@@ -191,7 +177,6 @@ fiber_resume(mrb_state *mrb, mrb_value self)
return
c
->
ci
->
proc
->
env
->
stack
[
0
];
}
MARK_CONTEXT_MODIFY
(
c
);
c
->
prev
=
mrb
->
c
;
if
(
c
->
prev
->
fib
)
mrb_field_write_barrier
(
mrb
,
(
struct
RBasic
*
)
c
->
fib
,
(
struct
RBasic
*
)
c
->
prev
->
fib
);
mrb_write_barrier
(
mrb
,
(
struct
RBasic
*
)
c
->
fib
);
...
...
@@ -200,6 +185,30 @@ fiber_resume(mrb_state *mrb, mrb_value self)
return
fiber_result
(
mrb
,
a
,
len
);
}
/*
* call-seq:
* fiber.resume(args, ...) -> obj
*
* Resumes the fiber from the point at which the last <code>Fiber.yield</code>
* was called, or starts running it if it is the first call to
* <code>resume</code>. Arguments passed to resume will be the value of
* the <code>Fiber.yield</code> expression or will be passed as block
* parameters to the fiber's block if this is the first <code>resume</code>.
*
* Alternatively, when resume is called it evaluates to the arguments passed
* to the next <code>Fiber.yield</code> statement inside the fiber's block
* or to the block value if it runs to completion without any
* <code>Fiber.yield</code>
*/
static
mrb_value
fiber_resume
(
mrb_state
*
mrb
,
mrb_value
self
)
{
mrb_value
*
a
;
int
len
;
mrb_get_args
(
mrb
,
"*"
,
&
a
,
&
len
);
return
fiber_switch
(
mrb
,
self
,
len
,
a
,
TRUE
);
}
/*
* call-seq:
* fiber.alive? -> true or false
...
...
@@ -229,14 +238,25 @@ fiber_eq(mrb_state *mrb, mrb_value self)
static
mrb_value
fiber_transfer
(
mrb_state
*
mrb
,
mrb_value
self
)
{
mrb_value
result
=
fiber_resume
(
mrb
,
self
);
struct
mrb_context
*
c
=
fiber_check
(
mrb
,
self
);
mrb_value
*
a
;
int
len
;
mrb_get_args
(
mrb
,
"*"
,
&
a
,
&
len
);
mrb_assert
(
mrb
->
c
->
prev
);
mrb_assert
(
mrb
->
c
->
prev
->
prev
);
mrb
->
c
->
prev
->
status
=
MRB_FIBER_SUSPENDED
;
mrb
->
c
->
prev
=
mrb
->
c
->
prev
->
prev
;
if
(
c
==
mrb
->
root_c
)
{
mrb
->
c
->
status
=
MRB_FIBER_TRANSFERRED
;
mrb
->
c
=
c
;
c
->
status
=
MRB_FIBER_RUNNING
;
MARK_CONTEXT_MODIFY
(
c
);
return
fiber_result
(
mrb
,
a
,
len
);
}
if
(
c
==
mrb
->
c
)
{
return
fiber_result
(
mrb
,
a
,
len
);
}
return
result
;
return
fiber_switch
(
mrb
,
self
,
len
,
a
,
FALSE
)
;
}
mrb_value
...
...
mrbgems/mruby-fiber/test/fiber.rb
View file @
e854a0e8
...
...
@@ -9,22 +9,24 @@ assert('Fiber#resume') {
}
assert
(
'Fiber#transfer'
)
do
f2
=
nil
f1
=
Fiber
.
new
do
|
v
|
assert_raise
(
FiberError
)
{
Fiber
.
current
.
transfer
}
Fiber
.
yield
v
f2
.
transfer
end
f2
=
Fiber
.
new
do
f1
.
transfer
(
1
)
f1
.
transfer
(
1
)
Fiber
.
yield
2
end
assert_equal
1
,
f2
.
resume
assert_equal
2
,
f2
.
resume
f1
.
resume
assert_raise
(
FiberError
)
{
f2
.
resume
}
assert_equal
2
,
f2
.
transfer
assert_raise
(
FiberError
)
{
f1
.
resume
}
f1
.
transfer
f2
.
resume
assert_false
f1
.
alive?
assert_false
f2
.
alive?
assert_raise
(
FiberError
)
{
Fiber
.
current
.
transfer
}
end
assert
(
'Fiber#alive?'
)
{
...
...
@@ -133,3 +135,74 @@ end
assert
(
'Fiber without block'
)
do
assert_raise
(
ArgumentError
)
{
Fiber
.
new
}
end
assert
(
'Transfer to self.'
)
do
result
=
[]
f
=
Fiber
.
new
{
result
<<
:start
;
f
.
transfer
;
result
<<
:end
}
f
.
transfer
assert_equal
[
:start
,
:end
],
result
result
=
[]
f
=
Fiber
.
new
{
result
<<
:start
;
f
.
transfer
;
result
<<
:end
}
f
.
resume
assert_equal
[
:start
,
:end
],
result
end
assert
(
'Resume transferred fiber'
)
do
f
=
Fiber
.
new
{
assert_raise
(
FiberError
)
{
f
.
resume
}
}
f
.
transfer
end
assert
(
'Root fiber transfer.'
)
do
result
=
nil
root
=
Fiber
.
current
f
=
Fiber
.
new
{
result
=
:ok
root
.
transfer
}
f
.
resume
assert_true
f
.
alive?
assert_equal
:ok
,
result
end
assert
(
'Break nested fiber with root fiber transfer'
)
do
root
=
Fiber
.
current
result
=
nil
f2
=
nil
f1
=
Fiber
.
new
{
Fiber
.
yield
f2
.
resume
result
=
:f1
}
f2
=
Fiber
.
new
{
result
=
:to_root
root
.
transfer
:from_f2
result
=
:f2
}
assert_equal
:from_f2
,
f1
.
resume
assert_equal
:to_root
,
result
assert_equal
:f2
,
f2
.
transfer
assert_equal
:f2
,
result
assert_false
f2
.
alive?
assert_equal
:f1
,
f1
.
resume
assert_equal
:f1
,
result
assert_false
f1
.
alive?
end
assert
(
'CRuby Fiber#transfer test.'
)
do
ary
=
[]
f2
=
nil
f1
=
Fiber
.
new
{
ary
<<
f2
.
transfer
(
:foo
)
:ok
}
f2
=
Fiber
.
new
{
ary
<<
f1
.
transfer
(
:baz
)
:ng
}
assert_equal
:ok
,
f1
.
transfer
assert_equal
[
:baz
],
ary
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment