I am trying to understand how signal handlers attach to a process and their scope for a process.
class Main
Signal.trap('USR1') do
Process2.kill
end
def main_process
#do something
p = Process2.new
output = p.give_output
#then again do something
end
end
class Process2
Signal.trap('USR1') do
Process2.kill
end
def self.kill
if ##static_object.blank?
#do nothing
else
#do something
end
end
def give_output
#do something
##static_object = true
#do something
end
end
Now if I issue a SIGUSR1 to the process while give_output is getting executed and ##static_object is not nil, the handler should behave as expected. However, even after give_output has finished execution, if a signal is sent, the handler inside Process2 will catch it. From what I understand, the handler gets attached to the process. Can we have two signal handlers for the same process for the same signal? For example - while give_output is executing and a signal is issued, the handler inside Process2 should get control otherwise another signal handler defined in Main should get control.
I was curious about this myself and came across the following resources: http://timuruski.net/blog/2014/signals-traps-and-rescues/, https://www.ruby-forum.com/topic/87221, and http://www.ibm.com/developerworks/library/l-reent/. That second link has some resources which seem very relevant to your question.
In short, you can only reliably trap one interrupt type per process. Signal interrupts are handled by the host OS. As its name suggests, interrupts halt the normal execution of your program until the interrupt is handled.
Summarizing the information given in the links posted by #Anthony E. Using signal trap it's not possible to trap a signal from multiple places in your code. If you want to handle signals differently at multiple places, use rescue blocks.
Signal Trap -
Signal.trap("USR1") do
#do something
end
Rescue Interrupt -
begin
#some functions
rescue Interrupt
#handle the exception
exit
end
Difference in the way signals are handled by rescue and trap -
Trap defines the handler at the top of the code, if a signal is triggered, it would be caught by the trap. On the other hand, rescue is defined at the bottom of the code, that is when there is no trap available, it will raise a Signal Exception which will be caught by the rescue block
The signal trap code gets associated with the process and cannot be replaced. If one wants to handle signals at different places of the program in a different way, the best way is to raise an exception and handle it
Related
I have a flag that activates in one process and I would like that a concurret process respond to this activation.
send_data is a bit signal:
signal send_data:std_logic:='0';
process
begin
wait until send_data='1';
...
end
process(enumer)
begin
...
send_data<='1';
...
end process;
Generally:
You can write a Signal in one process and read it in multiple other processes.
For your application:
You can set send_data to '1' whilst waiting for it in another process, then set a signal like send_flag_encountered to '1', then reset send_data in the first process and then reset the send_flag_encountered in the second process.
This is even synthesizable. When doing this, I would recommend you to use FSMs.
I am trying to do signal handling for my CLI app. I would like to avoid the self-pipe "trick", but also consider that using a per thread list of signals that is periodically polled is not the best idea. Hence, my idea was to use Queue to block until a new signal arrives. Here is my attempt:
class CLI
def initialize
#manager = Thread.new { sleep }
#signal_queue = Queue.new
setup_signal_handlers
end
def run
loop do
signal = #signal_queue.pop # This doesn't unblock!
handle_signal(signal)
end
rescue Interrupt
exit
end
private
def handle_signal(signal)
case signal
when 'INT'
raise Interrupt
end
end
def setup_signal_handlers
%w(INT).each do |signal|
trap signal do
#signal_queue.push signal # This works. #signal_queue.size is incremented
end
end
end
end
# Run with CLI.new.run and hit ctrl^C
where I've simplified #manager for clarity. The problem is that, even if the signal is trapped and pushed to #signal_queue, the blocking call #signal_queue.pop doesn't pick it up. What am I missing here?
It looks like you're experiencing Ruby bug #12405: Queue doesn't work inside of trap. Luckily this bug got fixed in Ruby versions 2.2.7, 2.3.4, and 2.4.1 (2.5.0 already includes that fix); therefore your code behaves as expected after upgrading to a more recent Ruby version.
Looking for a way to wait for the completion of all child processes, I found this code:
while true
p "waiting for child processes"
begin
exited_pid = Process.waitpid(-1,Process::WNOHANG)
if exited_pid and exited_pid > 0 then
p "Process exited : #{exited_pid} with status #{$?.exitstatus }"
end
sleep 5
rescue SystemCallError
puts "All children collected!"
break
end
end
This looks like it works in a similar way to Unix-systems process management, as I read on tutorialspoint HERE.
So in summary, it looks like this code:
Calls Process.waitpid, for any child process that exists. If no child process has exited, continue anyway.
If a child process has exited, then notify the user. Otherwise sleep, and check again.
When all child processes have exited an error is thrown, which is caught and the user is notified that processes are complete.
But looking at a similar question on waiting for child processes in C (Make parent wait for all child processes), which has as an answer:
POSIX defines a function: wait(NULL);. It's shorthand for waitpid(-1,
NULL, 0);, which will block until all children processes exit.
I tested that Process.wait() in Ruby achieves pretty much the same thing as the more verbose code above.
What is the benefit of the more verbose code above? Or, which is considered a better approach to waiting for child processes? It seems in the verbose code that I would be able to wait for specific processes and listen for specific exit codes. But if I don't need to do this is there any benefit?
Also, regarding the more verbose code:
Why does the call to Process.waitpid() throw an error if there are no more child processes?
If more than 1 child process exists within the 5 second sleep period, it seems like there is a queue of completed processes and that Process.waitpid just returns the top member of the queue. What is actually happening here?
In Linux when an executing thread calling 'sleep' suspends its execution. As soon as a signal is sent to the process the 'sleep' function returns immediately. I can install my signal handler and set the flag below properly to exit the while loop.
// a signal handler set 'flag' on CTRL-C
while(flag) {
sleep(10); // returns on signal caught
}
In Windows I cannot see that. I am using 'Sleep(DWORD milliseconds)' and I have installed my signal handler using 'signal' function. Essentially the sleeping threads resumes only at the end of 'Sleep'.
What do I have to do to allow 'Sleep' to return before hand in my code?
Am I using the right approach (using a flag to exit the while loop) or do I have to look at something else?
You should be using an event object.
Replace your loop with a call to WaitForSingleObject, and have the control-C handler call SetEvent.
(Of course, in practice it is unlikely that you really want your program to sit and wait, doing nothing, until the user presses control-C. But that's the scenario the question presents, and this answer gives you a starting point for more realistic scenarios.)
I want to know how trap("INT") is different from rescue Interrupt in ruby. In what circumstances one has to use trap("INT") and in what circumstances one has to use rescue Interrupt.
Also, I have used trap("INT") in my code, but when I call kill -2 , the trap handler is not getting called.
Trap is more like a GOTO jump.
If you rescue Interrupt, you still have your local scope + variables and can do some cleanup for that particular block.