File: fiber2.rb

package info (click to toggle)
mruby 3.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,584 kB
  • sloc: ansic: 51,933; ruby: 29,510; yacc: 7,077; cpp: 517; makefile: 51; sh: 42
file content (155 lines) | stat: -rw-r--r-- 4,944 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# This file tests fiber switching crossing C functions

unless RUBY_ENGINE == "mruby"
  class Fiber
    alias resume_by_c_func resume
    alias resume_by_c_method resume

    class << self
      alias yield_by_c_func yield

      def yield_by_c_method(*args)
        raise FiberError, "ycan't cross C function boundary"
      end
    end
  end

  def Proc.c_tunnel
    yield
  end
end

begin
  $fiber_test_activity = __FILE__

  assert('Call Fiber#resume nested with C') do
    assert_equal "ok1", Fiber.new { Fiber.new { "ok1" }.resume_by_c_func }.resume_by_c_func
    assert_equal "ok2", Fiber.new { Fiber.new { "ok2" }.resume_by_c_method }.resume_by_c_func
    assert_equal "ok3", Fiber.new { Fiber.new { "ok3" }.resume_by_c_func }.resume_by_c_method
    assert_equal "ok4", Fiber.new { Fiber.new { "ok4" }.resume_by_c_method }.resume_by_c_method
    assert_equal "ok5", Fiber.new { Proc.c_tunnel { Fiber.new { "ok5" }.resume_by_c_func } }.resume_by_c_func
    assert_equal "ok6", Fiber.new { Proc.c_tunnel { Fiber.new { "ok6" }.resume_by_c_method } }.resume_by_c_func
    assert_equal "ok7", Fiber.new { Proc.c_tunnel { Fiber.new { "ok7" }.resume_by_c_func } }.resume_by_c_method
    assert_equal "ok8", Fiber.new { Proc.c_tunnel { Fiber.new { "ok8" }.resume_by_c_method } }.resume_by_c_method
    assert_equal "ok9", Fiber.new { Proc.c_tunnel { Fiber.new { "ok9" }.resume } }.resume_by_c_func
    assert_equal "ok10", Fiber.new { Proc.c_tunnel { Fiber.new { "ok10" }.resume } }.resume_by_c_method
  end

  assert('Call Fiber#resume and Fiber.yield mixed with C.') do
    assert_equal 1, Fiber.new { Fiber.yield 1 }.resume_by_c_func
    assert_equal 2, Fiber.new { Fiber.yield 2 }.resume_by_c_method
    assert_equal 3, Fiber.new { Fiber.yield_by_c_func 3 }.resume
    assert_equal 4, Fiber.new { Fiber.yield_by_c_func 4 }.resume_by_c_func
    assert_equal 5, Fiber.new { Fiber.yield_by_c_func 5 }.resume_by_c_method
    assert_raise(FiberError) { Fiber.new { Fiber.yield_by_c_method "bad" }.resume }
    assert_raise(FiberError) { Fiber.new { Fiber.yield_by_c_method "bad" }.resume_by_c_func }
    assert_raise(FiberError) { Fiber.new { Fiber.yield_by_c_method "bad" }.resume_by_c_method }

    result = []
    f1 = Fiber.new { result << Fiber.new { Fiber.yield 1; "bad" }.resume_by_c_func; 2 }
    f2 = Fiber.new { result << f1.resume; 3 }
    result << f2.resume
    assert_equal [1, 2, 3], result

    f1 = Fiber.new {
      -> {
        Fiber.yield 1
        Fiber.yield_by_c_func 2
        f2 = Fiber.new {
          -> {
            Fiber.yield_by_c_func 3
            Fiber.yield 4
            Fiber.yield_by_c_func 5
            Fiber.yield 6
          }.call
          7
        }
        Fiber.yield f2.resume_by_c_func
        Fiber.yield f2.resume
        Fiber.yield f2.resume_by_c_method
        Fiber.yield f2.resume
        Fiber.yield f2.resume_by_c_func
        Fiber.yield 8
      }.call
      Fiber.yield 9
      10
    }
    result = []
    10.times { result << f1.resume }
    assert_equal [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], result
  end

  assert('Call Fiber#resume and Fiber.yield mixed with C and raising exceptions') do
    f = Fiber.new do
      raise ZeroDivisionError
    rescue
      Fiber.yield "rescue"
      "pass1"
    ensure
      Fiber.yield "ensure"
    end
    assert_equal "rescue", f.resume_by_c_method
    assert_equal "ensure", f.resume_by_c_method
    assert_equal "pass1", f.resume_by_c_method
    assert_raise(FiberError) { f.resume_by_c_method }

    f = Fiber.new do
      raise ZeroDivisionError
    rescue
      Fiber.yield "rescue"
      "pass2"
    ensure
      Fiber.yield "ensure"
    end
    assert_equal "rescue", f.resume_by_c_func
    assert_equal "ensure", f.resume_by_c_func
    assert_equal "pass2", f.resume_by_c_func
    assert_raise(FiberError) { f.resume_by_c_func }

    f2 = Fiber.new do
      -> do
        Fiber.yield 1
        raise "3"
      ensure
        Fiber.yield 2
      end.call
      "NOT REACH 1"
    end
    f1 = Fiber.new do
      Fiber.yield f2.resume_by_c_func
      begin
        Fiber.yield f2.resume
        Fiber.yield f2.resume_by_c_method
        Fiber.yield "NOT REACH 2"
      rescue => e
        Fiber.yield e.message
        Fiber.yield 4
      ensure
        Fiber.yield 5
      end
      Fiber.yield 6
      7
    end
    result = []
    7.times { result << f1.resume }
    assert_equal [1, 2, "3", 4, 5, 6, 7], result
  end

  assert('Call Fiber#transfer with C') do
    assert_equal "ok1", Fiber.new { Fiber.new { "ok1" }.resume_by_c_method }.transfer
    assert_equal "ok2", Fiber.new { Fiber.new { "ok2" }.resume_by_c_func }.transfer
    assert_raise(FiberError) { Proc.c_tunnel { Fiber.new { "BAD!" }.transfer } }

    b = Fiber.current
    a = Fiber.new {
      Proc.c_tunnel {
        Fiber.new {
          b.transfer
        }.resume
      }
    }
    assert_raise(FiberError) { a.transfer }
  end
ensure
  $fiber_test_activity = nil
end