Q: threads and sleeping system calls

I’ve been playing around, adding a Dir::notify method
that uses ‘directory notification’ on Linux.
Summary: do a couple file-controls, setup a signal handler,
wait for a signal to occur.

This works OK in a single threaded script,
but it makes all the threads stop, when I use it
inside a thread.

Does anyone have any pointers to some thread-friendly
ways of doing this? Should I try to use Ruby’s signal
and trap handling? (but I need to get to the ‘siginfo’ struct)

Any clues appreciated!
Thanks!

···


Mike Hall
http://www.enteract.com/~mghall

Though I’m not sure of what you’d like to do, the following sketchs
how to raise an exception from specified thread when a signal is trapped.

hope this helps,

#---------------------------------------------------------------------- begin
module Signal # backward compatibility for Ruby 1.7 feature
unless self.respond_to?(:list)
LIST = { # obtained on freebsd4
"HUP" => 1, “INT” => 2, “QUIT” => 3, “ILL” => 4, “TRAP” => 5,
“ABRT” => 6, “IOT” => 6, “EMT” => 7, “FPE” => 8, “KILL” => 9,
“BUS” => 10, “SEGV” => 11, “SYS” => 12, “PIPE” => 13, “ALRM” => 14,
“TERM” => 15, “URG” => 16, “STOP” => 17, “TSTP” => 18,
“CONT” => 19, “CHLD” => 20, “CLD” => 20, “TTIN” => 21, “TTOU” => 22,
“IO” => 23, “XCPU” => 24, “XFSZ” => 25, “VTALRM” => 26,
“PROF” => 27, “WINCH” => 28, “INFO” => 29, “USR1” => 30, “USR2” => 31
}.freeze
def self.list() LIST end
end
end

class UnhundledThreadedSignal < Exception; end

class Thread
Signal_to_Thread = {}

def raise_by_signal(signal, exception = RuntimeError, opt = "")
  signo = Signal.list[signal]
  Signal_to_Thread[signo] = [self, exception.new(opt)]

  ::Kernel::trap(signal) do |s|
    t, e = Signal_to_Thread.delete(s)
    t ? t.raise(e) : ::Kernel::raise(UnhundledThreadedSignal)
  end
end

end

class Sig1 < StandardError; end
class Sig2 < StandardError; end

child = fork do # sandbox
trap(“HUP”){ exit }
tg = ThreadGroup.new
for i in 0…9
Thread.start(i) do |n|
ct = Thread.current
tg.add(ct)

    case n
    when 1
      loop do
        begin
          ct.raise_by_signal("USR1", Sig1, "USR1 signaled")
          STDERR.print("\r#{n} ")
          sleep rand
        rescue Sig1 => e
          STDERR.printf("\r%s\n", [n, e].inspect)
        end
      end
    when 2
      loop do
        begin
          ct.raise_by_signal("USR2", Sig2, "USR2 signaled")
          STDERR.print("\r#{n} ")
          sleep rand
        rescue Sig2 => e
          STDERR.printf("\r%s\n", [n, e].inspect)
        end
      end
    else
      loop do
        STDERR.print("\r#{n} ")
        sleep rand
      end
    end
  end
end
tg.list.each{|i| i.join}

end

parent

sleep 1 # waiting setup of child
begin
5.times do
Process.kill(“USR1”, child)
sleep(rand*2)
Process.kill(“USR2”, child)
end
ensure
Process.kill(“HUP”, child)
Process.wait
end
#------------------------------------------------------------------------ end

···

At Tue, 23 Jul 2002 03:25:10 +0900, Mike Hall wrote:

Summary: do a couple file-controls, setup a signal handler,
wait for a signal to occur.

This works OK in a single threaded script,
but it makes all the threads stop, when I use it
inside a thread.