Skip to content

Commit 86622fa

Browse files
committed
Add more information.
1 parent 8b3882f commit 86622fa

File tree

1 file changed

+72
-32
lines changed

1 file changed

+72
-32
lines changed

README.md

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,7 @@ module Puma
19571957
class Server
19581958
def run(background=true)
19591959
#...
1960+
@status = :run
19601961
queue_requests = @queue_requests
19611962

19621963
# This part is important.
@@ -1978,7 +1979,7 @@ module Puma
19781979

19791980
# ...
19801981
if process_now
1981-
# process the request. You can treat `client` as request.
1982+
# Process the request. You can treat `client` as request.
19821983
# If you want to know more about 'process_client', please read part 3
19831984
# or search 'process_client' in this document.
19841985
process_client(client, buffer)
@@ -1991,11 +1992,12 @@ module Puma
19911992
# ...
19921993

19931994
if background # background: true (for this example)
1994-
# It's important part.
1995+
# This part is important.
19951996
# Remember puma created a thread here!
1996-
# We will know that the thread's job is waiting for requests.
1997+
# We will know that the newly created thread's job is waiting for requests.
19971998
# When a request comes, the thread will transfer the request processing work to a thread in ThreadPool.
1998-
# The method `handle_servers` in thread's block will be executed immediately.
1999+
# The method `handle_servers` in thread's block will be executed immediately
2000+
# (executed in the newly created thread, not in the main thread).
19992001
@thread = Thread.new { handle_servers } # Let's step into this line to see what I said.
20002002
return @thread
20012003
else
@@ -2010,11 +2012,11 @@ module Puma
20102012

20112013
# ...
20122014

2013-
# The thread is always running!
2015+
# The thread is always running, because @status has been set to :run in Puma::Server#run.
20142016
# Yes, it should always be running to transfer the incoming requests.
20152017
while @status == :run
20162018
begin
2017-
# This line will cause current thread waiting until a request is coming.
2019+
# This line will cause current thread waiting until a request arrives.
20182020
# So it will be the entry of every request!
20192021
ios = IO.select sockets
20202022

@@ -2029,7 +2031,8 @@ module Puma
20292031
# ...
20302032

20312033
# FYI, the method '<<' is redefined.
2032-
# Add the request (client) to thread pool means a thread in the pool will process this request (client).
2034+
# Add the request (client) to thread pool means
2035+
# a thread in the pool will process this request (client).
20332036
pool << client # Let's step into this line.
20342037

20352038
pool.wait_until_not_full # Let's step into this line later.
@@ -2058,24 +2061,24 @@ module Puma
20582061
def initialize(min, max, *extra, &block)
20592062
#..
20602063
@mutex = Mutex.new
2061-
@todo = [] # @todo is requests (in puma, it's Puma::Client instance) which need to be processed.
2062-
@spawned = 0 # The count of @spawned threads.
2064+
@todo = [] # @todo is requests (in puma, they are Puma::Client instances) which need to be processed.
2065+
@spawned = 0 # the count of @spawned threads
20632066
@min = Integer(min) # @min threads count
20642067
@max = Integer(max) # @max threads count
20652068
@block = block # block will be called in method `spawn_thread` to processed a request.
20662069
@workers = []
20672070
@reaper = nil
20682071

20692072
@mutex.synchronize do
2070-
@min.times { spawn_thread } # Puma started @min count threads.
2073+
@min.times { spawn_thread } # Puma spawned @min count threads.
20712074
end
20722075
end
20732076

20742077
def spawn_thread
20752078
@spawned += 1
20762079

2077-
# Run a new Thread now.
2078-
# The block of the thread will be executed separately from the calling thread.
2080+
# Create a new Thread now.
2081+
# The block of the thread will be executed immediately and separately from the calling thread (main thread).
20792082
th = Thread.new(@spawned) do |spawned|
20802083
# Thread name is new in Ruby 2.3
20812084
Thread.current.name = 'puma %03i' % spawned if Thread.current.respond_to?(:name=)
@@ -2118,7 +2121,7 @@ module Puma
21182121
# You can search `def <<(work)` in this document.
21192122
# Method `<<` is used in method `handle_servers`: `pool << client` in Puma::Server#run.
21202123
# `pool << client` means add a request to the thread pool,
2121-
# and then the thread waked up will process the request.
2124+
# and then the waked up thread will process the request.
21222125
not_empty.wait mutex
21232126

21242127
@waiting -= 1
@@ -2136,7 +2139,7 @@ module Puma
21362139

21372140
begin
21382141
# `block.call` will switch program to the block definition part.
2139-
# The Block definition part is in `Puma::Server#run`:
2142+
# The block definition part is in `Puma::Server#run`:
21402143
# @thread_pool = ThreadPool.new(@min_threads,
21412144
# @max_threads,
21422145
# IOBuffer) do |client, buffer| #...; end
@@ -2191,7 +2194,7 @@ module Puma
21912194

21922195
# Wake up the waiting thread to process the request.
21932196
# The waiting thread is defined in the same file: Puma::ThreadPool#spawn_thread.
2194-
# There are these code in `spawn_thread`:
2197+
# This code is in `spawn_thread`:
21952198
# while true
21962199
# # ...
21972200
# not_empty.wait mutex
@@ -2200,7 +2203,7 @@ module Puma
22002203
# end
22012204
@not_empty.signal
22022205
end
2203-
end
2206+
end
22042207
end
22052208
end
22062209
```
@@ -2212,7 +2215,7 @@ In `#perform`, call `Rails::Server#start`. Then call `Rack::Server#start`.
22122215

22132216
Then call `Rack::Handler::Puma.run(YourProject::Application.new)`.
22142217

2215-
In `.run`, Puma will new a always running Thread to `ios = IO.select(sockets)`.
2218+
In `.run`, Puma will new a always running Thread for `ios = IO.select sockets`.
22162219

22172220
Request is created from `ios` object.
22182221

@@ -2222,14 +2225,15 @@ The thread will invoke rack apps' `call` to get the response for the request.
22222225

22232226
### Exiting Puma
22242227
#### Process and Thread
2225-
For Puma is multiple threads, we need to have some basic concepts about Process and Thread.
2228+
Because Puma is using multiple threads, we need to have some basic concepts about Process and Thread.
22262229

2227-
This link's good for you to obtain the concepts: [Process and Thread](https://stackoverflow.com/questions/4894609/will-a-cpu-process-have-at-least-one-thread)
2230+
This link is good for you to obtain the concepts: [Process and Thread](https://stackoverflow.com/questions/4894609/will-a-cpu-process-have-at-least-one-thread)
22282231

22292232
In the next part, you will often see `thread.join`.
22302233

2231-
I will use a simple example to tell what does `thread.join` do.
2234+
I will use two simple example to tell what does `thread.join` do.
22322235

2236+
##### Example one
22332237
Try to run `test_thread_join.rb`.
22342238

22352239
```ruby
@@ -2256,6 +2260,32 @@ After you added `thread.join`, you can see:
22562260
````
22572261
in console.
22582262

2263+
##### Example two
2264+
```ruby
2265+
arr = [
2266+
Thread.new { sleep 1 },
2267+
Thread.new do
2268+
sleep 5
2269+
puts 'I am arry[1]'
2270+
end,
2271+
Thread.new { sleep 8}
2272+
]
2273+
2274+
puts Thread.list.size # returns 4 (including the main thread)
2275+
2276+
sleep 2
2277+
2278+
arr.each { |thread| puts "~~~~~ #{thread}" }
2279+
2280+
puts Thread.list.size # returns 3 (because arr[0] is dead)
2281+
2282+
# arr[1].join # comment off to see differences
2283+
2284+
arr.each { |thread| puts "~~~~~ #{thread}" }
2285+
2286+
puts "Exit main thread"
2287+
```
2288+
22592289
#### Send `SIGTERM` to Puma
22602290
When you stop puma by running `$ kill -s SIGTERM puma_process_id`, you will enter `setup_signals` in `Puma::Launcher#run`.
22612291
```ruby
@@ -2267,7 +2297,7 @@ module Puma
22672297
def run
22682298
#...
22692299
2270-
# Set the behavior for signals like `$ kill -s SIGTERM process_id`.
2300+
# Set the behaviors for signals like `$ kill -s SIGTERM process_id`.
22712301
setup_signals # Let's step into this line.
22722302
22732303
set_process_title
@@ -2277,7 +2307,7 @@ module Puma
22772307
# ...
22782308
end
22792309
2280-
# Set the behavior for signals like `$ kill -s SIGTERM process_id`.
2310+
# Set the behaviors for signals like `$ kill -s SIGTERM process_id`.
22812311
# Signal.list #=> {"EXIT"=>0, "HUP"=>1, "INT"=>2, "QUIT"=>3, "ILL"=>4, "TRAP"=>5, "IOT"=>6, "ABRT"=>6, "FPE"=>8, "KILL"=>9, "BUS"=>7, "SEGV"=>11, "SYS"=>31, "PIPE"=>13, "ALRM"=>14, "TERM"=>15, "URG"=>23, "STOP"=>19, "TSTP"=>20, "CONT"=>18, "CHLD"=>17, "CLD"=>17, "TTIN"=>21, "TTOU"=>22, "IO"=>29, "XCPU"=>24, "XFSZ"=>25, "VTALRM"=>26, "PROF"=>27, "WINCH"=>28, "USR1"=>10, "USR2"=>12, "PWR"=>30, "POLL"=>29}
22822312
# Press `Control + C` to quit means 'SIGINT'.
22832313
def setup_signals
@@ -2357,7 +2387,7 @@ module Puma
23572387
thread = server.run
23582388
23592389
# This line will suspend the main thread execution.
2360-
# And the `thread`'s block (which is method `handle_servers`) will be executed.
2390+
# And the `thread`'s block (which is the method `handle_servers`) will be executed.
23612391
thread.join
23622392
end
23632393
@@ -2374,7 +2404,7 @@ end
23742404
module Puma
23752405
class Server
23762406
def initialize(app, events=Events.stdio, options={})
2377-
# This method returns `IO.pipe`.
2407+
# 'Puma::Util.pipe' returns `IO.pipe`.
23782408
@check, @notify = Puma::Util.pipe # @check, @notify is a pair.
23792409
23802410
@status = :stop
@@ -2387,7 +2417,7 @@ module Puma
23872417
IOBuffer) do |client, buffer|
23882418
23892419
#...
2390-
# process the request.
2420+
# Process the request.
23912421
process_client(client, buffer)
23922422
#...
23932423
end
@@ -2419,7 +2449,9 @@ module Puma
24192449
# Stops the acceptor thread and then causes the worker threads to finish
24202450
# off the request queue before finally exiting.
24212451
def stop(sync=false)
2422-
# This line which change the :status to :stop.
2452+
# This line will set '@status = :stop',
2453+
# and cause `ios = IO.select sockets` in method `handle_servers` to return result.
2454+
# So the code after `ios = IO.select sockets` will be executed.
24232455
notify_safely(STOP_COMMAND) # Let's step into this line.
24242456
24252457
# 'Thread.current.object_id' returns '70144214949920',
@@ -2430,9 +2462,7 @@ module Puma
24302462
# The @thread is just the always running Thread created in `Puma::Server#run`.
24312463
# Please look at method `Puma::Server#run`.
24322464
# `@thread.join` will suspend the main thread execution.
2433-
# And the @thread's code will continue be executed.
2434-
# Because @thread is waiting for incoming request, the next executed code
2435-
# will be `ios = IO.select sockets` in method `handle_servers`.
2465+
# And the code in @thread will continue be executed.
24362466
@thread.join if @thread && sync
24372467
end
24382468

@@ -2443,12 +2473,18 @@ module Puma
24432473
def handle_servers
24442474
begin
24452475
check = @check
2476+
# sockets: [#<IO:fd 23>, #<TCPServer:fd 22, AF_INET, 0.0.0.0, 3000>]
24462477
sockets = [check] + @binder.ios
24472478
pool = @thread_pool
24482479
#...
24492480

24502481
while @status == :run
2451-
# After `@thread.join` in main thread, this line will be executed and will return result.
2482+
# After `notify_safely(STOP_COMMAND)` in main thread, this line will be executed and will return result.
2483+
# FYI, `@check, @notify = IO.pipe`.
2484+
# def notify_safely(message)
2485+
# @notify << message
2486+
# end
2487+
# sockets: [#<IO:fd 23>, #<TCPServer:fd 22, AF_INET, 0.0.0.0, 3000>]
24522488
ios = IO.select sockets
24532489

24542490
ios.first.each do |sock|
@@ -2528,6 +2564,10 @@ module Puma
25282564
# ...
25292565

25302566
# dup workers so that we join them all safely
2567+
# @workers is an array.
2568+
# @workers.dup will not create new thread.
2569+
# @workers is an instance variable and will be changed when shutdown (by `@workers.delete th`).
2570+
# So ues dup.
25312571
@workers.dup
25322572
end
25332573

@@ -2539,7 +2579,7 @@ module Puma
25392579
@spawned = 0
25402580
@workers = []
25412581
end
2542-
2582+
25432583
def initialize(min, max, *extra, &block)
25442584
#..
25452585
@mutex = Mutex.new
@@ -2621,7 +2661,7 @@ module Puma
26212661
def run
26222662
#...
26232663

2624-
# Set the behavior for signals like `$ kill -s SIGTERM process_id`.
2664+
# Set the behaviors for signals like `$ kill -s SIGTERM process_id`.
26252665
setup_signals # Let's step into this line.
26262666

26272667
set_process_title

0 commit comments

Comments
 (0)