start using kgio library
[rainbows.git] / lib / rainbows / thread_pool.rb
blob321d3e4099f4fe412c2cc653cc9052938a9ffc24
1 # -*- encoding: binary -*-
3 module Rainbows
5   # Implements a worker thread pool model.  This is suited for platforms
6   # like Ruby 1.9, where the cost of dynamically spawning a new thread
7   # for every new client connection is higher than with the ThreadSpawn
8   # model.
9   #
10   # This model should provide a high level of compatibility with all
11   # Ruby implementations, and most libraries and applications.
12   # Applications running under this model should be thread-safe
13   # but not necessarily reentrant.
14   #
15   # Applications using this model are required to be thread-safe.
16   # Threads are never spawned dynamically under this model.  If you're
17   # connecting to external services and need to perform DNS lookups,
18   # consider using the "resolv-replace" library which replaces parts of
19   # the core Socket package with concurrent DNS lookup capabilities.
20   #
21   # This model probably less suited for many slow clients than the
22   # others and thus a lower +worker_connections+ setting is recommended.
24   module ThreadPool
25     include Base
27     def worker_loop(worker) # :nodoc:
28       init_worker_process(worker)
29       pool = (1..worker_connections).map do
30         Thread.new { LISTENERS.size == 1 ? sync_worker : async_worker }
31       end
33       while G.alive
34         # if any worker dies, something is serious wrong, bail
35         pool.each do |thr|
36           G.tick or break
37           thr.join(1) and G.quit!
38         end
39       end
40       join_threads(pool)
41     end
43     def sync_worker # :nodoc:
44       s = LISTENERS[0]
45       begin
46         c = s.kgio_accept and process_client(c)
47       rescue => e
48         Error.listen_loop(e)
49       end while G.alive
50     end
52     def async_worker # :nodoc:
53       begin
54         # TODO: check if select() or accept() is a problem on large
55         # SMP systems under Ruby 1.9.  Hundreds of native threads
56         # all working off the same socket could be a thundering herd
57         # problem.  On the other hand, a thundering herd may not
58         # even incur as much overhead as an extra Mutex#synchronize
59         ret = IO.select(LISTENERS, nil, nil, 1) and ret[0].each do |s|
60           s = s.kgio_tryaccept and process_client(s)
61         end
62       rescue Errno::EINTR
63       rescue => e
64         Error.listen_loop(e)
65       end while G.alive
66     end
68     def join_threads(threads) # :nodoc:
69       G.quit!
70       threads.delete_if do |thr|
71         G.tick
72         begin
73           thr.run
74           thr.join(0.01)
75         rescue
76           true
77         end
78       end until threads.empty?
79     end
81   end
82 end