1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| | # -*- encoding: binary -*-
module Rainbows
# Spawns a new thread for every client connection we accept(). This
# model is recommended for platforms like Ruby 1.8 where spawning new
# threads is inexpensive.
#
# This model should provide a high level of compatibility with all
# Ruby implementations, and most libraries and applications.
# Applications running under this model should be thread-safe
# but not necessarily reentrant.
#
# If you're connecting to external services and need to perform DNS
# lookups, consider using the "resolv-replace" library which replaces
# parts of the core Socket package with concurrent DNS lookup
# capabilities
module ThreadSpawn
include Base
def worker_loop(worker)
init_worker_process(worker)
threads = ThreadGroup.new
alive = worker.tmp
m = 0
limit = worker_connections
begin
G.alive && master_pid == Process.ppid or break
ret = begin
alive.chmod(m = 0 == m ? 1 : 0)
IO.select(LISTENERS, nil, nil, 1) or next
rescue Errno::EINTR
retry
rescue Errno::EBADF, TypeError
break
end
alive.chmod(m = 0 == m ? 1 : 0)
ret.first.each do |l|
# Sleep if we're busy, another less busy worker process may
# take it for us if we sleep. This is gross but other options
# still suck because they require expensive/complicated
# synchronization primitives for _every_ case, not just this
# unlikely one. Since this case is (or should be) uncommon,
# just busy wait when we have to.
while threads.list.size > limit # unlikely
sleep(0.1) # hope another process took it
break # back to IO.select
end
begin
threads.add(Thread.new(l.accept_nonblock) {|c| process_client(c) })
rescue Errno::EAGAIN, Errno::ECONNABORTED
end
end
rescue Object => e
listen_loop_error(e)
end while true
join_threads(threads.list, worker)
end
end
end
|