From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.9 required=3.0 tests=ALL_TRUSTED,BAYES_00, URIBL_BLOCKED shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: unicorn-public@bogomips.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 256491F490; Sun, 18 Jan 2015 03:39:16 +0000 (UTC) Date: Sun, 18 Jan 2015 03:39:16 +0000 From: Eric Wong To: unicorn-public@bogomips.org Subject: [PATCH] use the monotonic clock under Ruby 2.1+ Message-ID: <20150118033916.GA4478@dcvr.yhbt.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline List-Id: The monotonic clock is immune to time adjustments so it is not thrown off by misconfigured clocks. Process.clock_gettime also generates less garbage on 64-bit systems due to the use of Flonum. --- lib/unicorn/http_server.rb | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb index a523fce..e0c0370 100644 --- a/lib/unicorn/http_server.rb +++ b/lib/unicorn/http_server.rb @@ -265,7 +265,7 @@ class Unicorn::HttpServer # is signalling us too often. def join respawn = true - last_check = Time.now + last_check = time_now proc_name 'master' logger.info "master process ready" # test_exec.rb relies on this message @@ -283,7 +283,7 @@ class Unicorn::HttpServer when nil # avoid murdering workers after our master process (or the # machine) comes out of suspend/hibernation - if (last_check + @timeout) >= (last_check = Time.now) + if (last_check + @timeout) >= (last_check = time_now) sleep_time = murder_lazy_workers else sleep_time = @timeout/2.0 + 1 @@ -337,8 +337,8 @@ class Unicorn::HttpServer # Terminates all workers, but does not exit master process def stop(graceful = true) self.listeners = [] - limit = Time.now + timeout - until WORKERS.empty? || Time.now > limit + limit = time_now + timeout + until WORKERS.empty? || time_now > limit if graceful soft_kill_each_worker(:QUIT) else @@ -470,7 +470,7 @@ class Unicorn::HttpServer # forcibly terminate all workers that haven't checked in in timeout seconds. The timeout is implemented using an unlinked File def murder_lazy_workers next_sleep = @timeout - 1 - now = Time.now.to_i + now = time_now.to_i WORKERS.dup.each_pair do |wpid, worker| tick = worker.tick 0 == tick and next # skip workers that haven't processed any clients @@ -650,7 +650,7 @@ class Unicorn::HttpServer begin nr < 0 and reopen_worker_logs(worker.nr) nr = 0 - worker.tick = Time.now.to_i + worker.tick = time_now.to_i tmp = ready.dup while sock = tmp.shift # Unicorn::Worker#kgio_tryaccept is not like accept(2) at all, @@ -658,7 +658,7 @@ class Unicorn::HttpServer if client = sock.kgio_tryaccept process_client(client) nr += 1 - worker.tick = Time.now.to_i + worker.tick = time_now.to_i end break if nr < 0 end @@ -675,7 +675,7 @@ class Unicorn::HttpServer ppid == Process.ppid or return # timeout used so we can detect parent death: - worker.tick = Time.now.to_i + worker.tick = time_now.to_i ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0] rescue => e redo if nr < 0 && readers[0] @@ -799,4 +799,17 @@ class Unicorn::HttpServer raise ArgumentError, "no listeners" if LISTENERS.empty? NEW_LISTENERS.clear end + + # try to use the monotonic clock in Ruby >= 2.1, it is immune to clock + # offset adjustments and generates less garbage (Float vs Time object) + begin + Process.clock_gettime(Process::CLOCK_MONOTONIC) + def time_now + Process.clock_gettime(Process::CLOCK_MONOTONIC) + end + rescue NameError, NoMethodError + def time_now # Ruby <= 2.0 + Time.now + end + end end -- EW