1# Thread and Fiber
2
3assert_equal %q{ok}, %q{
4  Thread.new{
5  }.join
6  :ok
7}
8assert_equal %q{ok}, %q{
9  Thread.new{
10    :ok
11  }.value
12}
13assert_equal %q{20100}, %q{
14  v = 0
15  (1..200).map{|i|
16    Thread.new{
17      i
18    }
19  }.each{|t|
20    v += t.value
21  }
22  v
23}
24assert_equal %q{5000}, %q{
25  5000.times{|e|
26    (1..2).map{
27      Thread.new{
28      }
29    }.each{|e|
30      e.join()
31    }
32  }
33}
34assert_equal %q{5000}, %q{
35  5000.times{|e|
36    (1..2).map{
37      Thread.new{
38      }
39    }.each{|e|
40      e.join(1000000000)
41    }
42  }
43}
44assert_equal %q{5000}, %q{
45  5000.times{
46    t = Thread.new{}
47    while t.alive?
48      Thread.pass
49    end
50  }
51}
52assert_equal %q{100}, %q{
53  100.times{
54    Thread.new{loop{Thread.pass}}
55  }
56}
57assert_equal %q{ok}, %q{
58  Thread.new{
59    :ok
60  }.join.value
61}
62assert_equal %q{ok}, %q{
63  begin
64    Thread.new{
65      raise "ok"
66    }.join
67  rescue => e
68    e
69  end
70}
71assert_equal %q{ok}, %q{
72  ans = nil
73  t = Thread.new{
74    begin
75      sleep 0.5
76    ensure
77      ans = :ok
78    end
79  }
80  Thread.pass
81  t.kill
82  t.join
83  ans
84}
85assert_equal %q{ok}, %q{
86  t = Thread.new{
87    sleep
88  }
89  sleep 0.1
90  t.raise
91  begin
92    t.join
93    :ng
94  rescue
95    :ok
96  end
97}
98assert_equal %q{ok}, %q{
99  t = Thread.new{
100    loop{}
101  }
102  Thread.pass
103  t.raise
104  begin
105    t.join
106    :ng
107  rescue
108    :ok
109  end
110}
111assert_equal %q{ok}, %q{
112  t = Thread.new{
113  }
114  Thread.pass
115  t.join
116  t.raise # raise to exited thread
117  begin
118    t.join
119    :ok
120  rescue
121    :ng
122  end
123}
124assert_equal %q{run}, %q{
125  t = Thread.new{
126    loop{}
127  }
128  st = t.status
129  t.kill
130  st
131}
132assert_equal %q{sleep}, %q{
133  t = Thread.new{
134    sleep
135  }
136  sleep 0.1
137  st = t.status
138  t.kill
139  st
140}
141assert_equal %q{false}, %q{
142  t = Thread.new{
143  }
144  t.kill
145  sleep 0.1
146  t.status
147}
148assert_equal %q{[ThreadGroup, true]}, %q{
149  ptg = Thread.current.group
150  Thread.new{
151    ctg = Thread.current.group
152    [ctg.class, ctg == ptg]
153  }.value
154}
155assert_equal %q{[1, 1]}, %q{
156  thg = ThreadGroup.new
157
158  t = Thread.new{
159    thg.add Thread.current
160    sleep
161  }
162  sleep 0.1
163  [thg.list.size, ThreadGroup::Default.list.size]
164}
165assert_equal %q{true}, %q{
166  thg = ThreadGroup.new
167
168  t = Thread.new{sleep 5}
169  thg.add t
170  thg.list.include?(t)
171}
172assert_equal %q{[true, nil, true]}, %q{
173  /a/ =~ 'a'
174  $a = $~
175  Thread.new{
176    $b = $~
177    /b/ =~ 'b'
178    $c = $~
179  }.join
180  $d = $~
181  [$a == $d, $b, $c != $d]
182}
183assert_equal %q{11}, %q{
184  Thread.current[:a] = 1
185  Thread.new{
186    Thread.current[:a] = 10
187    Thread.pass
188    Thread.current[:a]
189  }.value + Thread.current[:a]
190}
191assert_normal_exit %q{
192  begin
193    100.times do |i|
194      begin
195        th = Thread.start(Thread.current) {|u| u.raise }
196        raise
197      rescue
198      ensure
199        th.join
200      end
201    end
202  rescue
203  end
204}, '[ruby-dev:31371]'
205
206assert_equal 'true', %{
207  t = Thread.new { loop {} }
208  begin
209    pid = fork {
210      exit t.status != "run"
211    }
212    Process.wait pid
213    $?.success?
214  rescue NotImplementedError
215    true
216  end
217}
218
219assert_equal 'ok', %{
220  open("zzz.rb", "w") do |f|
221    f.puts <<-END
222      begin
223        Thread.new { fork { GC.start } }.join
224        pid, status = Process.wait2
225        $result = status.success? ? :ok : :ng
226      rescue NotImplementedError
227        $result = :ok
228      end
229    END
230  end
231  require "./zzz.rb"
232  $result
233}
234
235assert_finish 3, %{
236  th = Thread.new {sleep 2}
237  th.join(1)
238  th.join
239}
240
241assert_finish 3, %{
242  require 'timeout'
243  th = Thread.new {sleep 2}
244  begin
245    Timeout.timeout(1) {th.join}
246  rescue Timeout::Error
247  end
248  th.join
249}
250
251assert_normal_exit %q{
252  STDERR.reopen(STDOUT)
253  exec "/"
254}
255
256assert_normal_exit %q{
257  (0..10).map {
258    Thread.new {
259     10000.times {
260        Object.new.to_s
261      }
262    }
263  }.each {|t|
264    t.join
265  }
266}
267
268assert_equal 'ok', %q{
269  def m
270    t = Thread.new { while true; // =~ "" end }
271    sleep 0.1
272    10.times {
273      if /((ab)*(ab)*)*(b)/ =~ "ab"*7
274        return :ng if !$4
275        return :ng if $~.size != 5
276      end
277    }
278    :ok
279  ensure
280    Thread.kill t
281  end
282  m
283}, '[ruby-dev:34492]'
284
285assert_normal_exit %q{
286  at_exit { Fiber.new{}.resume }
287}
288
289assert_normal_exit %q{
290  g = enum_for(:local_variables)
291  loop { g.next }
292}, '[ruby-dev:34128]'
293
294assert_normal_exit %q{
295  g = enum_for(:block_given?)
296  loop { g.next }
297}, '[ruby-dev:34128]'
298
299assert_normal_exit %q{
300  g = enum_for(:binding)
301  loop { g.next }
302}, '[ruby-dev:34128]'
303
304assert_normal_exit %q{
305  g = "abc".enum_for(:scan, /./)
306  loop { g.next }
307}, '[ruby-dev:34128]'
308
309assert_normal_exit %q{
310  g = Module.enum_for(:new)
311  loop { g.next }
312}, '[ruby-dev:34128]'
313
314assert_normal_exit %q{
315  Fiber.new(&Object.method(:class_eval)).resume("foo")
316}, '[ruby-dev:34128]'
317
318assert_normal_exit %q{
319  Thread.new("foo", &Object.method(:class_eval)).join
320}, '[ruby-dev:34128]'
321
322assert_equal 'ok', %q{
323  begin
324    Thread.new { Thread.stop }
325    Thread.stop
326    :ng
327  rescue Exception
328    :ok
329  end
330}
331
332assert_equal 'ok', %q{
333  begin
334    m1, m2 = Mutex.new, Mutex.new
335    Thread.new { m1.lock; sleep 1; m2.lock }
336    m2.lock; sleep 1; m1.lock
337    :ng
338  rescue Exception
339    :ok
340  end
341}
342
343assert_equal 'ok', %q{
344  m = Mutex.new
345  Thread.new { m.lock }; sleep 1; m.lock
346  :ok
347}
348
349assert_equal 'ok', %q{
350  m = Mutex.new
351  Thread.new { m.lock }; m.lock
352  :ok
353}
354
355assert_equal 'ok', %q{
356  m = Mutex.new
357  Thread.new { m.lock }.join; m.lock
358  :ok
359}
360
361assert_equal 'ok', %q{
362  m = Mutex.new
363  Thread.new { m.lock; sleep 2 }
364  sleep 1; m.lock
365  :ok
366}
367
368assert_equal 'ok', %q{
369  m = Mutex.new
370  Thread.new { m.lock; sleep 2; m.unlock }
371  sleep 1; m.lock
372  :ok
373}
374
375assert_equal 'ok', %q{
376  t = Thread.new {`echo`}
377  t.join
378  $? ? :ng : :ok
379}, '[ruby-dev:35414]'
380
381assert_equal 'ok', %q{
382  begin
383    100.times{
384      (1..100).map{ Thread.new(true) {|x| x == false } }.each{|th| th.join}
385    }
386  rescue NoMemoryError, StandardError
387  end
388  :ok
389}
390
391assert_equal 'ok', %{
392  open("zzz.rb", "w") do |f|
393    f.puts <<-END
394      begin
395        m = Mutex.new
396        Thread.new { m.lock; sleep 1 }
397        sleep 0.3
398        parent = Thread.current
399        Thread.new do
400          sleep 0.3
401          begin
402            fork { GC.start }
403          rescue Exception
404            parent.raise $!
405          end
406        end
407        m.lock
408        pid, status = Process.wait2
409        $result = status.success? ? :ok : :ng
410      rescue NotImplementedError
411        $result = :ok
412      end
413    END
414  end
415  require "./zzz.rb"
416  $result
417}
418
419assert_finish 3, %q{
420  require 'thread'
421
422  lock = Mutex.new
423  cond = ConditionVariable.new
424  t = Thread.new do
425    lock.synchronize do
426      cond.wait(lock)
427    end
428  end
429
430  begin
431    pid = fork do
432      # Child
433      STDOUT.write "This is the child process.\n"
434      STDOUT.write "Child process exiting.\n"
435    end
436    Process.waitpid(pid)
437  rescue NotImplementedError
438  end
439}, '[ruby-core:23572]'
440
441assert_equal 'ok', %q{
442  begin
443    Process.waitpid2(fork {sleep 1})[1].success? ? 'ok' : 'ng'
444  rescue NotImplementedError
445    'ok'
446  end
447}
448
449assert_equal 'foo', %q{
450  f = proc {|s| /#{ sleep 1; s }/o }
451  [ Thread.new {            f.call("foo"); nil },
452    Thread.new { sleep 0.5; f.call("bar"); nil },
453  ].each {|t| t.join }
454  GC.start
455  f.call.source
456}
457