PageRenderTime 40ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/test/jruby/test_thread.rb

http://github.com/jruby/jruby
Ruby | 402 lines | 316 code | 53 blank | 33 comment | 20 complexity | 0cc463bbff40b3e416687523f174843b MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, GPL-2.0, JSON, LGPL-2.1
  1. require 'test/unit'
  2. require 'thread'
  3. class TestThread < Test::Unit::TestCase
  4. def test_running_and_finishing
  5. thread = Thread.new {
  6. $toto = 1
  7. }
  8. thread.join
  9. assert_equal(1, $toto)
  10. assert_equal(false, thread.status)
  11. end
  12. def test_local_variables
  13. v = nil
  14. t = Thread.new { v = 1 }
  15. t.join
  16. assert_equal(1, v)
  17. end
  18. def test_taking_arguments
  19. v = nil
  20. t = Thread.new(10) {|argument| v = argument }
  21. t.join
  22. assert_equal(10, v)
  23. end
  24. def test_thread_current
  25. t = Thread.current
  26. assert_equal(t, Thread.current)
  27. end
  28. def test_thread_local_variables
  29. v = nil
  30. t = Thread.new {
  31. Thread.current[:x] = 1234
  32. assert_equal(1234, Thread.current[:x])
  33. assert_equal(nil, Thread.current[:y])
  34. assert(Thread.current.key?(:x))
  35. assert(! Thread.current.key?(:y))
  36. }
  37. t.join
  38. assert(! Thread.current.key?(:x))
  39. Thread.current[:x] = 1
  40. assert(Thread.current.key?(:x))
  41. Thread.current["y"] = 2
  42. assert(Thread.current.key?("y"))
  43. assert_equal([:x, :y], Thread.current.keys.sort {|x, y| x.to_s <=> y.to_s} & [:x, :y])
  44. assert_raises(TypeError) { Thread.current[Object.new] }
  45. assert_raises(TypeError) { Thread.current[Object.new] = 1 }
  46. assert_raises(TypeError) { Thread.current[1] }
  47. assert_raises(TypeError) { Thread.current[1] = 1}
  48. end
  49. def test_status
  50. t = Thread.new { Thread.current.status }
  51. t.join
  52. v = t.value
  53. assert_equal("run", v)
  54. assert_equal(false, t.status)
  55. # check that "run", sleep", and "dead" appear in inspected output
  56. q = Queue.new
  57. ready = false
  58. t = Thread.new { q << Thread.current.inspect; ready = true; sleep }
  59. Thread.pass until ready && (t.status == "sleep" || !t.alive?)
  60. assert(q.shift(true)["run"])
  61. assert(t.inspect["sleep"])
  62. t.kill
  63. t.join rescue nil
  64. assert(t.inspect["dead"])
  65. end
  66. def thread_foo()
  67. raise "hello"
  68. end
  69. def test_error_handling
  70. e = nil
  71. t = Thread.new {
  72. thread_foo()
  73. }
  74. begin
  75. t.join
  76. rescue RuntimeError => error
  77. e = error
  78. end
  79. assert(! e.nil?)
  80. assert_equal(nil, t.status)
  81. end
  82. def test_joining_itself
  83. e = nil
  84. begin
  85. Thread.current.join
  86. rescue ThreadError => error
  87. e = error
  88. end
  89. assert(! e.nil?)
  90. assert_match(/thread [0-9a-z]+ tried to join itself/, e.message)
  91. end
  92. def test_raise
  93. e = nil
  94. t = Thread.new {
  95. while true
  96. Thread.pass
  97. end
  98. }
  99. t.raise("Die")
  100. begin
  101. t.join
  102. rescue RuntimeError => error
  103. e = error
  104. end
  105. assert(e.kind_of?(RuntimeError))
  106. # test raising in a sleeping thread
  107. e = 1
  108. set = false
  109. begin
  110. t = Thread.new { e = 2; set = true; sleep(100); e = 3 }
  111. while !set
  112. sleep(1)
  113. end
  114. t.raise("Die")
  115. rescue; end
  116. assert_equal(2, e)
  117. assert_raise(RuntimeError) { t.value }
  118. end
  119. def test_thread_value
  120. assert_raise(ArgumentError) { Thread.new { }.value(100) }
  121. assert_equal(2, Thread.new { 2 }.value)
  122. assert_raise(RuntimeError) { Thread.new { raise "foo" }.value }
  123. end
  124. class MyThread < Thread
  125. def initialize
  126. super do; 1; end
  127. end
  128. end
  129. def test_thread_subclass_zsuper
  130. x = MyThread.new
  131. x.join
  132. assert_equal(1, x.value)
  133. x = MyThread.start { 2 }
  134. x.join
  135. assert_equal(2, x.value)
  136. end
  137. # Because a Ruby thread may use a pooled thread, we will
  138. # not preserve priorities set into dead threads. Because
  139. # this is a meaningless feature, anyway, I remove it here
  140. # and consider this behavior undefined. CON@20120306
  141. # def test_dead_thread_priority
  142. # x = Thread.new {}
  143. # 1 while x.alive?
  144. # x.priority = 5
  145. # assert_equal(5, x.priority)
  146. # end
  147. def test_join_returns_thread
  148. x = Thread.new {}
  149. assert_nothing_raised { x.join.to_s }
  150. end
  151. def test_abort_on_exception_does_not_blow_up
  152. # CON: I had an issue where annotated methods weren't binding right
  153. # where there was both a static and instance method of the same name.
  154. # This caused abort_on_exception to fail to bind right; a temporary fix
  155. # was put in place by appending _x but it shouldn't stay. This test confirms
  156. # the method stays callable.
  157. assert_nothing_raised { Thread.abort_on_exception }
  158. assert_nothing_raised { Thread.abort_on_exception = Thread.abort_on_exception}
  159. end
  160. # JRUBY-2021
  161. def test_multithreaded_method_definition
  162. def run_me
  163. sleep 0.1
  164. def do_stuff
  165. sleep 0.1
  166. end
  167. end
  168. threads = []
  169. 100.times {
  170. threads << Thread.new { run_me }
  171. }
  172. threads.each { |t| t.join }
  173. end
  174. def test_socket_accept_can_be_interrupted
  175. require 'socket'
  176. tcps = nil
  177. 100.times{|i|
  178. begin
  179. tcps = TCPServer.new("0.0.0.0", 10000+i)
  180. break
  181. rescue Errno::EADDRINUSE
  182. next
  183. end
  184. }
  185. flunk "unable to find open port" unless tcps
  186. t = Thread.new {
  187. tcps.accept
  188. }
  189. Thread.pass until t.status == "sleep"
  190. ex = Exception.new
  191. t.raise ex
  192. assert_raises(Exception) { t.join }
  193. end
  194. # JRUBY-2315
  195. def test_exit_from_within_thread
  196. begin
  197. a = Thread.new do
  198. loop do
  199. sleep 0.1
  200. end
  201. end
  202. b = Thread.new do
  203. sleep 0.5
  204. Kernel.exit(1)
  205. end
  206. a.join
  207. fail
  208. b.join
  209. rescue SystemExit
  210. # rescued!
  211. assert(true)
  212. ensure
  213. a.kill rescue nil
  214. b.kill rescue nil
  215. end
  216. end
  217. def call_to_s(a)
  218. a.to_s
  219. end
  220. # JRUBY-2477 - polymorphic calls are not thread-safe
  221. def test_poly_calls_thread_safe
  222. # Note this isn't a perfect test, but it's not possible to test perfectly
  223. # This might only fail on multicore machines
  224. results = [false] * 20
  225. threads = []
  226. sym = :foo
  227. str = "foo"
  228. 20.times {|i| threads << Thread.new { 10_000.times { call_to_s(sym); call_to_s(str) }; results[i] = true }}
  229. threads.pop.join until threads.empty?
  230. assert_equal [true] * 20, results
  231. end
  232. def test_thread_exit_does_not_deadlock
  233. 100.times do
  234. t = Thread.new { Thread.stop; Thread.current.exit }
  235. Thread.pass until t.status == "sleep"
  236. t.wakeup; t.join
  237. end
  238. end
  239. # JRUBY-2380: Thread.list has a race condition
  240. # Fix is to make sure the thread is added to the global list before returning from Thread#new
  241. def test_new_thread_in_list
  242. 1000.times do
  243. t = Thread.new do
  244. sleep
  245. end
  246. fail("new thread was not in Thread.list") unless Thread.list.include? t
  247. Thread.pass until t.status == 'sleep'
  248. t.wakeup
  249. t.join
  250. end
  251. end
  252. # JRUBY-3568: thread group is inherited from parent
  253. def test_inherits_thread_group
  254. tg = ThreadGroup.new
  255. og = nil
  256. tg.add(Thread.current)
  257. Thread.new { og = Thread.current.group }.join
  258. assert_equal(tg, og)
  259. end
  260. # JRUBY-3740: Thread#wakeup not working
  261. def test_wakeup_wakes_sleeping_thread
  262. awoke = false
  263. t = Thread.new { sleep; awoke = true }
  264. Thread.pass until t.status == "sleep"
  265. t.wakeup.join
  266. assert awoke
  267. awoke = false
  268. start_time = Time.now
  269. done = false
  270. t = Thread.new { sleep 100; done = true }
  271. Thread.pass until t.status == "sleep"
  272. t.wakeup
  273. loop {
  274. break if done || Time.now - start_time > 10
  275. Thread.pass
  276. }
  277. assert done
  278. end
  279. # JRUBY-5290
  280. def test_default_priority
  281. t = Thread.new { sleep 1 while true }
  282. assert_equal 0, t.priority
  283. t.exit
  284. end
  285. # Simpler case for sleep/wakeup close together, which can race if thread state is not managed well
  286. def test_sleep_wakeup_interlacing
  287. go = false
  288. ret = []
  289. t = Thread.new do
  290. 10000.times do
  291. Thread.pass until go
  292. sleep
  293. ret << 'ok'
  294. end
  295. end
  296. 10000.times do
  297. go = true
  298. Thread.pass until t.status == 'sleep'
  299. go = false
  300. t.wakeup
  301. end
  302. t.join
  303. assert_equal(10000, ret.size)
  304. end
  305. def test_inspect_and_to_s
  306. t = Thread.new {}.join
  307. assert_match(/#<Thread:0x[0-9a-z]+>/, t.to_s)
  308. # TODO we do not have file/line right :
  309. # MRI: #<Thread:0x000000014b0e28@test/jruby/test_thread.rb:346 dead>
  310. #assert_match(/#<Thread:0x[0-9a-z]+@test\/jruby\/test_thread\.rb\:346 \w+>/, t.inspect)
  311. assert_match(/#<Thread:0x[0-9a-z]+(@.*\.rb\:\d+)? \w+>/, t.inspect)
  312. assert_nil t.name
  313. t = Thread.new {}.join
  314. t.name = 'universal'
  315. assert_match(/#<Thread:0x[0-9a-z]+>/, t.to_s)
  316. assert_match(/#<Thread:0x[0-9a-z]+@universal(@.*\.rb\:\d+)? \w+>/, t.inspect)
  317. end
  318. def test_thread_name
  319. Thread.new do
  320. assert_match(/\#\<Thread\:0x\h+(@[\w\/\._]+\:\d+)?\srun\>/, Thread.current.inspect)
  321. # TODO? currently in JIT file comes as "" and line as 0
  322. assert_match(/Ruby\-\d+\-Thread\-\d+\:\s(.*\.rb)?\:\d+/, native_thread_name(Thread.current)) if defined? JRUBY_VERSION
  323. end.join
  324. Thread.new do
  325. Thread.current.name = 'foo'
  326. assert_match(/\#\<Thread\:0x\h+@foo(@[\w\/\._]+\:\d+)?\srun\>/, Thread.current.inspect)
  327. assert_match(/Ruby\-\d+\-Thread\-\d+\@foo:\s(.*\.rb)?\:\d+/, native_thread_name(Thread.current)) if defined? JRUBY_VERSION
  328. Thread.current.name = 'bar'
  329. assert_match(/\#\<Thread\:0x\h+@bar(@[\w\/\._]+\:\d+)?\srun\>/, Thread.current.inspect)
  330. assert_match(/Ruby\-\d+\-Thread\-\d+\@bar:\s(.*\.rb)?\:\d+/, native_thread_name(Thread.current)) if defined? JRUBY_VERSION
  331. Thread.current.name = nil
  332. assert_match(/\#\<Thread\:0x\h+(@[\w\/\._]+\:\d+)?\srun\>/, Thread.current.inspect)
  333. assert_match(/Ruby\-\d+\-Thread\-\d+\:\s(.*\.rb)?\:\d+/, native_thread_name(Thread.current)) if defined? JRUBY_VERSION
  334. end.join
  335. Thread.new do
  336. Thread.current.to_java.native_thread.name = 'user-set-native-thread-name'
  337. Thread.current.name = 'foo'
  338. assert Thread.current.inspect.index('@foo')
  339. assert_equal 'user-set-native-thread-name', native_thread_name(Thread.current) if defined? JRUBY_VERSION
  340. Thread.current.name = nil
  341. assert ! Thread.current.inspect.index('@foo')
  342. assert_equal 'user-set-native-thread-name', native_thread_name(Thread.current) if defined? JRUBY_VERSION
  343. end.join
  344. end
  345. private
  346. def native_thread_name(thread)
  347. thread.to_java.native_thread.name
  348. end
  349. end