signal handling when process is waiting for another process to terminate - c++

I am just trying to understand the concept of signal handling with respective from kernel and user mode for the running process.
PROCESS-1 --------------------> PROCESS-3
(parent process) <-------------------
^ process-3 sending signals(SIGPIPE-for communication) or
|| SIGSTOP or SIGKILL to process-1
||
||
||process-1 waiting for child process-2
|| using waitpid command.
||
v
PROCESS-2(waiting for resource, page fault happened, etc)
(child process)
I want to know how kernel sends the signal from process-3 to process-1 knowing that process-1 is waiting for process-2 to finish. Would like to know more about the user and kernel communication during the signal handling scenario(PCB,resources,open file descriptors etc.). Please explain related to this context..
Any help given is thankful..!!!

The kernel doesn't really care that process-1 is "waiting for process-2 to finish" (in particular it's not interested in "why" it's in the state it is, merely that it is in some state: in this case, idling in the kernel waiting for some event). For typical1 caught signals, the signal-sender essentially just sets some bit(s) in the signal-receiver's process/thread state, and then if appropriate, schedules that process/thread to run so that it can see those bits. If the receiver is idling in the kernel waiting for some event, that's one of the "schedule to run" cases. (Other common situations include: the receiver is in STOP state, where it stays stopped except for SIGCONT signals; or, the receiver is running in user mode, where it is set up to transition to kernel mode so as to notice the pending signals.)
Both SIGKILL and SIGSTOP cannot be caught or ignored, so, no, you cannot provide a handler for these. (Normally processes are put into stop state via SIGTSTP, SIGTTIN, or SIGTTOU, all of which can be caught or ignored.)
If system calls are set to restart after a user signal handler returns (via the SA_RESTART flag of sigaction()), this is achieved by setting up the "return address" for the sigreturn() operation to, in fact, make the system call over again. That is, if process-1 is in waitpid(), the sequence of operations (from process-1's point of view) from the point of the initial waitpid(), through receiving a caught signal s, and back to more waiting, is:
system call: waitpid()
put self to sleep waiting for an event
awakened: check for awakening event
event is signal and signal is caught, so:
set new signal mask per sigaction() settings (see sigaction())
push signal frame on a stack (see SA_ONSTACK and sigaltstack())
set up for user code (program counter) to enter at "signal trampoline"
return to user code (into trampoline)
(At this point process-1 is back in user mode. The remaining steps are not numbered because I can't make SO start at 9. :-) )
call user handler routine (still on stack chosen above)
when user routine returns, execute sigreturn() system call,
using the frame stored at setup time, possibly modified
by user routine
(At this point the process enters kernel mode, to execute sigreturn() system call)
system call: sigreturn(): set signal mask specified by sigreturn() argument
set other registers, including stack pointer(s) and
program counter, as specified by sigreturn() arguments
return to user code
(the program is now back in user mode, with registers set up to enter waitpid)
system call: waitpid()
At this point the process returns to the same state it had before it received the caught signal: waitpid puts it to sleep waiting for an event (step 2). Once awakened (step 3), either the event it was waiting for has occurred (e.g., the process being waitpid()-ed is done) and it can return normally, or another caught signal has occurred and it should repeat this sequence, or it is being killed and it should clean up, or whatever.
This sequence is why some system calls (such as some read()-like system calls) will "return early" if interrupted by a signal: they've done something irreversible between the "first" entry into the kernel and the time the signal handler is to be run. In this case, the signal frame pushed at step 6 must not have a program-counter value that causes the entire system call to restart. If it did, the irreversible work done before the process went to sleep would be lost. So, it is instead set up to return to the instruction that detects a successful system call, with the register values set up to return the short read() count, or whatever.
When system calls are set up not to restart (SA_RESTART is not set), the signal frame pushed in step 6 is also different. Instead of returning to the instruction that executes the system call, it returns to the instruction that detects a failed system call, with the register values set up to indicate an EINTR error.
(Often, but not always, these are the same instruction, e.g., a conditional branch to test for success/fail. In my original SPARC port, I made them different instructions in most cases. Since leaf routines return to %o6+8 with no register or stack manipulation, I just set a bit indicating that a successful return should return to the leaf routine's return address. So most system calls were just "put syscall number and ret-on-success flag into %g1, then trap to kernel, then jump-to-error-handling because the system call must have failed if we got here.")
1Versus queued signals.

Related

Who sends and who reveive SIGTRAP in case of interupt 3?

In a debugging session, when the deugger wants to set a breakpoint, it replaces an instruction by int3. When the Target process reach this instruction, the process stops. I have read that a signal is send at this time. But i did not manage to capture this signal (i wrote my own mini debugger for testing). Who send this signal ? The kernel? And who is the receiver?
I had to put a wait() fonction juste after the ptrace_cont. Do you think this is this wait function that catch the signal in order to notify the debugger that the process reach a break point ?
When the Target process reach this instruction, the process stops.
That's not quite accurate. When the trap instruction (0xCC on x86) is executed, the processor notifies the OS. On UNIX, the OS checks to see whether the process is being ptraced by somebody.
If no, the SIGTRAP signal is delivered to the application, which usually results in process being killed (but you can catch and handle the signal in the application).
If there is a ptraceer (usually a debugger), then the signal is not delivered to the application. Instead, debugger's wait is unblocked to notify the debugger that the inferior has changed state. The debugger then looks at where the inferior process stopped, discovers that it did so because of a breakpoint, and handles the situation as appropriate (let's you examine the inferior, or resumes it if the breakpoint is conditional and current conditions don't match, etc.)

In Linux/C++, does a signal sent to a thread/process make it become active?

In Linux, when a signal is sent to a process/thread (for whatever reason), is the signal handler (assuming there is one, and the signal isn't blocked) called immediately?
I mean, I'm pretty sure that in the process/thread that handles the signal it will be called immediately, but I mean with respect to other processes/threads.
And if the handler is called immediately, will it also make the corresponding process/thread active (so that its normal execution continues immediatly)?
EDIT
As my original question seems to have been misunderstood, I'll try to explain again with an example.
Lets say in my computer I have a single CPU, and 2 processes running, process 'A' and process 'B'. And assume none of them is blocking in a system call (like sleep). Normally, I guess, the OS will switch between executing process 'A' and process 'B', after small periods of time (e.g. execute process 'A' for 100ms, then process 'B' for 100ms, then process A again for 100ms, etc.). Let's say process 'A' is now the active process (i.e. it's the one now occupying the CPU). Say now that process 'A' sends a signal to process 'B' (or, alternately, the OS sends this signal to process 'B', for whatever reason). Process 'B' has registered an handler for that signal, and is not blocking it. So the question is, will the OS now immediately stop executing process 'A' and switch to executing the signal handler of process 'B'? And if the answer is yes, will it afterwards immediately continue executing process 'B' (The normal code, not the signal handler), or switch back to executing process 'A', and only after some small period of time resume with executing process 'B'?
And then the same questions can be asked about threads rather than processes.
No, signals are delivered on context switch only. Upto that time all signals will be queued. Among many signals of same type, usually Only one signal is delivered to the destination. So i am comfortable to sat that more signals destroyed than delivered.
I suggest you to consult chapter regarding any unix book book. My favorite is understanding linux kernel and linux kernel development.
if you still need techincal help please comment about it
There are two cases: when the signaled process is active, and when it is blocked.
For the former case, according to http://www.tldp.org/LDP/tlk/ipc/ipc.html, the process would handle the signal when it exits from a system call. This would mean that a normal instruction like a = b+c (or its equivalent machine code) would not be interrupted because of signal. Signal handling may also be delayed in a CPU-intensive process.
However, when the process is blocked, it depends on whether the kernel function being called is interruptible (e.g., wait_event_interruptible). If it is interruptible, the process will wake up, otherwise, it will not until it leaves the uninterruptible function (due to IRQ, for instance).
Yes, the handler will be called immediately.
Suppose I have a process coded as below.
#include <stdio.h>
#include <signal.h>
void handle_signal(int signal);
volatile int i = 1;
int main( )
{
struct sigaction sa;
// Setup the sighub handler
sa.sa_handler = &handle_signal;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
while(1)
{
if(i == 1)
{
printf("A");
}
}
return 0;
}
void handle_signal(int signal) {
/*
* Please note that printf et al. are NOT safe to use in signal handlers.
* Look for async safe functions.
*/
const char *signal_name;
sigset_t pending;
// Find out which signal we're handling
switch (signal) {
case SIGHUP:
signal_name = "SIGHUP";
break;
case SIGSTOP:
i = 0;
signal_name = "SIGSTOP";
break;
case SIGCONT:
signal_name = "SIGCONT";
i = 1;
break;
default:
fprintf(stderr, "Caught wrong signal: %d\n", signal);
return;
}
}
This prints A on shell all the time unless it receives SIGSTOP signal.
So, open the shell and do kill -STOP <pid of above process>
Verify that process is stopped, and then from the shell send the SIGCONT signal using kill -CONT <pid of above process>
And if the handler is called immediately, will it also make the corresponding process/thread active (so that its normal execution continues immediatly)
Your signal handler has its own context. So there is no thread which must be activated for handling your signal. But there are some issues which must be kept in mind. If your thread is waiting with some syscalls like sleep or read/write or any other blocking operation, this system call will be interrupted and the return value from that call give you the information, that your process ( not thread! ) has received a signal.This return value is EINTR. If your thread is simply running or sleeping without waiting on a system call, nothing else is happened! Simply the handler is invoked without any changes in scheduling your threads inside your process.

How to make the process ignore some signal(like SIGHUP,SIGABRT,SIGABORT,SIGINT etc..)

I am a newbie and have basic understanding of linux.
Whenever the kernel encounters a signal for a particular process, first it checks the signal handler table in the process control block(PCB) of the particular process. If the signal handler is registered it calls the function. if the flag is SIG_DEFAULT then it calls the signal handler registered in the global signal table of kernel. If the flag is SIG_IGNORE then kernel just ignores the signal for the particular process.
All signals have default signal handlers already registered in signal table by kernel.
I just want to know how a process can change the flag from SIG_DEFAULT TO SIG_IGNORE. Please explain the mechanism(either using system call or changes in the signal table or PCB). Next time when the signal is again captured what optimizations does the kernel do.
Call the signal function. Note that some signals may not be ultimately ignoreable.

What is SIG44 in gdb?

Sometimes when I am debugging I get message like this.
Program received signal SIG44, Real-time event 44.
What does it means?
Thank you.
EDIT :
Platform is linux
A signal is a message sent by the kernel to a process in order to notify the process that event of some kind has occurred in the system.
Usual signals on linux are for example SIGINT (value 2, interrupt from keyboard) or SIGKILL ( value 9, kill a program).
Signals are received either when the kernel detects a system event (like division by zero is SIGFPE, value 8) or when a process invokes the kill() function to explicitly tell the kernel to send a signal to a process (or to the process itself that called the kill() ).
A signal can often be caught by the process in order to do something.
So to answer to your question, the code is most likely calling the kill() function and sending it a signal with value 44 when something happens. Since you are getting that message, it means that the process has received the signal and is going to exit or do what is written in the code in case that signal comes.
Unlike standard signals, real-time
signals have no predefined meanings:
the entire set of real-time signals
can be used for application-defined
purposes. (Note, however, that the
LinuxThreads implementation uses the
first three real-time signals.)
Source for the quote here
The GNU C++ library uses SIG44 to awaken sleeping threads when signalling condition variables.

SIGALRM Timeout -- How does it affect existing operations?

I am currently using select() to act as a timer. I have network receive operations which occur within a loop, and every few seconds a processing operation needs to occur.
As a result, the select() statement's timeout constantly changes -- decreasing to zero over time and then restarting at 3.
rv = select(selectmonitor+1, &readnet, NULL, NULL, &helper.timeout());
As things come in on the network, the statement is repeated and the value passed to it by helper.timeout() decreases. Eventually, the value will either be equal to zero or the system will timeout, which will result in the processing function executing. However, I've noticed that this is quite resource intensive -- the value for helper.timeout() must be constantly calculated. When I am trying to receive a few thousand packets a second, the time it takes for this operation to be done results in packet loss.
My new idea is using SIGALRM to resolve this. This would allow me to set a timer once and then react when it is set off. However, I'm confused as to how it will affect my program. When SIGALRM 'goes off', it will run a function which I specify. However, how will it interrupt my existing code? And once the function is done, how will my existing code (within the while statement) resume?
Also, it would appear its impossible to set the SIGALRM signal to call a function within a class? Is this correct? I imagine I can call a function, which can in turn call a function within a class..
Thanks for any assistance ahead of time.
Use your SIGALRM handler to set a flag variable.
Use sigaction instead of signal to set your signal handler. Do not set the SA_RESTART flag. With SA_RESTART not set your select statement will be interrupted by the signal. Your select will return -1 and errno will be EINTR.
Since the signal might happen while your other code is executing you will want to check the flag variable too, probably right before going into the select.
I was just reminded that this pattern can result in missing the signal, if it happens just after checking the flag and just before entering the select.
To avoid that, you need to use sigprocmask to block the SIGALRM signal before entering the while loop. Then you use pselect instead of select. By giving pselect a signal mask with SIGALRM unmasked, the signal will end up always interrupting during the select instead of happening at any other time.