thin 1.8.2 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

Files changed (108) hide show
  1. data/.gitignore +9 -0
  2. data/CHANGELOG +29 -116
  3. data/Gemfile +8 -0
  4. data/README.md +44 -78
  5. data/Rakefile +28 -18
  6. data/bin/thin +4 -4
  7. data/examples/async.ru +21 -0
  8. data/examples/thin.conf.rb +39 -0
  9. data/lib/thin/async.rb +108 -0
  10. data/lib/thin/backends/prefork.rb +44 -0
  11. data/lib/thin/backends/single_process.rb +28 -0
  12. data/lib/thin/chunked_body.rb +28 -0
  13. data/lib/thin/configurator.rb +118 -0
  14. data/lib/thin/connection.rb +246 -172
  15. data/lib/thin/listener.rb +114 -0
  16. data/lib/thin/request.rb +94 -76
  17. data/lib/thin/response.rb +112 -45
  18. data/lib/thin/runner.rb +134 -197
  19. data/lib/thin/server.rb +203 -252
  20. data/lib/thin/system.rb +49 -0
  21. data/lib/thin/version.rb +12 -27
  22. data/lib/thin.rb +2 -44
  23. data/man/index.txt +3 -0
  24. data/man/thin-conf.5.ronn +121 -0
  25. data/man/thin.1.ronn +105 -0
  26. data/site/.gitignore +2 -0
  27. data/site/README.md +21 -0
  28. data/site/Rakefile +20 -0
  29. data/site/config.ru +4 -0
  30. data/site/public/images/grid.png +0 -0
  31. data/site/public/javascripts/dd_belatedpng.js +13 -0
  32. data/site/public/javascripts/modernizr-1.6.min.js +30 -0
  33. data/site/public/man/thin-conf.5.html +220 -0
  34. data/site/public/man/thin.1.html +177 -0
  35. data/site/site/assets/javascripts/main.coffee +2 -0
  36. data/site/site/assets/stylesheets/_config.scss +55 -0
  37. data/site/site/assets/stylesheets/main.scss +24 -0
  38. data/site/site/helpers.rb +17 -0
  39. data/site/site/layouts/base.erb +55 -0
  40. data/site/site/layouts/default.erb +17 -0
  41. data/site/site/pages/about.md +5 -0
  42. data/site/site/pages/index.erb +10 -0
  43. data/site/site/partials/.gitkeep +0 -0
  44. data/test/fixtures/big.txt +1 -0
  45. data/test/fixtures/small.txt +1 -0
  46. data/test/fixtures/thin.conf.rb +15 -0
  47. data/test/integration/async_test.rb +35 -0
  48. data/test/integration/big_request_test.rb +30 -0
  49. data/test/integration/config.ru +57 -0
  50. data/test/integration/daemonize_test.rb +26 -0
  51. data/test/integration/env_test.rb +44 -0
  52. data/test/integration/error_test.rb +37 -0
  53. data/test/integration/file_sending_test.rb +24 -0
  54. data/test/integration/keep_alive_test.rb +35 -0
  55. data/test/integration/robustness_test.rb +37 -0
  56. data/test/integration/single_process_test.rb +15 -0
  57. data/test/integration/socket_family_test.rb +38 -0
  58. data/test/integration/worker_test.rb +22 -0
  59. data/test/test_helper.rb +195 -0
  60. data/test/unit/configurator_test.rb +43 -0
  61. data/test/unit/connection_test.rb +94 -0
  62. data/test/unit/listener_test.rb +74 -0
  63. data/test/unit/request_test.rb +74 -0
  64. data/test/unit/response_test.rb +90 -0
  65. data/test/unit/server_test.rb +29 -0
  66. data/test/unit/system_test.rb +17 -0
  67. data/thin.gemspec +26 -0
  68. data/v2.todo +21 -0
  69. metadata +138 -93
  70. checksums.yaml +0 -7
  71. data/example/adapter.rb +0 -32
  72. data/example/async_app.ru +0 -126
  73. data/example/async_chat.ru +0 -247
  74. data/example/async_tailer.ru +0 -100
  75. data/example/config.ru +0 -22
  76. data/example/monit_sockets +0 -20
  77. data/example/monit_unixsock +0 -20
  78. data/example/myapp.rb +0 -1
  79. data/example/ramaze.ru +0 -12
  80. data/example/thin.god +0 -80
  81. data/example/thin_solaris_smf.erb +0 -36
  82. data/example/thin_solaris_smf.readme.txt +0 -150
  83. data/example/vlad.rake +0 -72
  84. data/ext/thin_parser/common.rl +0 -59
  85. data/ext/thin_parser/ext_help.h +0 -14
  86. data/ext/thin_parser/extconf.rb +0 -6
  87. data/ext/thin_parser/parser.c +0 -1447
  88. data/ext/thin_parser/parser.h +0 -49
  89. data/ext/thin_parser/parser.rl +0 -152
  90. data/ext/thin_parser/thin.c +0 -435
  91. data/lib/rack/adapter/loader.rb +0 -75
  92. data/lib/rack/adapter/rails.rb +0 -178
  93. data/lib/rack/handler/thin.rb +0 -38
  94. data/lib/thin/backends/base.rb +0 -169
  95. data/lib/thin/backends/swiftiply_client.rb +0 -66
  96. data/lib/thin/backends/tcp_server.rb +0 -34
  97. data/lib/thin/backends/unix_server.rb +0 -56
  98. data/lib/thin/command.rb +0 -53
  99. data/lib/thin/controllers/cluster.rb +0 -178
  100. data/lib/thin/controllers/controller.rb +0 -189
  101. data/lib/thin/controllers/service.rb +0 -76
  102. data/lib/thin/controllers/service.sh.erb +0 -39
  103. data/lib/thin/daemonizing.rb +0 -199
  104. data/lib/thin/headers.rb +0 -47
  105. data/lib/thin/logging.rb +0 -174
  106. data/lib/thin/stats.html.erb +0 -216
  107. data/lib/thin/stats.rb +0 -52
  108. data/lib/thin/statuses.rb +0 -48
data/lib/thin/server.rb CHANGED
@@ -1,290 +1,241 @@
1
+ require "eventmachine"
2
+
3
+ require "thin/system"
4
+ require "thin/listener"
5
+ require "thin/connection"
6
+ require "thin/backends/prefork"
7
+ require "thin/backends/single_process"
8
+
1
9
  module Thin
2
- # The utterly famous Thin HTTP server.
3
- # It listens for incoming requests through a given +backend+
4
- # and forwards all requests to +app+.
5
- #
6
- # == TCP server
7
- # Create a new TCP server bound to <tt>host:port</tt> by specifiying +host+
8
- # and +port+ as the first 2 arguments.
10
+ # The uterly famous Thin server.
9
11
  #
10
- # Thin::Server.start('0.0.0.0', 3000, app)
12
+ # == Listening
13
+ # Create and start a new server listenting on port 3000 and forwarding all requests to +app+.
11
14
  #
12
- # == UNIX domain server
13
- # Create a new UNIX domain socket bound to +socket+ file by specifiying a filename
14
- # as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a <tt>/</tt>
15
- # it will be assumed to be a UNIX socket.
15
+ # server = Thin::Server.new(app)
16
+ # server.listen 3000
17
+ # server.start
16
18
  #
17
- # Thin::Server.start('/tmp/thin.sock', app)
19
+ # == Preforking and workers
20
+ # If fork(2) is available on your system, Thin will try to start workers to process requests.
21
+ # By default the number of workers will be based on the number of processors on your system.
22
+ # Configure this using the +worker_processes+ attribute.
23
+ # However, if fork(2) or if +worker_processes+ if equal to +0+, Thin will run in a single process
24
+ # with limited features.
18
25
  #
19
- # == Using a custom backend
20
- # You can implement your own way to connect the server to its client by creating your
21
- # own Backend class and passing it as the :backend option.
26
+ # == Single process mode
27
+ # In this mode, Thin features will be limited:
28
+ # - no log files
29
+ # - no signal handling (only exits on INT).
22
30
  #
23
- # Thin::Server.start('galaxy://faraway', 1345, app, :backend => Thin::Backends::MyFancyBackend)
31
+ # This mode is only intended as a fallback for systems with no fork(2) system call.
24
32
  #
25
- # == Rack application (+app+)
26
- # All requests will be processed through +app+, which must be a valid Rack adapter.
27
- # A valid Rack adapter (application) must respond to <tt>call(env#Hash)</tt> and
28
- # return an array of <tt>[status, headers, body]</tt>.
29
- #
30
- # == Building an app in place
31
- # If a block is passed, a <tt>Rack::Builder</tt> instance
32
- # will be passed to build the +app+. So you can do cool stuff like this:
33
- #
34
- # Thin::Server.start('0.0.0.0', 3000) do
35
- # use Rack::CommonLogger
36
- # use Rack::ShowExceptions
37
- # map "/lobster" do
38
- # use Rack::Lint
39
- # run Rack::Lobster.new
40
- # end
41
- # end
33
+ # You can force this mode by setting +worker_processes+ to +0+.
42
34
  #
43
35
  # == Controlling with signals
44
- # * INT and TERM: Force shutdown (see Server#stop!)
45
- # * TERM & QUIT calls +stop+ to shutdown gracefully.
46
- # * HUP calls +restart+ to ... surprise, restart!
47
- # * USR1 reopen log files.
48
- # Signals are processed at one second intervals.
49
- # Disable signals by passing <tt>:signals => false</tt>.
50
- #
36
+ # - *WINCH*: Gracefully kill all workers but keep master alive
37
+ # - *TTIN*: Increase number of workers
38
+ # - *TTOU*: Decrease number of workers
39
+ # - *QUIT*: Kill workers and master in a graceful way
40
+ # - *TERM*, *INT*: Kill workers and master immediately
51
41
  class Server
52
- include Logging
53
- include Daemonizable
54
- extend Forwardable
42
+ # Application called with the request that produces the response.
43
+ attr_reader :app
55
44
 
56
- # Default values
57
- DEFAULT_TIMEOUT = 30 #sec
58
- DEFAULT_HOST = '0.0.0.0'
59
- DEFAULT_PORT = 3000
60
- DEFAULT_MAXIMUM_CONNECTIONS = 1024
61
- DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS = 100
62
-
63
- # Application (Rack adapter) called with the request that produces the response.
64
- attr_accessor :app
45
+ # Set to +true+ to load the app before forking to workers.
46
+ # Default: false
47
+ attr_accessor :preload_app
65
48
 
66
49
  # A tag that will show in the process listing
67
50
  attr_accessor :tag
68
51
 
69
- # Backend handling the connections to the clients.
70
- attr_accessor :backend
71
-
72
- # Maximum number of seconds for incoming data to arrive before the connection
73
- # is dropped.
74
- def_delegators :backend, :timeout, :timeout=
75
-
76
- # Maximum number of file or socket descriptors that the server may open.
77
- def_delegators :backend, :maximum_connections, :maximum_connections=
78
-
79
- # Maximum number of connections that can be persistent at the same time.
80
- # Most browsers never close the connection so most of the time they are closed
81
- # when the timeout occurs. If we don't control the number of persistent connections,
82
- # it would be very easy to overflow the server for a DoS attack.
83
- def_delegators :backend, :maximum_persistent_connections, :maximum_persistent_connections=
84
-
85
- # Allow using threads in the backend.
86
- def_delegators :backend, :threaded?, :threaded=, :threadpool_size, :threadpool_size=
87
-
88
- # Allow using SSL in the backend.
89
- def_delegators :backend, :ssl?, :ssl=, :ssl_options=
90
-
91
- # Address and port on which the server is listening for connections.
92
- def_delegators :backend, :host, :port
93
-
94
- # UNIX domain socket on which the server is listening for connections.
95
- def_delegator :backend, :socket
96
-
97
- # Disable the use of epoll under Linux
98
- def_delegators :backend, :no_epoll, :no_epoll=
52
+ # Number of child worker processes.
53
+ # Setting this to 0 will result in running in a single process with limited features.
54
+ # Default: number of processors available, or 1 in development, or 0 if +fork+ is not available.
55
+ attr_accessor :worker_processes
56
+
57
+ # Maximum number of file descriptors that the worker may open.
58
+ # Default: 1024
59
+ attr_accessor :worker_connections
60
+
61
+ # Set to +true+ to call +app+ in a thread.
62
+ # Default: false
63
+ attr_accessor :threaded
64
+
65
+ # Size of the pool of threads used to call the +app+.
66
+ # Default: 20
67
+ attr_accessor :thread_pool_size
68
+
69
+ # Workers are killed if they don't check-in under +timeout+ seconds.
70
+ # Default: 30
71
+ attr_accessor :timeout
99
72
 
100
- def initialize(*args, &block)
101
- host, port, options = DEFAULT_HOST, DEFAULT_PORT, {}
73
+ # Maximum number of concurrent requests which can be made over a keep-alive connection.
74
+ # Default: 100
75
+ attr_accessor :max_keep_alive_requests
76
+
77
+ # Path to the file in which the PID is saved.
78
+ # Default: ./thin.pid
79
+ attr_accessor :pid_path
80
+
81
+ # Path to the file in which standard output streams are redirected.
82
+ # Default: none, outputs to stdout
83
+ attr_accessor :log_path
84
+
85
+ # Set to +true+ to use epoll event model.
86
+ attr_accessor :use_epoll
87
+
88
+ # Set to +true+ to use kqueue event model.
89
+ attr_accessor :use_kqueue
90
+
91
+ # Set the backend handling the connections to the clients.
92
+ attr_writer :backend
93
+
94
+ # Listeners currently registered on this server.
95
+ # @see Thin::Listener
96
+ attr_accessor :listeners
97
+
98
+ # Object that is +call+ed before forking a worker process inside the master process.
99
+ attr_accessor :before_fork
100
+
101
+ # Object that is +call+ed after forking a worker process inside the worker process.
102
+ attr_accessor :after_fork
103
+
104
+ # Creates a new server that will forward requests to the app returned when +call+ing the +app_loader+ block.
105
+ # When +preload_app+ is set to +true+, +app_loader+ will be called before forking.
106
+ # When +preload_app+ is set to +false+, +app_loader+ will be called after forking.
107
+ # +host+, +port+ and +app+ supported for backward compatibility with Rack adapter.
108
+ def initialize(host=nil, port=nil, app=nil, &app_loader)
109
+ app_loader = proc { app } if app
110
+ @app_loader = app_loader || raise(ArgumentError, "app_loader block required")
102
111
 
103
- # Guess each parameter by its type so they can be
104
- # received in any order.
105
- args.each do |arg|
106
- case arg
107
- when 0.class, /^\d+$/ then port = arg.to_i
108
- when String then host = arg
109
- when Hash then options = arg
112
+ # Set defaults
113
+ @preload_app = false
114
+ @timeout = 30
115
+ @pid_path = "./thin.pid"
116
+ @log_path = nil
117
+ @worker_connections = 1024
118
+ @threaded = false
119
+ @thread_pool_size = 20
120
+ @max_keep_alive_requests = 100
121
+ @keep_alive_requests = 0
122
+ @connections = 0 # Number of active connections
123
+
124
+ if System.supports_fork?
125
+ if ENV["RACK_ENV"] == "development"
126
+ # Default to one worker in development.
127
+ @worker_processes = 1
110
128
  else
111
- @app = arg if arg.respond_to?(:call)
129
+ # One worker per processor in production.
130
+ @worker_processes = System.processor_count
112
131
  end
132
+ else
133
+ # No workers, runs in a single process.
134
+ @worker_processes = 0
113
135
  end
114
-
115
- # Set tag if needed
116
- self.tag = options[:tag]
117
136
 
118
- # Try to intelligently select which backend to use.
119
- @backend = select_backend(host, port, options)
120
-
121
- load_cgi_multipart_eof_fix
137
+ @listeners = []
122
138
 
123
- @backend.server = self
124
-
125
- # Set defaults
126
- @backend.maximum_connections = DEFAULT_MAXIMUM_CONNECTIONS
127
- @backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
128
- @backend.timeout = options[:timeout] || DEFAULT_TIMEOUT
129
-
130
- # Allow using Rack builder as a block
131
- @app = Rack::Builder.new(&block).to_app if block
132
-
133
- # If in debug mode, wrap in logger adapter
134
- @app = Rack::CommonLogger.new(@app) if Logging.debug?
135
-
136
- @setup_signals = options[:signals] != false
139
+ listen "#{host}:#{port}" if host && port
137
140
  end
138
-
139
- # Lil' shortcut to turn this:
140
- #
141
- # Server.new(...).start
142
- #
143
- # into this:
144
- #
145
- # Server.start(...)
146
- #
147
- def self.start(*args, &block)
148
- new(*args, &block).start!
149
- end
150
-
151
- # Start the server and listen for connections.
152
- def start
153
- raise ArgumentError, 'app required' unless @app
154
-
155
- log_info "Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
156
- log_debug "Debugging ON"
157
- trace "Tracing ON"
158
-
159
- log_info "Maximum connections set to #{@backend.maximum_connections}"
160
- log_info "Listening on #{@backend}, CTRL+C to stop"
161
141
 
162
- @backend.start { setup_signals if @setup_signals }
163
- end
164
- alias :start! :start
165
-
166
- # == Gracefull shutdown
167
- # Stops the server after processing all current connections.
168
- # As soon as this method is called, the server stops accepting
169
- # new requests and waits for all current connections to finish.
170
- # Calling twice is the equivalent of calling <tt>stop!</tt>.
171
- def stop
172
- if running?
173
- @backend.stop
174
- unless @backend.empty?
175
- log_info "Waiting for #{@backend.size} connection(s) to finish, "\
176
- "can take up to #{timeout} sec, CTRL+C to stop now"
142
+ # Backend handling connections to the clients.
143
+ def backend
144
+ @backend ||= begin
145
+ if prefork?
146
+ Backends::Prefork.new(self)
147
+ else
148
+ Backends::SingleProcess.new(self)
177
149
  end
178
- else
179
- stop!
180
150
  end
181
151
  end
182
152
 
183
- # == Force shutdown
184
- # Stops the server closing all current connections right away.
185
- # This doesn't wait for connection to finish their work and send data.
186
- # All current requests will be dropped.
187
- def stop!
188
- if @backend.started_reactor?
189
- log_info "Stopping ..."
190
- else
191
- log_info "Stopping Thin ..."
192
- log_info "Thin was started inside an existing EventMachine.run block."
193
- log_info "Call `EventMachine.stop` to stop the reactor and quit the process."
194
- end
195
-
196
- @backend.stop!
197
- end
198
-
199
- # == Reopen log file.
200
- # Reopen the log file and redirect STDOUT and STDERR to it.
201
- def reopen_log
202
- return unless log_file
203
- file = File.expand_path(log_file)
204
- log_info "Reopening log file: #{file}"
205
- Daemonize.redirect_io(file)
153
+ # Listen for incoming connections on +address+.
154
+ # @example
155
+ # listen 3000 # port number
156
+ # listen "0.0.0.0:8008", :backlog => 80
157
+ # listen "[::]:8008", :ipv6_only => true
158
+ # listen "/tmp/thin.sock"
159
+ # @param address [String, Integer] address to listen on. Can be a port number of host:port.
160
+ # @option options [Boolean] :tcp_no_delay (true) Disables the Nagle algorithm for send coalescing.
161
+ # @option options [Boolean] :ipv6_only (false) do not listen on IPv4 interface.
162
+ # @option options [Integer] :backlog (1024) Maximum number of clients in the listening backlog.
163
+ def listen(address, options={})
164
+ @listeners << Listener.new(address, options)
206
165
  end
207
-
208
- # == Configure the server
209
- # The process might need to have superuser privilege to configure
210
- # server with optimal options.
211
- def config
212
- @backend.config
213
- end
214
-
215
- # Name of the server and type of backend used.
216
- # This is also the name of the process in which Thin is running as a daemon.
217
- def name
218
- "thin server (#{@backend})" + (tag ? " [#{tag}]" : "")
219
- end
220
- alias :to_s :name
221
-
222
- # Return +true+ if the server is running and ready to receive requests.
223
- # Note that the server might still be running and return +false+ when
224
- # shuting down and waiting for active connections to complete.
225
- def running?
226
- @backend.running?
227
- end
228
-
229
- protected
230
- def setup_signals
231
- # Queue up signals so they are processed in non-trap context
232
- # using a EM timer.
233
- @signal_queue ||= []
234
166
 
235
- %w( INT TERM ).each do |signal|
236
- trap(signal) { @signal_queue.push signal }
237
- end
238
- # *nix only signals
239
- %w( QUIT HUP USR1 ).each do |signal|
240
- trap(signal) { @signal_queue.push signal }
241
- end unless Thin.win?
167
+ # Starts the server and open a listening socket for each +listeners+.
168
+ # @param daemonize Daemonize the process after starting.
169
+ def start(daemonize=false)
170
+ puts "Starting #{to_s} ..."
242
171
 
243
- # Signals are processed at one second intervals.
244
- @signal_timer ||= EM.add_periodic_timer(1) { handle_signals }
245
- end
172
+ # Configure EventMachine
173
+ EM.epoll = @use_epoll unless @use_epoll.nil?
174
+ EM.kqueue = @use_kqueue unless @use_kqueue.nil?
175
+ @worker_connections = EM.set_descriptor_table_size(@worker_connections)
176
+ EM.threadpool_size = @thread_pool_size
246
177
 
247
- def handle_signals
248
- case @signal_queue.shift
249
- when 'INT'
250
- stop!
251
- when 'TERM', 'QUIT'
252
- stop
253
- when 'HUP'
254
- restart
255
- when 'USR1'
256
- reopen_log
257
- end
258
- EM.next_tick { handle_signals } unless @signal_queue.empty?
259
- end
260
-
261
- def select_backend(host, port, options)
262
- case
263
- when options.has_key?(:backend)
264
- raise ArgumentError, ":backend must be a class" unless options[:backend].is_a?(Class)
265
- options[:backend].new(host, port, options)
266
- when options.has_key?(:swiftiply)
267
- Backends::SwiftiplyClient.new(host, port, options)
268
- when host.include?('/')
269
- Backends::UnixServer.new(host)
270
- else
271
- Backends::TcpServer.new(host, port)
272
- end
178
+ # Preload the app in the master process.
179
+ @app = @app_loader.call if @preload_app
180
+
181
+ @listeners.each do |listener|
182
+ puts "Listening with #{listener}"
183
+ listener.listen
273
184
  end
274
-
275
- # Taken from Mongrel cgi_multipart_eof_fix
276
- # Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it.
277
- def load_cgi_multipart_eof_fix
278
- version = RUBY_VERSION.split('.').map { |i| i.to_i }
279
-
280
- if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/
281
- begin
282
- require 'cgi_multipart_eof_fix'
283
- rescue LoadError
284
- log_error "Ruby 1.8.5 is not secure please install cgi_multipart_eof_fix:"
285
- log_error "gem install cgi_multipart_eof_fix"
185
+ puts "CTRL+C to stop"
186
+
187
+ backend.start(daemonize) do
188
+ # Load the app in the worker process if it was not preloaded.
189
+ @app = @app_loader.call unless @preload_app
190
+
191
+ @listeners.each do |listener|
192
+ EM.attach_server(listener.socket, Connection) do |connection|
193
+ connection.comm_inactivity_timeout = @timeout
194
+ connection.server = self
195
+ connection.listener = listener
196
+
197
+ # We control the number of keep-alive connections to prevent easy DDoS attacks.
198
+ if @keep_alive_requests < @max_keep_alive_requests
199
+ connection.can_keep_alive = true
200
+ @keep_alive_requests += 1
201
+ else
202
+ connection.can_keep_alive = false
203
+ end
204
+
205
+ @connections += 1
206
+
207
+ # Decrement counters on close
208
+ connection.on_close do
209
+ @keep_alive_requests -= 1 if connection.can_keep_alive
210
+ @connections -= 1
211
+ end
286
212
  end
287
213
  end
288
214
  end
215
+ rescue
216
+ stop
217
+ raise
218
+ end
219
+
220
+ # Stops the server and close all listeners.
221
+ def stop
222
+ puts "Stopping ..."
223
+ @listeners.each { |listener| listener.close }
224
+ end
225
+ alias :shutdown :stop
226
+
227
+ # Returns +true+ if the server will fork workers or +false+ if it will run in a single process.
228
+ def prefork?
229
+ @worker_processes > 0
230
+ end
231
+
232
+ def threaded?
233
+ @threaded
234
+ end
235
+
236
+ # Procline of the process when the server is running.
237
+ def to_s
238
+ "Thin" + (@tag ? " [#{@tag}]" : "")
239
+ end
289
240
  end
290
241
  end
@@ -0,0 +1,49 @@
1
+ module Thin
2
+ module System
3
+ def self.win?
4
+ RUBY_PLATFORM =~ /mswin|mingw/
5
+ end
6
+
7
+ def self.java?
8
+ RUBY_PLATFORM =~ /java/
9
+ end
10
+
11
+ def self.linux?
12
+ RUBY_PLATFORM =~ /linux/
13
+ end
14
+
15
+ def self.ruby_18?
16
+ RUBY_VERSION =~ /^1\.8/
17
+ end
18
+
19
+ # Source: https://github.com/grosser/parallel/blob/master/lib/parallel.rb#L65-84
20
+ def self.processor_count
21
+ architecture = RbConfig::CONFIG['host_os']
22
+ case architecture = RbConfig::CONFIG['host_os']
23
+ when /darwin9/
24
+ `hwprefs cpu_count`.to_i
25
+ when /darwin/
26
+ (`which hwprefs` != '' ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
27
+ when /linux/
28
+ `grep -c processor /proc/cpuinfo`.to_i
29
+ when /freebsd/
30
+ `sysctl -n hw.ncpu`.to_i
31
+ when /mswin|mingw/
32
+ require 'win32ole'
33
+ wmi = WIN32OLE.connect("winmgmts://")
34
+ cpu = wmi.ExecQuery("select NumberOfLogicalProcessors from Win32_Processor")
35
+ cpu.to_enum.first.NumberOfLogicalProcessors
36
+ else
37
+ warn "Unknown architecture ( #{architecture} ) assuming one processor."
38
+ 1
39
+ end
40
+ end
41
+
42
+ def self.supports_fork?
43
+ fork { exit }
44
+ true
45
+ rescue NotImplementedError
46
+ false
47
+ end
48
+ end
49
+ end
data/lib/thin/version.rb CHANGED
@@ -1,32 +1,17 @@
1
1
  module Thin
2
- # Raised when a feature is not supported on the
3
- # current platform.
4
- class PlatformNotSupported < RuntimeError; end
5
-
6
- module VERSION #:nodoc:
7
- MAJOR = 1
8
- MINOR = 8
9
- TINY = 2
10
-
11
- STRING = [MAJOR, MINOR, TINY].join('.')
12
-
13
- CODENAME = "Ruby Razor".freeze
14
-
15
- RACK = [1, 0].freeze # Rack protocol version
2
+ module VERSION
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ TINY = 0
6
+ PRE = "pre"
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
+
10
+ CODENAME = "The Wire Burner".freeze
11
+
12
+ RACK = [1, 1].freeze # Rack protocol version
16
13
  end
17
-
14
+
18
15
  NAME = 'thin'.freeze
19
16
  SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
20
-
21
- def self.win?
22
- RUBY_PLATFORM =~ /mswin|mingw/
23
- end
24
-
25
- def self.linux?
26
- RUBY_PLATFORM =~ /linux/
27
- end
28
-
29
- def self.ruby_18?
30
- RUBY_VERSION =~ /^1\.8/
31
- end
32
17
  end
data/lib/thin.rb CHANGED
@@ -1,45 +1,3 @@
1
- require 'fileutils'
2
- require 'timeout'
3
- require 'stringio'
4
- require 'time'
5
- require 'forwardable'
6
- require 'openssl'
7
- require 'eventmachine'
8
- require 'rack'
9
-
10
- module Thin
11
- autoload :Command, "thin/command"
12
- autoload :Connection, "thin/connection"
13
- autoload :Daemonizable, "thin/daemonizing"
14
- autoload :Logging, "thin/logging"
15
- autoload :Headers, "thin/headers"
16
- autoload :Request, "thin/request"
17
- autoload :Response, "thin/response"
18
- autoload :Runner, "thin/runner"
19
- autoload :Server, "thin/server"
20
- autoload :Stats, "thin/stats"
21
-
22
- module Backends
23
- autoload :Base, "thin/backends/base"
24
- autoload :SwiftiplyClient, "thin/backends/swiftiply_client"
25
- autoload :TcpServer, "thin/backends/tcp_server"
26
- autoload :UnixServer, "thin/backends/unix_server"
27
- end
28
-
29
- module Controllers
30
- autoload :Cluster, "thin/controllers/cluster"
31
- autoload :Controller, "thin/controllers/controller"
32
- autoload :Service, "thin/controllers/service"
33
- end
34
- end
35
-
36
1
  require "thin/version"
37
- require "thin/statuses"
38
- require "rack/adapter/loader"
39
- require "thin_parser"
40
-
41
- module Rack
42
- module Adapter
43
- autoload :Rails, "rack/adapter/rails"
44
- end
45
- end
2
+ require "thin/system"
3
+ require "thin/server"
data/man/index.txt ADDED
@@ -0,0 +1,3 @@
1
+ # manuals
2
+ thin(1) thin.1.ronn
3
+ thin-conf(5) thin-conf.5.ronn