PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/test/ruby/test_thread.rb

http://github.com/ruby/ruby
Ruby | 1392 lines | 1220 code | 157 blank | 15 comment | 35 complexity | dd2acf33f65c280e533bc44aec906fc0 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # -*- coding: us-ascii -*-
  2. # frozen_string_literal: false
  3. require 'test/unit'
  4. require "rbconfig/sizeof"
  5. require "timeout"
  6. class TestThread < Test::Unit::TestCase
  7. class Thread < ::Thread
  8. Threads = []
  9. def self.new(*)
  10. th = super
  11. Threads << th
  12. th
  13. end
  14. end
  15. def setup
  16. Thread::Threads.clear
  17. end
  18. def teardown
  19. Thread::Threads.each do |t|
  20. t.kill if t.alive?
  21. begin
  22. t.join
  23. rescue Exception
  24. end
  25. end
  26. end
  27. def test_inspect
  28. line = __LINE__+1
  29. th = Module.new {break module_eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")}.start{}
  30. s = th.inspect
  31. assert_include(s, "::C\u{30b9 30ec 30c3 30c9}:")
  32. assert_include(s, " #{__FILE__}:#{line} ")
  33. assert_equal(s, th.to_s)
  34. ensure
  35. th.join
  36. end
  37. def test_inspect_with_fiber
  38. inspect1 = inspect2 = nil
  39. Thread.new{
  40. inspect1 = Thread.current.inspect
  41. Fiber.new{
  42. inspect2 = Thread.current.inspect
  43. }.resume
  44. }.join
  45. assert_equal inspect1, inspect2, '[Bug #13689]'
  46. end
  47. def test_main_thread_variable_in_enumerator
  48. assert_equal Thread.main, Thread.current
  49. Thread.current.thread_variable_set :foo, "bar"
  50. thread, value = Fiber.new {
  51. Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
  52. }.resume
  53. assert_equal Thread.current, thread
  54. assert_equal Thread.current.thread_variable_get(:foo), value
  55. end
  56. def test_thread_variable_in_enumerator
  57. Thread.new {
  58. Thread.current.thread_variable_set :foo, "bar"
  59. thread, value = Fiber.new {
  60. Fiber.yield [Thread.current, Thread.current.thread_variable_get(:foo)]
  61. }.resume
  62. assert_equal Thread.current, thread
  63. assert_equal Thread.current.thread_variable_get(:foo), value
  64. }.join
  65. end
  66. def test_thread_variables
  67. assert_equal [], Thread.new { Thread.current.thread_variables }.join.value
  68. t = Thread.new {
  69. Thread.current.thread_variable_set(:foo, "bar")
  70. Thread.current.thread_variables
  71. }
  72. assert_equal [:foo], t.join.value
  73. end
  74. def test_thread_variable?
  75. Thread.new { assert_not_send([Thread.current, :thread_variable?, "foo"]) }.value
  76. t = Thread.new {
  77. Thread.current.thread_variable_set("foo", "bar")
  78. }.join
  79. assert_send([t, :thread_variable?, "foo"])
  80. assert_send([t, :thread_variable?, :foo])
  81. assert_not_send([t, :thread_variable?, :bar])
  82. end
  83. def test_thread_variable_strings_and_symbols_are_the_same_key
  84. t = Thread.new {}.join
  85. t.thread_variable_set("foo", "bar")
  86. assert_equal "bar", t.thread_variable_get(:foo)
  87. end
  88. def test_thread_variable_frozen
  89. t = Thread.new { }.join
  90. t.freeze
  91. assert_raise(FrozenError) do
  92. t.thread_variable_set(:foo, "bar")
  93. end
  94. end
  95. def test_mutex_synchronize
  96. m = Thread::Mutex.new
  97. r = 0
  98. num_threads = 10
  99. loop=100
  100. (1..num_threads).map{
  101. Thread.new{
  102. loop.times{
  103. m.synchronize{
  104. tmp = r
  105. # empty and waste loop for making thread preemption
  106. 100.times {
  107. }
  108. r = tmp + 1
  109. }
  110. }
  111. }
  112. }.each{|e|
  113. e.join
  114. }
  115. assert_equal(num_threads*loop, r)
  116. end
  117. def test_mutex_synchronize_yields_no_block_params
  118. bug8097 = '[ruby-core:53424] [Bug #8097]'
  119. assert_empty(Thread::Mutex.new.synchronize {|*params| break params}, bug8097)
  120. end
  121. def test_local_barrier
  122. dir = File.dirname(__FILE__)
  123. lbtest = File.join(dir, "lbtest.rb")
  124. $:.unshift File.join(File.dirname(dir), 'ruby')
  125. $:.shift
  126. 3.times {
  127. `#{EnvUtil.rubybin} #{lbtest}`
  128. assert_not_predicate($?, :coredump?, '[ruby-dev:30653]')
  129. }
  130. end
  131. def test_priority
  132. c1 = c2 = 0
  133. run = true
  134. t1 = Thread.new { c1 += 1 while run }
  135. t1.priority = 3
  136. t2 = Thread.new { c2 += 1 while run }
  137. t2.priority = -3
  138. assert_equal(3, t1.priority)
  139. assert_equal(-3, t2.priority)
  140. sleep 0.5
  141. 5.times do
  142. assert_not_predicate(t1, :stop?)
  143. assert_not_predicate(t2, :stop?)
  144. break if c1 > c2
  145. sleep 0.1
  146. end
  147. run = false
  148. t1.kill
  149. t2.kill
  150. assert_operator(c1, :>, c2, "[ruby-dev:33124]") # not guaranteed
  151. t1.join
  152. t2.join
  153. end
  154. def test_new
  155. assert_raise(ThreadError) do
  156. Thread.new
  157. end
  158. t1 = Thread.new { sleep }
  159. assert_raise(ThreadError) do
  160. t1.instance_eval { initialize { } }
  161. end
  162. t2 = Thread.new(&method(:sleep).to_proc)
  163. assert_raise(ThreadError) do
  164. t2.instance_eval { initialize { } }
  165. end
  166. ensure
  167. t1&.kill&.join
  168. t2&.kill&.join
  169. end
  170. def test_new_symbol_proc
  171. bug = '[ruby-core:80147] [Bug #13313]'
  172. assert_ruby_status([], "#{<<-"begin;"}\n#{<<-'end;'}", bug)
  173. begin;
  174. exit("1" == Thread.start(1, &:to_s).value)
  175. end;
  176. end
  177. def test_join
  178. t = Thread.new { sleep }
  179. assert_nil(t.join(0.05))
  180. ensure
  181. t&.kill&.join
  182. end
  183. def test_join2
  184. ok = false
  185. t1 = Thread.new { ok = true; sleep }
  186. Thread.pass until ok
  187. Thread.pass until t1.stop?
  188. t2 = Thread.new do
  189. Thread.pass while ok
  190. t1.join(0.01)
  191. end
  192. t3 = Thread.new do
  193. ok = false
  194. t1.join
  195. end
  196. assert_nil(t2.value)
  197. t1.wakeup
  198. assert_equal(t1, t3.value)
  199. ensure
  200. t1&.kill
  201. t2&.kill
  202. t3&.kill
  203. end
  204. { 'FIXNUM_MAX' => RbConfig::LIMITS['FIXNUM_MAX'],
  205. 'UINT64_MAX' => RbConfig::LIMITS['UINT64_MAX'],
  206. 'INFINITY' => Float::INFINITY
  207. }.each do |name, limit|
  208. define_method("test_join_limit_#{name}") do
  209. t = Thread.new {}
  210. assert_same t, t.join(limit), "limit=#{limit.inspect}"
  211. end
  212. end
  213. { 'minus_1' => -1,
  214. 'minus_0_1' => -0.1,
  215. 'FIXNUM_MIN' => RbConfig::LIMITS['FIXNUM_MIN'],
  216. 'INT64_MIN' => RbConfig::LIMITS['INT64_MIN'],
  217. 'minus_INFINITY' => -Float::INFINITY
  218. }.each do |name, limit|
  219. define_method("test_join_limit_negative_#{name}") do
  220. t = Thread.new { sleep }
  221. begin
  222. assert_nothing_raised(Timeout::Error) do
  223. Timeout.timeout(30) do
  224. assert_nil t.join(limit), "limit=#{limit.inspect}"
  225. end
  226. end
  227. ensure
  228. t.kill
  229. end
  230. end
  231. end
  232. def test_kill_main_thread
  233. assert_in_out_err([], <<-INPUT, %w(1), [])
  234. p 1
  235. Thread.kill Thread.current
  236. p 2
  237. INPUT
  238. end
  239. def test_kill_wrong_argument
  240. bug4367 = '[ruby-core:35086]'
  241. assert_raise(TypeError, bug4367) {
  242. Thread.kill(nil)
  243. }
  244. o = Object.new
  245. assert_raise(TypeError, bug4367) {
  246. Thread.kill(o)
  247. }
  248. end
  249. def test_kill_thread_subclass
  250. c = Class.new(Thread)
  251. t = c.new { sleep 10 }
  252. assert_nothing_raised { Thread.kill(t) }
  253. assert_equal(nil, t.value)
  254. end
  255. def test_exit
  256. s = 0
  257. Thread.new do
  258. s += 1
  259. Thread.exit
  260. s += 2
  261. end.join
  262. assert_equal(1, s)
  263. end
  264. def test_wakeup
  265. s = 0
  266. t = Thread.new do
  267. s += 1
  268. Thread.stop
  269. s += 1
  270. end
  271. Thread.pass until t.stop?
  272. sleep 1 if RubyVM::MJIT.enabled? # t.stop? behaves unexpectedly with --jit-wait
  273. assert_equal(1, s)
  274. t.wakeup
  275. Thread.pass while t.alive?
  276. assert_equal(2, s)
  277. assert_raise(ThreadError) { t.wakeup }
  278. ensure
  279. t&.kill&.join
  280. end
  281. def test_stop
  282. assert_in_out_err([], <<-INPUT, %w(2), [])
  283. begin
  284. Thread.stop
  285. p 1
  286. rescue ThreadError
  287. p 2
  288. end
  289. INPUT
  290. end
  291. def test_list
  292. assert_in_out_err([], <<-INPUT) do |r, e|
  293. t1 = Thread.new { sleep }
  294. Thread.pass
  295. t2 = Thread.new { loop { Thread.pass } }
  296. Thread.new { }.join
  297. p [Thread.current, t1, t2].map{|t| t.object_id }.sort
  298. p Thread.list.map{|t| t.object_id }.sort
  299. INPUT
  300. assert_equal(r.first, r.last)
  301. assert_equal([], e)
  302. end
  303. end
  304. def test_main
  305. assert_in_out_err([], <<-INPUT, %w(true false), [])
  306. p Thread.main == Thread.current
  307. Thread.new { p Thread.main == Thread.current }.join
  308. INPUT
  309. end
  310. def test_abort_on_exception
  311. assert_in_out_err([], <<-INPUT, %w(false 1), [])
  312. p Thread.abort_on_exception
  313. begin
  314. t = Thread.new {
  315. Thread.current.report_on_exception = false
  316. raise
  317. }
  318. Thread.pass until t.stop?
  319. p 1
  320. rescue
  321. p 2
  322. end
  323. INPUT
  324. assert_in_out_err([], <<-INPUT, %w(true 2), [])
  325. Thread.abort_on_exception = true
  326. p Thread.abort_on_exception
  327. begin
  328. Thread.new {
  329. Thread.current.report_on_exception = false
  330. raise
  331. }
  332. sleep 0.5
  333. p 1
  334. rescue
  335. p 2
  336. end
  337. INPUT
  338. assert_in_out_err(%w(--disable-gems -d), <<-INPUT, %w(false 2), %r".+")
  339. p Thread.abort_on_exception
  340. begin
  341. t = Thread.new { raise }
  342. Thread.pass until t.stop?
  343. p 1
  344. rescue
  345. p 2
  346. end
  347. INPUT
  348. assert_in_out_err([], <<-INPUT, %w(false true 2), [])
  349. p Thread.abort_on_exception
  350. begin
  351. ok = false
  352. t = Thread.new {
  353. Thread.current.report_on_exception = false
  354. Thread.pass until ok
  355. raise
  356. }
  357. t.abort_on_exception = true
  358. p t.abort_on_exception
  359. ok = 1
  360. sleep 1
  361. p 1
  362. rescue
  363. p 2
  364. end
  365. INPUT
  366. end
  367. def test_report_on_exception
  368. assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
  369. begin;
  370. q1 = Thread::Queue.new
  371. q2 = Thread::Queue.new
  372. assert_equal(true, Thread.report_on_exception,
  373. "global flag is true by default")
  374. assert_equal(true, Thread.current.report_on_exception,
  375. "the main thread has report_on_exception=true")
  376. Thread.report_on_exception = true
  377. Thread.current.report_on_exception = false
  378. assert_equal(true,
  379. Thread.start {Thread.current.report_on_exception}.value,
  380. "should not inherit from the parent thread but from the global flag")
  381. assert_warn("", "exception should be ignored silently when false") {
  382. th = Thread.start {
  383. Thread.current.report_on_exception = false
  384. q1.push(Thread.current.report_on_exception)
  385. raise "report 1"
  386. }
  387. assert_equal(false, q1.pop)
  388. Thread.pass while th.alive?
  389. assert_raise(RuntimeError) { th.join }
  390. }
  391. assert_warn(/report 2/, "exception should be reported when true") {
  392. th = Thread.start {
  393. q1.push(Thread.current.report_on_exception = true)
  394. raise "report 2"
  395. }
  396. assert_equal(true, q1.pop)
  397. Thread.pass while th.alive?
  398. assert_raise(RuntimeError) { th.join }
  399. }
  400. assert_warn("", "the global flag should not affect already started threads") {
  401. Thread.report_on_exception = false
  402. th = Thread.start {
  403. q2.pop
  404. q1.push(Thread.current.report_on_exception)
  405. raise "report 3"
  406. }
  407. q2.push(Thread.report_on_exception = true)
  408. assert_equal(false, q1.pop)
  409. Thread.pass while th.alive?
  410. assert_raise(RuntimeError) { th.join }
  411. }
  412. assert_warn(/report 4/, "should defaults to the global flag at the start") {
  413. Thread.report_on_exception = true
  414. th = Thread.start {
  415. q1.push(Thread.current.report_on_exception)
  416. raise "report 4"
  417. }
  418. assert_equal(true, q1.pop)
  419. Thread.pass while th.alive?
  420. assert_raise(RuntimeError) { th.join }
  421. }
  422. assert_warn(/report 5/, "should first report and then raise with report_on_exception + abort_on_exception") {
  423. th = Thread.start {
  424. Thread.current.report_on_exception = true
  425. Thread.current.abort_on_exception = true
  426. q2.pop
  427. raise "report 5"
  428. }
  429. assert_raise_with_message(RuntimeError, "report 5") {
  430. q2.push(true)
  431. Thread.pass while th.alive?
  432. }
  433. assert_raise(RuntimeError) { th.join }
  434. }
  435. end;
  436. end
  437. def test_status_and_stop_p
  438. a = ::Thread.new {
  439. Thread.current.report_on_exception = false
  440. raise("die now")
  441. }
  442. b = Thread.new { Thread.stop }
  443. c = Thread.new { Thread.exit }
  444. e = Thread.current
  445. Thread.pass while a.alive? or !b.stop? or c.alive?
  446. assert_equal(nil, a.status)
  447. assert_predicate(a, :stop?)
  448. assert_equal("sleep", b.status)
  449. assert_predicate(b, :stop?)
  450. assert_equal(false, c.status)
  451. assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect)
  452. assert_predicate(c, :stop?)
  453. es1 = e.status
  454. es2 = e.stop?
  455. assert_equal(["run", false], [es1, es2])
  456. assert_raise(RuntimeError) { a.join }
  457. ensure
  458. b&.kill&.join
  459. c&.join
  460. end
  461. def test_switch_while_busy_loop
  462. bug1402 = "[ruby-dev:38319] [Bug #1402]"
  463. flag = true
  464. th = Thread.current
  465. waiter = Thread.start {
  466. sleep 0.1
  467. flag = false
  468. sleep 1
  469. th.raise(bug1402)
  470. }
  471. assert_nothing_raised(RuntimeError, bug1402) do
  472. nil while flag
  473. end
  474. assert(!flag, bug1402)
  475. ensure
  476. waiter&.kill&.join
  477. end
  478. def test_thread_local
  479. t = Thread.new { sleep }
  480. assert_equal(false, t.key?(:foo))
  481. t["foo"] = "foo"
  482. t["bar"] = "bar"
  483. t["baz"] = "baz"
  484. assert_equal(true, t.key?(:foo))
  485. assert_equal(true, t.key?("foo"))
  486. assert_equal(false, t.key?(:qux))
  487. assert_equal(false, t.key?("qux"))
  488. assert_equal([:foo, :bar, :baz].sort, t.keys.sort)
  489. ensure
  490. t&.kill&.join
  491. end
  492. def test_thread_local_fetch
  493. t = Thread.new { sleep }
  494. assert_equal(false, t.key?(:foo))
  495. t["foo"] = "foo"
  496. t["bar"] = "bar"
  497. t["baz"] = "baz"
  498. x = nil
  499. assert_equal("foo", t.fetch(:foo, 0))
  500. assert_equal("foo", t.fetch(:foo) {x = true})
  501. assert_nil(x)
  502. assert_equal("foo", t.fetch("foo", 0))
  503. assert_equal("foo", t.fetch("foo") {x = true})
  504. assert_nil(x)
  505. x = nil
  506. assert_equal(0, t.fetch(:qux, 0))
  507. assert_equal(1, t.fetch(:qux) {x = 1})
  508. assert_equal(1, x)
  509. assert_equal(2, t.fetch("qux", 2))
  510. assert_equal(3, t.fetch("qux") {x = 3})
  511. assert_equal(3, x)
  512. e = assert_raise(KeyError) {t.fetch(:qux)}
  513. assert_equal(:qux, e.key)
  514. assert_equal(t, e.receiver)
  515. ensure
  516. t&.kill&.join
  517. end
  518. def test_thread_local_security
  519. Thread.new do
  520. Thread.current[:foo] = :bar
  521. Thread.current.freeze
  522. assert_raise(FrozenError) do
  523. Thread.current[:foo] = :baz
  524. end
  525. end.join
  526. end
  527. def test_thread_local_dynamic_symbol
  528. bug10667 = '[ruby-core:67185] [Bug #10667]'
  529. t = Thread.new {}.join
  530. key_str = "foo#{rand}"
  531. key_sym = key_str.to_sym
  532. t.thread_variable_set(key_str, "bar")
  533. assert_equal("bar", t.thread_variable_get(key_str), "#{bug10667}: string key")
  534. assert_equal("bar", t.thread_variable_get(key_sym), "#{bug10667}: symbol key")
  535. end
  536. def test_select_wait
  537. assert_nil(IO.select(nil, nil, nil, 0.001))
  538. t = Thread.new do
  539. IO.select(nil, nil, nil, nil)
  540. end
  541. Thread.pass until t.stop?
  542. assert_predicate(t, :alive?)
  543. ensure
  544. t&.kill
  545. end
  546. def test_mutex_deadlock
  547. m = Thread::Mutex.new
  548. m.synchronize do
  549. assert_raise(ThreadError) do
  550. m.synchronize do
  551. assert(false)
  552. end
  553. end
  554. end
  555. end
  556. def test_mutex_interrupt
  557. m = Thread::Mutex.new
  558. m.lock
  559. t = Thread.new do
  560. m.lock
  561. :foo
  562. end
  563. Thread.pass until t.stop?
  564. t.kill
  565. assert_nil(t.value)
  566. end
  567. def test_mutex_illegal_unlock
  568. m = Thread::Mutex.new
  569. m.lock
  570. Thread.new do
  571. assert_raise(ThreadError) do
  572. m.unlock
  573. end
  574. end.join
  575. end
  576. def test_mutex_fifo_like_lock
  577. m1 = Thread::Mutex.new
  578. m2 = Thread::Mutex.new
  579. m1.lock
  580. m2.lock
  581. m1.unlock
  582. m2.unlock
  583. assert_equal(false, m1.locked?)
  584. assert_equal(false, m2.locked?)
  585. m3 = Thread::Mutex.new
  586. m1.lock
  587. m2.lock
  588. m3.lock
  589. m1.unlock
  590. m2.unlock
  591. m3.unlock
  592. assert_equal(false, m1.locked?)
  593. assert_equal(false, m2.locked?)
  594. assert_equal(false, m3.locked?)
  595. end
  596. def test_mutex_trylock
  597. m = Thread::Mutex.new
  598. assert_equal(true, m.try_lock)
  599. assert_equal(false, m.try_lock, '[ruby-core:20943]')
  600. Thread.new{
  601. assert_equal(false, m.try_lock)
  602. }.join
  603. m.unlock
  604. end
  605. def test_recursive_outer
  606. arr = []
  607. obj = Struct.new(:foo, :visited).new(arr, false)
  608. arr << obj
  609. def obj.hash
  610. self[:visited] = true
  611. super
  612. raise "recursive_outer should short circuit intermediate calls"
  613. end
  614. assert_nothing_raised {arr.hash}
  615. assert(obj[:visited], "obj.hash was not called")
  616. end
  617. def test_thread_instance_variable
  618. bug4389 = '[ruby-core:35192]'
  619. assert_in_out_err([], <<-INPUT, %w(), [], bug4389)
  620. class << Thread.current
  621. @data = :data
  622. end
  623. INPUT
  624. end
  625. def test_no_valid_cfp
  626. skip 'with win32ole, cannot run this testcase because win32ole redefines Thread#initialize' if defined?(WIN32OLE)
  627. bug5083 = '[ruby-dev:44208]'
  628. assert_equal([], Thread.new(&Module.method(:nesting)).value, bug5083)
  629. assert_instance_of(Thread, Thread.new(:to_s, &Class.new.method(:undef_method)).join, bug5083)
  630. end
  631. def make_handle_interrupt_test_thread1 flag
  632. r = []
  633. ready_q = Queue.new
  634. done_q = Queue.new
  635. th = Thread.new{
  636. begin
  637. Thread.handle_interrupt(RuntimeError => flag){
  638. begin
  639. ready_q << true
  640. done_q.pop
  641. rescue
  642. r << :c1
  643. end
  644. }
  645. rescue
  646. r << :c2
  647. end
  648. }
  649. ready_q.pop
  650. th.raise
  651. begin
  652. done_q << true
  653. th.join
  654. rescue
  655. r << :c3
  656. end
  657. r
  658. end
  659. def test_handle_interrupt
  660. [[:never, :c2],
  661. [:immediate, :c1],
  662. [:on_blocking, :c1]].each{|(flag, c)|
  663. assert_equal([flag, c], [flag] + make_handle_interrupt_test_thread1(flag))
  664. }
  665. # TODO: complex cases are needed.
  666. end
  667. def test_handle_interrupt_invalid_argument
  668. assert_raise(ArgumentError) {
  669. Thread.handle_interrupt(RuntimeError => :immediate) # no block
  670. }
  671. assert_raise(ArgumentError) {
  672. Thread.handle_interrupt(RuntimeError => :xyzzy) {}
  673. }
  674. assert_raise(TypeError) {
  675. Thread.handle_interrupt([]) {} # array
  676. }
  677. end
  678. def for_test_handle_interrupt_with_return
  679. Thread.handle_interrupt(Object => :never){
  680. Thread.current.raise RuntimeError.new("have to be rescured")
  681. return
  682. }
  683. rescue
  684. end
  685. def test_handle_interrupt_with_return
  686. assert_nothing_raised do
  687. for_test_handle_interrupt_with_return
  688. _dummy_for_check_ints=nil
  689. end
  690. end
  691. def test_handle_interrupt_with_break
  692. assert_nothing_raised do
  693. begin
  694. Thread.handle_interrupt(Object => :never){
  695. Thread.current.raise RuntimeError.new("have to be rescured")
  696. break
  697. }
  698. rescue
  699. end
  700. _dummy_for_check_ints=nil
  701. end
  702. end
  703. def test_handle_interrupt_blocking
  704. r = nil
  705. q = Queue.new
  706. e = Class.new(Exception)
  707. th_s = Thread.current
  708. th = Thread.start {
  709. assert_raise(RuntimeError) {
  710. Thread.handle_interrupt(Object => :on_blocking){
  711. begin
  712. q.pop
  713. Thread.current.raise RuntimeError, "will raise in sleep"
  714. r = :ok
  715. sleep
  716. ensure
  717. th_s.raise e, "raise from ensure", $@
  718. end
  719. }
  720. }
  721. }
  722. assert_raise(e) {q << true; th.join}
  723. assert_equal(:ok, r)
  724. end
  725. def test_handle_interrupt_and_io
  726. assert_in_out_err([], <<-INPUT, %w(ok), [])
  727. th_waiting = true
  728. q = Queue.new
  729. t = Thread.new {
  730. Thread.current.report_on_exception = false
  731. Thread.handle_interrupt(RuntimeError => :on_blocking) {
  732. q << true
  733. nil while th_waiting
  734. # async interrupt should be raised _before_ writing puts arguments
  735. puts "ng"
  736. }
  737. }
  738. q.pop
  739. t.raise RuntimeError
  740. th_waiting = false
  741. t.join rescue nil
  742. puts "ok"
  743. INPUT
  744. end
  745. def test_handle_interrupt_and_p
  746. assert_in_out_err([], <<-INPUT, %w(:ok :ok), [])
  747. th_waiting = false
  748. t = Thread.new {
  749. Thread.current.report_on_exception = false
  750. Thread.handle_interrupt(RuntimeError => :on_blocking) {
  751. th_waiting = true
  752. nil while th_waiting
  753. # p shouldn't provide interruptible point
  754. p :ok
  755. p :ok
  756. }
  757. }
  758. Thread.pass until th_waiting
  759. t.raise RuntimeError
  760. th_waiting = false
  761. t.join rescue nil
  762. INPUT
  763. end
  764. def test_handle_interrupted?
  765. q = Thread::Queue.new
  766. Thread.handle_interrupt(RuntimeError => :never){
  767. done = false
  768. th = Thread.new{
  769. q.push :e
  770. begin
  771. begin
  772. Thread.pass until done
  773. rescue
  774. q.push :ng1
  775. end
  776. begin
  777. Thread.handle_interrupt(Object => :immediate){} if Thread.pending_interrupt?
  778. rescue RuntimeError
  779. q.push :ok
  780. end
  781. rescue
  782. q.push :ng2
  783. ensure
  784. q.push :ng3
  785. end
  786. }
  787. q.pop
  788. th.raise
  789. done = true
  790. th.join
  791. assert_equal(:ok, q.pop)
  792. }
  793. end
  794. def test_thread_timer_and_ensure
  795. assert_normal_exit(<<_eom, 'r36492', timeout: 10)
  796. flag = false
  797. t = Thread.new do
  798. begin
  799. sleep
  800. ensure
  801. 1 until flag
  802. end
  803. end
  804. Thread.pass until t.status == "sleep"
  805. t.kill
  806. t.alive? == true
  807. flag = true
  808. t.join
  809. _eom
  810. end
  811. def test_uninitialized
  812. c = Class.new(Thread) {def initialize; end}
  813. assert_raise(ThreadError) { c.new.start }
  814. bug11959 = '[ruby-core:72732] [Bug #11959]'
  815. c = Class.new(Thread) {def initialize; exit; end}
  816. assert_raise(ThreadError, bug11959) { c.new }
  817. c = Class.new(Thread) {def initialize; raise; end}
  818. assert_raise(ThreadError, bug11959) { c.new }
  819. c = Class.new(Thread) {
  820. def initialize
  821. pending = pending_interrupt?
  822. super {pending}
  823. end
  824. }
  825. assert_equal(false, c.new.value, bug11959)
  826. end
  827. def test_backtrace
  828. Thread.new{
  829. assert_equal(Array, Thread.main.backtrace.class)
  830. }.join
  831. t = Thread.new{}
  832. t.join
  833. assert_equal(nil, t.backtrace)
  834. end
  835. def test_thread_timer_and_interrupt
  836. bug5757 = '[ruby-dev:44985]'
  837. pid = nil
  838. cmd = 'Signal.trap(:INT, "DEFAULT"); pipe=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; pipe[0].read'
  839. opt = {}
  840. opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM
  841. s, t, _err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, **opt) do |in_p, out_p, err_p, cpid|
  842. assert IO.select([out_p], nil, nil, 10), 'subprocess not ready'
  843. out_p.gets
  844. pid = cpid
  845. t0 = Time.now.to_f
  846. Process.kill(:SIGINT, pid)
  847. begin
  848. Timeout.timeout(10) { Process.wait(pid) }
  849. rescue Timeout::Error
  850. EnvUtil.terminate(pid)
  851. raise
  852. end
  853. t1 = Time.now.to_f
  854. [$?, t1 - t0, err_p.read]
  855. end
  856. assert_equal(pid, s.pid, bug5757)
  857. assert_equal([false, true, false, Signal.list["INT"]],
  858. [s.exited?, s.signaled?, s.stopped?, s.termsig],
  859. "[s.exited?, s.signaled?, s.stopped?, s.termsig]")
  860. assert_include(0..2, t, bug5757)
  861. end
  862. def test_thread_join_in_trap
  863. assert_separately [], <<-'EOS'
  864. Signal.trap(:INT, "DEFAULT")
  865. t0 = Thread.current
  866. assert_nothing_raised{
  867. t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$)}
  868. Signal.trap :INT do
  869. t.join
  870. end
  871. t.join
  872. }
  873. EOS
  874. end
  875. def test_thread_value_in_trap
  876. assert_separately [], <<-'EOS'
  877. Signal.trap(:INT, "DEFAULT")
  878. t0 = Thread.current
  879. t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$); :normal_end}
  880. Signal.trap :INT do
  881. t.value
  882. end
  883. assert_equal(:normal_end, t.value)
  884. EOS
  885. end
  886. def test_thread_join_current
  887. assert_raise(ThreadError) do
  888. Thread.current.join
  889. end
  890. end
  891. def test_thread_join_main_thread
  892. Thread.new(Thread.current) {|t|
  893. assert_raise(ThreadError) do
  894. t.join
  895. end
  896. }.join
  897. end
  898. def test_main_thread_status_at_exit
  899. assert_in_out_err([], <<-'INPUT', ["false false aborting"], [])
  900. q = Thread::Queue.new
  901. Thread.new(Thread.current) {|mth|
  902. begin
  903. q.push nil
  904. mth.run
  905. Thread.pass until mth.stop?
  906. p :mth_stopped # don't run if killed by rb_thread_terminate_all
  907. ensure
  908. puts "#{mth.alive?} #{mth.status} #{Thread.current.status}"
  909. end
  910. }
  911. q.pop
  912. INPUT
  913. end
  914. def test_thread_status_in_trap
  915. # when running trap handler, Thread#status must show "run"
  916. # Even though interrupted from sleeping function
  917. assert_in_out_err([], <<-INPUT, %w(sleep run), [])
  918. Signal.trap(:INT) {
  919. puts Thread.current.status
  920. exit
  921. }
  922. t = Thread.current
  923. Thread.new(Thread.current) {|mth|
  924. Thread.pass until t.stop?
  925. puts mth.status
  926. Process.kill(:INT, $$)
  927. }
  928. sleep 0.1
  929. INPUT
  930. end
  931. # Bug #7450
  932. def test_thread_status_raise_after_kill
  933. ary = []
  934. t = Thread.new {
  935. assert_raise(RuntimeError) do
  936. begin
  937. ary << Thread.current.status
  938. sleep #1
  939. ensure
  940. begin
  941. ary << Thread.current.status
  942. sleep #2
  943. ensure
  944. ary << Thread.current.status
  945. end
  946. end
  947. end
  948. }
  949. Thread.pass until ary.size >= 1
  950. Thread.pass until t.stop?
  951. t.kill # wake up sleep #1
  952. Thread.pass until ary.size >= 2
  953. Thread.pass until t.stop?
  954. t.raise "wakeup" # wake up sleep #2
  955. Thread.pass while t.alive?
  956. assert_equal(ary, ["run", "aborting", "aborting"])
  957. t.join
  958. end
  959. def test_mutex_owned
  960. mutex = Thread::Mutex.new
  961. assert_equal(mutex.owned?, false)
  962. mutex.synchronize {
  963. # Now, I have the mutex
  964. assert_equal(mutex.owned?, true)
  965. }
  966. assert_equal(mutex.owned?, false)
  967. end
  968. def test_mutex_owned2
  969. begin
  970. mutex = Thread::Mutex.new
  971. th = Thread.new {
  972. # lock forever
  973. mutex.lock
  974. sleep
  975. }
  976. # acquired by another thread.
  977. Thread.pass until mutex.locked?
  978. assert_equal(mutex.owned?, false)
  979. ensure
  980. th&.kill
  981. end
  982. end
  983. def test_mutex_unlock_on_trap
  984. assert_in_out_err([], <<-INPUT, %w(locked unlocked false), [])
  985. m = Thread::Mutex.new
  986. trapped = false
  987. Signal.trap("INT") { |signo|
  988. m.unlock
  989. trapped = true
  990. puts "unlocked"
  991. }
  992. m.lock
  993. puts "locked"
  994. Process.kill("INT", $$)
  995. Thread.pass until trapped
  996. puts m.locked?
  997. INPUT
  998. end
  999. def invoke_rec script, vm_stack_size, machine_stack_size, use_length = true
  1000. env = {}
  1001. env['RUBY_THREAD_VM_STACK_SIZE'] = vm_stack_size.to_s if vm_stack_size
  1002. env['RUBY_THREAD_MACHINE_STACK_SIZE'] = machine_stack_size.to_s if machine_stack_size
  1003. out, = EnvUtil.invoke_ruby([env, '-e', script], '', true, true)
  1004. use_length ? out.length : out
  1005. end
  1006. def test_stack_size
  1007. h_default = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', nil, nil, false))
  1008. h_0 = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 0, 0, false))
  1009. h_large = eval(invoke_rec('p RubyVM::DEFAULT_PARAMS', 1024 * 1024 * 10, 1024 * 1024 * 10, false))
  1010. assert_operator(h_default[:thread_vm_stack_size], :>, h_0[:thread_vm_stack_size],
  1011. "0 thread_vm_stack_size")
  1012. assert_operator(h_default[:thread_vm_stack_size], :<, h_large[:thread_vm_stack_size],
  1013. "large thread_vm_stack_size")
  1014. assert_operator(h_default[:thread_machine_stack_size], :>=, h_0[:thread_machine_stack_size],
  1015. "0 thread_machine_stack_size")
  1016. assert_operator(h_default[:thread_machine_stack_size], :<=, h_large[:thread_machine_stack_size],
  1017. "large thread_machine_stack_size")
  1018. assert_equal("ok", invoke_rec('print :ok', 1024 * 1024 * 100, nil, false))
  1019. end
  1020. def test_vm_machine_stack_size
  1021. script = 'def rec; print "."; STDOUT.flush; rec; end; rec'
  1022. size_default = invoke_rec script, nil, nil
  1023. assert_operator(size_default, :>, 0, "default size")
  1024. size_0 = invoke_rec script, 0, nil
  1025. assert_operator(size_default, :>, size_0, "0 size")
  1026. size_large = invoke_rec script, 1024 * 1024 * 10, nil
  1027. assert_operator(size_default, :<, size_large, "large size")
  1028. end
  1029. def test_machine_stack_size
  1030. # check machine stack size
  1031. # Note that machine stack size may not change size (depend on OSs)
  1032. script = 'def rec; print "."; STDOUT.flush; 1.times{1.times{1.times{rec}}}; end; Thread.new{rec}.join'
  1033. vm_stack_size = 1024 * 1024
  1034. size_default = invoke_rec script, vm_stack_size, nil
  1035. size_0 = invoke_rec script, vm_stack_size, 0
  1036. assert_operator(size_default, :>=, size_0, "0 size")
  1037. size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10
  1038. assert_operator(size_default, :<=, size_large, "large size")
  1039. end unless /mswin|mingw/ =~ RUBY_PLATFORM
  1040. def test_blocking_mutex_unlocked_on_fork
  1041. bug8433 = '[ruby-core:55102] [Bug #8433]'
  1042. mutex = Thread::Mutex.new
  1043. mutex.lock
  1044. th = Thread.new do
  1045. mutex.synchronize do
  1046. sleep
  1047. end
  1048. end
  1049. Thread.pass until th.stop?
  1050. mutex.unlock
  1051. pid = Process.fork do
  1052. exit(mutex.locked?)
  1053. end
  1054. th.kill
  1055. pid, status = Process.waitpid2(pid)
  1056. assert_equal(false, status.success?, bug8433)
  1057. end if Process.respond_to?(:fork)
  1058. def test_fork_in_thread
  1059. bug9751 = '[ruby-core:62070] [Bug #9751]'
  1060. f = nil
  1061. th = Thread.start do
  1062. unless f = IO.popen("-")
  1063. STDERR.reopen(STDOUT)
  1064. exit
  1065. end
  1066. Process.wait2(f.pid)
  1067. end
  1068. unless th.join(EnvUtil.apply_timeout_scale(30))
  1069. Process.kill(:QUIT, f.pid)
  1070. Process.kill(:KILL, f.pid) unless th.join(EnvUtil.apply_timeout_scale(1))
  1071. end
  1072. _, status = th.value
  1073. output = f.read
  1074. f.close
  1075. assert_not_predicate(status, :signaled?, FailDesc[status, bug9751, output])
  1076. assert_predicate(status, :success?, bug9751)
  1077. end if Process.respond_to?(:fork)
  1078. def test_fork_while_locked
  1079. m = Mutex.new
  1080. thrs = []
  1081. 3.times do |i|
  1082. thrs << Thread.new { m.synchronize { Process.waitpid2(fork{})[1] } }
  1083. end
  1084. thrs.each do |t|
  1085. assert_predicate t.value, :success?, '[ruby-core:85940] [Bug #14578]'
  1086. end
  1087. end if Process.respond_to?(:fork)
  1088. def test_fork_while_parent_locked
  1089. skip 'needs fork' unless Process.respond_to?(:fork)
  1090. m = Thread::Mutex.new
  1091. nr = 1
  1092. thrs = []
  1093. m.synchronize do
  1094. thrs = nr.times.map { Thread.new { m.synchronize {} } }
  1095. thrs.each { Thread.pass }
  1096. pid = fork do
  1097. m.locked? or exit!(2)
  1098. thrs = nr.times.map { Thread.new { m.synchronize {} } }
  1099. m.unlock
  1100. thrs.each { |t| t.join(1) == t or exit!(1) }
  1101. exit!(0)
  1102. end
  1103. _, st = Process.waitpid2(pid)
  1104. assert_predicate st, :success?, '[ruby-core:90312] [Bug #15383]'
  1105. end
  1106. thrs.each { |t| assert_same t, t.join(1) }
  1107. end
  1108. def test_fork_while_mutex_locked_by_forker
  1109. skip 'needs fork' unless Process.respond_to?(:fork)
  1110. m = Mutex.new
  1111. m.synchronize do
  1112. pid = fork do
  1113. exit!(2) unless m.locked?
  1114. m.unlock rescue exit!(3)
  1115. m.synchronize {} rescue exit!(4)
  1116. exit!(0)
  1117. end
  1118. _, st = Timeout.timeout(30) { Process.waitpid2(pid) }
  1119. assert_predicate st, :success?, '[ruby-core:90595] [Bug #15430]'
  1120. end
  1121. end
  1122. def test_subclass_no_initialize
  1123. t = Module.new do
  1124. break eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")
  1125. end
  1126. t.class_eval do
  1127. def initialize
  1128. end
  1129. end
  1130. assert_raise_with_message(ThreadError, /C\u{30b9 30ec 30c3 30c9}/) do
  1131. t.new {}
  1132. end
  1133. end
  1134. def test_thread_name
  1135. t = Thread.start {sleep}
  1136. sleep 0.001 until t.stop?
  1137. assert_nil t.name
  1138. s = t.inspect
  1139. t.name = 'foo'
  1140. assert_equal 'foo', t.name
  1141. t.name = nil
  1142. assert_nil t.name
  1143. assert_equal s, t.inspect
  1144. ensure
  1145. t.kill
  1146. t.join
  1147. end
  1148. def test_thread_invalid_name
  1149. bug11756 = '[ruby-core:71774] [Bug #11756]'
  1150. t = Thread.start {}
  1151. assert_raise(ArgumentError, bug11756) {t.name = "foo\0bar"}
  1152. assert_raise(ArgumentError, bug11756) {t.name = "foo".encode(Encoding::UTF_32BE)}
  1153. ensure
  1154. t.kill
  1155. t.join
  1156. end
  1157. def test_thread_invalid_object
  1158. bug11756 = '[ruby-core:71774] [Bug #11756]'
  1159. t = Thread.start {}
  1160. assert_raise(TypeError, bug11756) {t.name = []}
  1161. ensure
  1162. t.kill
  1163. t.join
  1164. end
  1165. def test_thread_setname_in_initialize
  1166. bug12290 = '[ruby-core:74963] [Bug #12290]'
  1167. c = Class.new(Thread) {def initialize() self.name = "foo"; super; end}
  1168. assert_equal("foo", c.new {Thread.current.name}.value, bug12290)
  1169. end
  1170. def test_thread_interrupt_for_killed_thread
  1171. opts = { timeout: 5, timeout_error: nil }
  1172. # prevent SIGABRT from slow shutdown with MJIT
  1173. opts[:reprieve] = 3 if RubyVM::MJIT.enabled?
  1174. assert_normal_exit(<<-_end, '[Bug #8996]', **opts)
  1175. Thread.report_on_exception = false
  1176. trap(:TERM){exit}
  1177. while true
  1178. t = Thread.new{sleep 0}
  1179. t.raise Interrupt
  1180. Thread.pass # allow t to finish
  1181. end
  1182. _end
  1183. end
  1184. def test_signal_at_join
  1185. if /mswin|mingw/ =~ RUBY_PLATFORM
  1186. skip "can't trap a signal from another process on Windows"
  1187. # opt = {new_pgroup: true}
  1188. end
  1189. assert_separately([], "#{<<~"{#"}\n#{<<~'};'}", timeout: 120)
  1190. {#
  1191. n = 1000
  1192. sig = :INT
  1193. trap(sig) {}
  1194. IO.popen([EnvUtil.rubybin, "-e", "#{<<~"{#1"}\n#{<<~'};#1'}"], "r+") do |f|
  1195. tpid = #{$$}
  1196. sig = :#{sig}
  1197. {#1
  1198. STDOUT.sync = true
  1199. while gets
  1200. puts
  1201. Process.kill(sig, tpid)
  1202. end
  1203. };#1
  1204. assert_nothing_raised do
  1205. n.times do
  1206. w = Thread.start do
  1207. sleep 30
  1208. end
  1209. begin
  1210. f.puts
  1211. f.gets
  1212. ensure
  1213. w.kill
  1214. w.join
  1215. end
  1216. end
  1217. end
  1218. n.times do
  1219. w = Thread.start { sleep 30 }
  1220. begin
  1221. f.puts
  1222. f.gets
  1223. ensure
  1224. w.kill
  1225. t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  1226. w.join(30)
  1227. t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  1228. diff = t1 - t0
  1229. assert_operator diff, :<=, 2
  1230. end
  1231. end
  1232. end
  1233. };
  1234. end
  1235. end