PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/test-mri/test/ruby/test_thread.rb

https://github.com/ferrous26/MacRuby
Ruby | 663 lines | 557 code | 91 blank | 15 comment | 21 complexity | 1e07ed360e8486ce20dcc7b0fe6e5c7a MD5 | raw file
  1. require 'test/unit'
  2. require 'thread'
  3. require_relative 'envutil'
  4. class TestThread < Test::Unit::TestCase
  5. class Thread < ::Thread
  6. Threads = []
  7. def self.new(*)
  8. th = super
  9. th.abort_on_exception = true
  10. Threads << th
  11. th
  12. end
  13. end
  14. def setup
  15. Thread::Threads.clear
  16. end
  17. def teardown
  18. Thread::Threads.each do |t|
  19. t.kill if t.alive?
  20. begin
  21. t.join
  22. rescue Exception
  23. end
  24. end
  25. end
  26. def test_mutex_synchronize
  27. m = Mutex.new
  28. r = 0
  29. max = 10
  30. (1..max).map{
  31. Thread.new{
  32. i=0
  33. while i<max*max
  34. i+=1
  35. m.synchronize{
  36. r += 1
  37. }
  38. end
  39. }
  40. }.each{|e|
  41. e.join
  42. }
  43. assert_equal(max * max * max, r)
  44. end
  45. def test_condvar
  46. mutex = Mutex.new
  47. condvar = ConditionVariable.new
  48. result = []
  49. mutex.synchronize do
  50. t = Thread.new do
  51. mutex.synchronize do
  52. result << 1
  53. condvar.signal
  54. end
  55. end
  56. result << 0
  57. condvar.wait(mutex)
  58. result << 2
  59. t.join
  60. end
  61. assert_equal([0, 1, 2], result)
  62. end
  63. def test_condvar_wait_not_owner
  64. mutex = Mutex.new
  65. condvar = ConditionVariable.new
  66. assert_raise(ThreadError) { condvar.wait(mutex) }
  67. end
  68. def test_condvar_wait_exception_handling
  69. # Calling wait in the only thread running should raise a ThreadError of
  70. # 'stopping only thread'
  71. mutex = Mutex.new
  72. condvar = ConditionVariable.new
  73. locked = false
  74. thread = Thread.new do
  75. Thread.current.abort_on_exception = false
  76. mutex.synchronize do
  77. begin
  78. condvar.wait(mutex)
  79. rescue Exception
  80. locked = mutex.locked?
  81. raise
  82. end
  83. end
  84. end
  85. until thread.stop?
  86. sleep(0.1)
  87. end
  88. thread.raise Interrupt, "interrupt a dead condition variable"
  89. assert_raise(Interrupt) { thread.value }
  90. assert(locked)
  91. end
  92. def test_condvar_wait_and_broadcast
  93. nr_threads = 3
  94. threads = Array.new
  95. mutex = Mutex.new
  96. condvar = ConditionVariable.new
  97. result = []
  98. nr_threads.times do |i|
  99. threads[i] = Thread.new do
  100. mutex.synchronize do
  101. result << "C1"
  102. condvar.wait mutex
  103. result << "C2"
  104. end
  105. end
  106. end
  107. sleep 0.1
  108. mutex.synchronize do
  109. result << "P1"
  110. condvar.broadcast
  111. result << "P2"
  112. end
  113. nr_threads.times do |i|
  114. threads[i].join
  115. end
  116. assert_equal ["C1", "C1", "C1", "P1", "P2", "C2", "C2", "C2"], result
  117. end
  118. # Hmm.. don't we have a way of catch fatal exception?
  119. #
  120. # def test_cv_wait_deadlock
  121. # mutex = Mutex.new
  122. # cv = ConditionVariable.new
  123. #
  124. # assert_raises(fatal) {
  125. # mutex.lock
  126. # cv.wait mutex
  127. # mutex.unlock
  128. # }
  129. # end
  130. def test_condvar_wait_deadlock_2
  131. nr_threads = 3
  132. threads = Array.new
  133. mutex = Mutex.new
  134. condvar = ConditionVariable.new
  135. nr_threads.times do |i|
  136. if (i != 0)
  137. mutex.unlock
  138. end
  139. threads[i] = Thread.new do
  140. mutex.synchronize do
  141. condvar.wait mutex
  142. end
  143. end
  144. mutex.lock
  145. end
  146. assert_raise(Timeout::Error) do
  147. Timeout.timeout(0.1) { condvar.wait mutex }
  148. end
  149. mutex.unlock rescue
  150. threads[i].each.join
  151. end
  152. def test_condvar_timed_wait
  153. mutex = Mutex.new
  154. condvar = ConditionVariable.new
  155. timeout = 0.3
  156. locked = false
  157. t0 = Time.now
  158. mutex.synchronize do
  159. begin
  160. condvar.wait(mutex, timeout)
  161. ensure
  162. locked = mutex.locked?
  163. end
  164. end
  165. t1 = Time.now
  166. t = t1-t0
  167. assert_block { timeout*0.9 < t && t < timeout*1.1 }
  168. assert(locked)
  169. end
  170. def test_condvar_nolock
  171. mutex = Mutex.new
  172. condvar = ConditionVariable.new
  173. assert_raise(ThreadError) { condvar.wait(mutex) }
  174. end
  175. def test_condvar_nolock_2
  176. mutex = Mutex.new
  177. condvar = ConditionVariable.new
  178. Thread.new do
  179. assert_raise(ThreadError) {condvar.wait(mutex)}
  180. end.join
  181. end
  182. def test_condvar_nolock_3
  183. mutex = Mutex.new
  184. condvar = ConditionVariable.new
  185. Thread.new do
  186. assert_raise(ThreadError) {condvar.wait(mutex, 0.1)}
  187. end.join
  188. end
  189. def test_local_barrier
  190. dir = File.dirname(__FILE__)
  191. lbtest = File.join(dir, "lbtest.rb")
  192. $:.unshift File.join(File.dirname(dir), 'ruby')
  193. require 'envutil'
  194. $:.shift
  195. 3.times {
  196. result = `#{EnvUtil.rubybin} #{lbtest}`
  197. assert(!$?.coredump?, '[ruby-dev:30653]')
  198. assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]')
  199. }
  200. end
  201. def test_priority
  202. skip("[BUG : #1283] Segfault occurs when gets the busy loop with some threads.")
  203. c1 = c2 = 0
  204. t1 = Thread.new { loop { c1 += 1 } }
  205. t1.priority = -1
  206. t2 = Thread.new { loop { c2 += 1 } }
  207. t2.priority = -3
  208. assert_equal(-1, t1.priority)
  209. assert_equal(-3, t2.priority)
  210. sleep 0.5
  211. 5.times do
  212. break if c1 > c2
  213. sleep 0.1
  214. end
  215. t1.kill
  216. t2.kill
  217. # assert_operator(c1, :>, c2, "[ruby-dev:33124]") # not guaranteed
  218. end
  219. def test_new
  220. assert_raise(ThreadError) do
  221. Thread.new
  222. end
  223. t1 = Thread.new { sleep }
  224. assert_raise(ThreadError) do
  225. t1.instance_eval { initialize { } }
  226. end
  227. t2 = Thread.new(&method(:sleep).to_proc)
  228. assert_raise(ThreadError) do
  229. t2.instance_eval { initialize { } }
  230. end
  231. ensure
  232. t1.kill if t1
  233. t2.kill if t2
  234. end
  235. def test_join
  236. t = Thread.new { sleep }
  237. assert_nil(t.join(0.5))
  238. ensure
  239. t.kill if t
  240. end
  241. def test_join2
  242. t1 = Thread.new { sleep(1.5) }
  243. t2 = Thread.new do
  244. t1.join(1)
  245. end
  246. t3 = Thread.new do
  247. sleep 0.5
  248. t1.join
  249. end
  250. assert_nil(t2.value)
  251. assert_equal(t1, t3.value)
  252. ensure
  253. t1.kill if t1
  254. t2.kill if t2
  255. t3.kill if t3
  256. end
  257. def test_kill_main_thread
  258. assert_in_out_err([], <<-INPUT, %w(1), [])
  259. p 1
  260. Thread.kill Thread.current
  261. p 2
  262. INPUT
  263. end
  264. def test_kill_wrong_argument
  265. bug4367 = '[ruby-core:35086]'
  266. assert_raise(TypeError, bug4367) {
  267. Thread.kill(nil)
  268. }
  269. end
  270. def test_exit
  271. s = 0
  272. Thread.new do
  273. s += 1
  274. Thread.exit
  275. s += 2
  276. end.join
  277. assert_equal(1, s)
  278. end
  279. def test_wakeup
  280. s = 0
  281. t = Thread.new do
  282. s += 1
  283. Thread.stop
  284. s += 1
  285. end
  286. sleep 0.5
  287. assert_equal(1, s)
  288. t.wakeup
  289. sleep 0.5
  290. assert_equal(2, s)
  291. assert_raise(ThreadError) { t.wakeup }
  292. ensure
  293. t.kill if t
  294. end
  295. def test_stop
  296. assert_in_out_err([], <<-INPUT, %w(2), [])
  297. begin
  298. Thread.stop
  299. p 1
  300. rescue ThreadError
  301. p 2
  302. end
  303. INPUT
  304. end
  305. def test_list
  306. assert_in_out_err([], <<-INPUT) do |r, e|
  307. t1 = Thread.new { sleep }
  308. Thread.pass
  309. t2 = Thread.new { loop { } }
  310. t3 = Thread.new { }.join
  311. p [Thread.current, t1, t2].map{|t| t.object_id }.sort
  312. p Thread.list.map{|t| t.object_id }.sort
  313. INPUT
  314. assert_equal(r.first, r.last)
  315. assert_equal([], e)
  316. end
  317. end
  318. def test_main
  319. assert_in_out_err([], <<-INPUT, %w(true false), [])
  320. p Thread.main == Thread.current
  321. Thread.new { p Thread.main == Thread.current }.join
  322. INPUT
  323. end
  324. def test_abort_on_exception
  325. assert_in_out_err([], <<-INPUT, %w(false 1), [])
  326. p Thread.abort_on_exception
  327. begin
  328. Thread.new { raise }
  329. sleep 0.5
  330. p 1
  331. rescue
  332. p 2
  333. end
  334. INPUT
  335. assert_in_out_err([], <<-INPUT, %w(true 2), [])
  336. Thread.abort_on_exception = true
  337. p Thread.abort_on_exception
  338. begin
  339. Thread.new { raise }
  340. sleep 0.5
  341. p 1
  342. rescue
  343. p 2
  344. end
  345. INPUT
  346. assert_in_out_err(%w(-d), <<-INPUT, %w(false 2), /.+/)
  347. p Thread.abort_on_exception
  348. begin
  349. Thread.new { raise }
  350. sleep 0.5
  351. p 1
  352. rescue
  353. p 2
  354. end
  355. INPUT
  356. assert_in_out_err([], <<-INPUT, %w(false true 2), [])
  357. p Thread.abort_on_exception
  358. begin
  359. t = Thread.new { sleep 0.5; raise }
  360. t.abort_on_exception = true
  361. p t.abort_on_exception
  362. sleep 1
  363. p 1
  364. rescue
  365. p 2
  366. end
  367. INPUT
  368. end
  369. def test_status_and_stop_p
  370. a = ::Thread.new { raise("die now") }
  371. b = Thread.new { Thread.stop }
  372. c = Thread.new { Thread.exit }
  373. d = Thread.new { sleep }
  374. e = Thread.current
  375. sleep 0.5
  376. assert_equal(nil, a.status)
  377. assert(a.stop?)
  378. assert_equal("sleep", b.status)
  379. assert(b.stop?)
  380. assert_equal(false, c.status)
  381. assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect)
  382. assert(c.stop?)
  383. d.kill
  384. assert_equal(["aborting", false], [d.status, d.stop?])
  385. assert_equal(["run", false], [e.status, e.stop?])
  386. ensure
  387. a.kill if a
  388. b.kill if b
  389. c.kill if c
  390. d.kill if d
  391. end
  392. def test_safe_level
  393. t = Thread.new { $SAFE = 3; sleep }
  394. sleep 0.5
  395. assert_equal(0, Thread.current.safe_level)
  396. assert_equal(3, t.safe_level)
  397. ensure
  398. t.kill if t
  399. end
  400. def test_thread_local
  401. t = Thread.new { sleep }
  402. assert_equal(false, t.key?(:foo))
  403. t["foo"] = "foo"
  404. t["bar"] = "bar"
  405. t["baz"] = "baz"
  406. assert_equal(true, t.key?(:foo))
  407. assert_equal(true, t.key?("foo"))
  408. assert_equal(false, t.key?(:qux))
  409. assert_equal(false, t.key?("qux"))
  410. assert_equal([:foo, :bar, :baz], t.keys)
  411. ensure
  412. t.kill if t
  413. end
  414. def test_thread_local_security
  415. t = Thread.new { sleep }
  416. assert_raise(SecurityError) do
  417. Thread.new { $SAFE = 4; t[:foo] }.join
  418. end
  419. assert_raise(SecurityError) do
  420. Thread.new { $SAFE = 4; t[:foo] = :baz }.join
  421. end
  422. assert_raise(RuntimeError) do
  423. Thread.new do
  424. Thread.current[:foo] = :bar
  425. Thread.current.freeze
  426. Thread.current[:foo] = :baz
  427. end.join
  428. end
  429. end
  430. def test_select_wait
  431. skip("[BUG : #1233] Abort occurs when kill a thread waiting with IO.select")
  432. assert_nil(IO.select(nil, nil, nil, 1))
  433. t = Thread.new do
  434. IO.select(nil, nil, nil, nil)
  435. end
  436. sleep 0.5
  437. t.kill
  438. end
  439. def test_mutex_deadlock
  440. m = Mutex.new
  441. m.synchronize do
  442. assert_raise(ThreadError) do
  443. m.synchronize do
  444. assert(false)
  445. end
  446. end
  447. end
  448. end
  449. def test_mutex_interrupt
  450. m = Mutex.new
  451. m.lock
  452. t = Thread.new do
  453. m.lock
  454. :foo
  455. end
  456. sleep 0.5
  457. t.kill
  458. assert_nil(t.value)
  459. end
  460. def test_mutex_illegal_unlock
  461. m = Mutex.new
  462. m.lock
  463. assert_raise(ThreadError) do
  464. Thread.new do
  465. m.unlock
  466. end.join
  467. end
  468. end
  469. def test_mutex_fifo_like_lock
  470. m1 = Mutex.new
  471. m2 = Mutex.new
  472. m1.lock
  473. m2.lock
  474. m1.unlock
  475. m2.unlock
  476. assert_equal(false, m1.locked?)
  477. assert_equal(false, m2.locked?)
  478. m3 = Mutex.new
  479. m1.lock
  480. m2.lock
  481. m3.lock
  482. m1.unlock
  483. m2.unlock
  484. m3.unlock
  485. assert_equal(false, m1.locked?)
  486. assert_equal(false, m2.locked?)
  487. assert_equal(false, m3.locked?)
  488. end
  489. def test_mutex_trylock
  490. m = Mutex.new
  491. assert_equal(true, m.try_lock)
  492. assert_equal(false, m.try_lock, '[ruby-core:20943]')
  493. Thread.new{
  494. assert_equal(false, m.try_lock)
  495. }.join
  496. m.unlock
  497. end
  498. def test_recursive_outer
  499. arr = []
  500. obj = Struct.new(:foo, :visited).new(arr, false)
  501. arr << obj
  502. def obj.hash
  503. self[:visited] = true
  504. super
  505. raise "recursive_outer should short circuit intermediate calls"
  506. end
  507. assert_nothing_raised {arr.hash}
  508. assert(obj[:visited])
  509. end
  510. end
  511. class TestThreadGroup < Test::Unit::TestCase
  512. def test_thread_init
  513. thgrp = ThreadGroup.new
  514. Thread.new{
  515. thgrp.add(Thread.current)
  516. assert_equal(thgrp, Thread.new{sleep 1}.group)
  517. }.join
  518. end
  519. def test_frozen_thgroup
  520. skip("[BUG : #1085] Assertion failed: ((b->flags & flags) == flags)")
  521. thgrp = ThreadGroup.new
  522. t = Thread.new{1}
  523. Thread.new{
  524. thgrp.add(Thread.current)
  525. thgrp.freeze
  526. assert_raise(ThreadError) do
  527. Thread.new{1}.join
  528. end
  529. assert_raise(ThreadError) do
  530. thgrp.add(t)
  531. end
  532. assert_raise(ThreadError) do
  533. ThreadGroup.new.add Thread.current
  534. end
  535. }.join
  536. t.join
  537. end
  538. def test_enclosed_thgroup
  539. skip("[BUG : #1085] Assertion failed: ((b->flags & flags) == flags)")
  540. thgrp = ThreadGroup.new
  541. assert_equal(false, thgrp.enclosed?)
  542. t = Thread.new{1}
  543. Thread.new{
  544. thgrp.add(Thread.current)
  545. thgrp.enclose
  546. assert_equal(true, thgrp.enclosed?)
  547. assert_nothing_raised do
  548. Thread.new{1}.join
  549. end
  550. assert_raise(ThreadError) do
  551. thgrp.add t
  552. end
  553. assert_raise(ThreadError) do
  554. ThreadGroup.new.add Thread.current
  555. end
  556. }.join
  557. t.join
  558. end
  559. def test_uninitialized
  560. c = Class.new(Thread)
  561. c.class_eval { def initialize; end }
  562. assert_raise(ThreadError) { c.new.start }
  563. end
  564. def test_backtrace
  565. Thread.new{
  566. assert_equal(Array, Thread.main.backtrace.class)
  567. }.join
  568. t = Thread.new{}
  569. t.join
  570. assert_equal(nil, t.backtrace)
  571. end
  572. end