# -*- coding: utf-8 -*- require File.expand_path('utils') # ブロックを、後で時間があいたときに順次実行する。 # 名前deferのほうがよかったんじゃね class Delayer CRITICAL = 0 FASTER = 0 NORMAL = 1 LATER = 2 LAST = 2 extend MonitorMixin @@routines = [[],[],[]] @frozen = false attr_reader :backtrace, :status class << self attr_accessor :exception # 登録されたDelayerオブジェクトをいくつか実行する。 # 0.1秒以内に実行が終わらなければ、残りは保留してとりあえず処理を戻す。 def run return if @frozen debugging_wait begin @busy = true @st = Process.times.utime 3.times{ |cnt| procs = [] if not @@routines[cnt].empty? then procs = @@routines[cnt].clone procs.each{ |routine| @@routines[cnt].delete(routine) if Mopt.debug r_start = Process.times.utime routine.run if (r_end = Process.times.utime - r_start) > 0.1 bt = routine.backtrace.find{ |bt| not bt.include?('delayer') } bt = routine.backtrace.first if not bt Plugin.call(:processtime, :delayer, "#{"%.2f" % r_end},#{bt.gsub(FOLLOW_DIR, '{MIKUTTER_DIR}')}") end else routine.run end return if time_limit? } end } rescue => e Delayer.exception = e raise e ensure @busy = false end end def time_limit? (Process.times.utime - @st) > 0.02 end # Delayerのタスクを消化中ならtrueを返す def busy? @busy end # 仕事がなければtrue def empty? @@routines.all?{|r| r.empty? } end # 残っているDelayerの数を返す def size @@routines.map(&:size).reduce(:+)end # このメソッドが呼ばれたら、以後 Delayer.run が呼ばれても、Delayerオブジェクト # を実行せずにすぐにreturnするようになる。 def freeze @frozen = true end # freezeのはんたい def melt @frozen = false end def on_regist(delayer) end end # あとで実行するブロックを登録する。 def initialize(prio = NORMAL, *args, &block) @routine = block @args = args @backtrace = caller @status = :wait regist(prio) Delayer.on_regist(self) end # このDelayerを取り消す。処理が呼ばれる前に呼べば、処理をキャンセルできる def reject @status = nil end # このブロックを実行する。内部で呼ぶためにあるので、明示的に呼ばないこと def run return if @status != :wait @status = :run begin @routine.call(*@args) rescue Exception => e now = caller.size + 1 # @routine.callのぶんスタックが1つ多い $@ = e.backtrace[0, e.backtrace.size - now] + @backtrace raise e end @routine = nil @status = nil end private def regist(prio) self.class.synchronize{ @@routines[prio] << self } end end