Class: Ffmprb::Util::Thread

Inherits:
Thread
  • Object
show all
Defined in:
lib/ffmprb/util/thread.rb

Overview

NOTE doesn’t have specs (and not too proud about it)

Direct Known Subclasses

Reader

Defined Under Namespace

Classes: Error, ParentError

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = "some", &blk) ⇒ Thread

Returns a new instance of Thread.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ffmprb/util/thread.rb', line 44

def initialize(name="some", &blk)
  @name = name
  @parent = Thread.current
  @live_children = []
  @children_mon = Monitor.new
  @dead_children_q = Queue.new
  Ffmprb.logger.debug "about to launch #{name}"
  sync_q = Queue.new
  super() do
    @parent.child_lives self  if @parent.respond_to? :child_lives
    sync_q.enq :ok
    Ffmprb.logger.debug "#{name} thread launched"
    begin
      blk.call.tap do
        Ffmprb.logger.debug "#{name} thread done"
      end
    rescue Exception
      Ffmprb.logger.warn "#{$!.class} raised in #{name} thread: #{$!.message}\nBacktrace:\n\t#{$!.backtrace.join("\n\t")}"
      cause = $!
      Ffmprb.logger.warn "...caused by #{cause.class}: #{cause.message}\nBacktrace:\n\t#{cause.backtrace.join("\n\t")}" while
        cause = cause.cause
      fail $!  # XXX I have no idea why I need to give it `$!` -- the docs say I need not
    ensure
      @parent.child_dies self  if @parent.respond_to? :child_dies
    end
  end
  sync_q.deq
end

Class Attribute Details

.timeoutObject

Returns the value of attribute timeout.



13
14
15
# File 'lib/ffmprb/util/thread.rb', line 13

def timeout
  @timeout
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



42
43
44
# File 'lib/ffmprb/util/thread.rb', line 42

def name
  @name
end

Class Method Details

.join_children!(limit = nil, timeout: self.timeout) ⇒ Object



36
37
38
# File 'lib/ffmprb/util/thread.rb', line 36

def join_children!(limit=nil, timeout: self.timeout)
  Thread.current.join_children! limit, timeout: timeout
end

.timeout_or_live(limit = nil, log: "while doing this", timeout: self.timeout, &blk) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ffmprb/util/thread.rb', line 15

def timeout_or_live(limit=nil, log: "while doing this", timeout: self.timeout, &blk)
  started_at = Time.now
  tries = 0
  logged_tries = 0
  begin
    tries += 1
    time = Time.now - started_at
    fail TimeLimitError  if limit && time > limit
    Timeout.timeout timeout do
      blk.call time
    end
  rescue Timeout::Error
    if tries > 2 * logged_tries
      Ffmprb.logger.info "A little bit of timeout #{log.respond_to?(:call)? log.call : log} (##{tries})"
      logged_tries = tries
    end
    current.live!
    retry
  end
end

Instance Method Details

#child_dies(thr) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/ffmprb/util/thread.rb', line 86

def child_dies(thr)
  @children_mon.synchronize do
    Ffmprb.logger.debug "releasing #{thr.name} thread"
    @dead_children_q.enq thr
    fail "System Error"  unless @live_children.delete thr
  end
end

#child_lives(thr) ⇒ Object



79
80
81
82
83
84
# File 'lib/ffmprb/util/thread.rb', line 79

def child_lives(thr)
  @children_mon.synchronize do
    Ffmprb.logger.debug "picking up #{thr.name} thread"
    @live_children << thr
  end
end

#join_children!(limit = nil, timeout: self.class.timeout) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/ffmprb/util/thread.rb', line 94

def join_children!(limit=nil, timeout: self.class.timeout)
  timeout = [timeout, limit].compact.min
  Ffmprb.logger.debug "joining threads: #{@live_children.size} live, #{@dead_children_q.size} dead"
  until @live_children.empty? && @dead_children_q.empty?
    thr = self.class.timeout_or_live limit, log: "joining threads: #{@live_children.size} live, #{@dead_children_q.size} dead", timeout: timeout do
      @dead_children_q.deq
    end
    Ffmprb.logger.debug "joining the late #{thr.name} thread"
    fail "System Error"  unless thr.join(timeout)  # NOTE should not block
  end
end

#live!Object

TODO protected: none of these methods should be called by a user code, the only public methods are above



75
76
77
# File 'lib/ffmprb/util/thread.rb', line 75

def live!
  fail ParentError  if @parent.status.nil?
end