From 3896e2aa121bfc0ea99951bd984c8acf51f01154 Mon Sep 17 00:00:00 2001 From: Shannon Skipper Date: Tue, 19 Aug 2014 21:26:30 -0700 Subject: [PATCH] Fix thread spawning edge case. Rapidly adding work to the ThreadPool can result in many jobs making it onto `@todo` before one of the jobs gets the mutex lock to decrement `@waiting`. So `@waiting == 0` isn't true and no thread is spawned even though there's work piling up, e.g.: ```ruby require 'puma/thread_pool' pool = Puma::ThreadPool.new(1, 3) { sleep 2 } 3.times { pool << 1 } sleep 1 pool.spawned #=> 1 # When 3 is expected ``` Checking if `@waiting < @todo.size` shows that there's more work to do than threads waiting even if `@waiting` hasn't been decremented to `0` and also covers the base case where `@waiting == 0` and `@tudo.size == 1`. An alternate option would be just adding the new check without removing the old one, something like `(@waiting == 0 or @waiting < @todo.size)`, but I don't think it's necessary unless for some kind of performance reason. --- lib/puma/thread_pool.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puma/thread_pool.rb b/lib/puma/thread_pool.rb index 0746be6c..bbbad700 100644 --- a/lib/puma/thread_pool.rb +++ b/lib/puma/thread_pool.rb @@ -114,7 +114,7 @@ module Puma @todo << work - if @waiting == 0 and @spawned < @max + if @waiting < @todo.size and @spawned < @max spawn_thread end