SIG_IGN fails to ignore SIGINT signal - c++

I have a main process and some child process spawn from it. At a point of time i have to give SIGINT signal to all the child process but not to main process. I am unable to store pid's for all child processes. So i used SIG_IGN for ignoring SIGINT in main process and set to default after my action. But it is not working.
Please find my code snippet below:
/* Find group id for process */
nPgid = getpgid(parentPID);
/* Ignore SIGINT signal in parent process */
if (signal(SIGINT, SIG_IGN) == SIG_ERR)
{
cout << "Error in ignoring signal \n");
}
/* Send SIGINT signal to all process in the group */
nReturnValue = kill ( (-1 * nPgid), SIGINT);
if (nReturnValue == RETURN_SUCCESS)
{
cout << "Sent SIGINT signal to all process in group successfully \n";
}
else
{
cout << "Alert!!! Unable to send SIGINT signal to all process in the group \n";
}
/* Set SIGINT signal status to default */
signal (SIGINT, SIG_DFL);
sleep(2);
I am not getting any error. But parent is getting killed. Am i doing anything wrong here?

nPgid = getpgid(parentPID);
What is parentPID? The get the group of the calling process either pass 0 or the result of getpid().
From man getpgid():
getpgid() returns the PGID of the process specified by pid. If pid
is zero, the process ID of the calling process is used. (Retrieving
the PGID of a process other than the caller is rarely necessary, and
the POSIX.1 getpgrp() is preferred for that task.)
From this text above I'd draw the conclusion to do
nPgid = getpgid(o);

Related

Trying to ignore SIGTERM failed under Linux, process still exited

I met one issue of signal handling under Linux, my target is to let process ignore SIGTERM signal. But sometimes, process still exited, the probability of this issue will be 1/60.
Fake code of my application:
static int g_count_sig_old = 0;
static volatile int g_count_sig = 0;
void _signalhandler(){
g_count_sig ++;
printf(...); // Maybe not safe, just for debugging
myTrace(...); // Write log to file1 is not signal safe, but just for debugging.
}
main(){
sigaction(...) // Register signal handler for SIGTERM
while(1){
sleep(1000); // wait one second
myNewTrace(...); // Output value of g_count_sig to file2
if( g_count_sig != g_count_sig_old ) {
g_count_sig_old = g_count_sig;
printf(...); // output value of g_count_sig
myNewTrace(...); // Output value of g_count_sig to file2
}
}
}
I suppose this application will not quit when receiving signal SIGTERM, but actual testing result didn't match my design. Some times, the process still exit after receiving signal SIGTERM. And I confirm the process received SIGTERM signal when issue occurred, I can observe console output and trace file.
So I feel puzzled, why does this application exit even if ignoring SIGTERM? I am not sure how to position the cause of this issue, or it is reasonable symptom under Linux.
Hope to get your help. Thanks!

Linux - child reading from pipe receives debug messages sent to standard output

I'm trying to create a parent and a child processes that would communicate through a pipe.
I've setup the child to listen to its parent through a pipe, with a read command running in a while loop.
In order to debug my program I print debug messages to the standard output (note that my read command is set to the pipe with a file descriptor different than 0 or 1).
From some reason these debug messages are being received in the read command of my child process. I can't understand why this is happening. What could be causing this? What elegant solution do I have to solve it (apart from writing to the standard error instead of output)?
This code causes an endless loop because of the cout message that just triggers another read. Why? Notice that the child process exists upon receiving a CHILD_EXIT_CODE signal from parent.
int myPipe[2]
pipe(myPipe);
if(fork() == 0)
{
int readPipe = myPipe[0];
while(true)
{
size_t nBytes = read(readPipe, readBuffer, sizeof(readBuffer));
std::cout << readBuffer << "\n";
int newPosition = atoi(readBuffer);
if(newPosition == CHILD_EXIT_CODE)
{
exit(0);
}
}
}
Edit: Code creating the pipe and fork
I do not know what is doing your parent process (you did not post your code), but because of your description it seems like your parent and child processes are sharing the same stdout stream (the child inherits copies of the parent's set of open file descriptors; see man fork)
I guess, what you should do is to attach stdout and stderr streams in your parent process to the write side of your pipes (you need one more pipe for the stderr stream)
This is what I would try if I were in your situation (in my opinion you are missing dup2):
pid_t pid; /*Child or parent PID.*/
int out[2], err[2]; /*Store pipes file descriptors. Write ends attached to the stdout*/
/*and stderr streams.*/
// Init value as error.
out[0] = out[1] = err[0] = err[1] = -1;
/*Creating pipes, they will be attached to the stderr and stdout streams*/
if (pipe(out) < 0 || pipe(err) < 0) {
/* Error: you should log it */
exit (EXIT_FAILURE);
}
if ((pid=fork()) == -1) {
/* Error: you should log it */
exit (EXIT_FAILURE);
}
if (pid != 0) {
/*Parent process*/
/*Attach stderr and stdout streams to your pipes (their write end)*/
if ((dup2(out[1], 1) < 0) || (dup2(err[1], 2) < 0)) {
/* Error: you should log it */
/* The child is going to be an orphan process you should kill it before calling exit.*/
exit (EXIT_FAILURE);
}
/*WHATEVER YOU DO WITH YOUR PARENT PROCESS*/
/* The child is going to be an orphan process you should kill it before calling exit.*/
exit(EXIT_SUCCESS);
}
else {
/*Child process*/
}
You should not forget a couple of things:
wait or waitpid to release associated memory to child process when it dies. wait or waitpid must be called from parent process.
If you use wait or waitpid you might have to think about blocking SIGCHLD before calling fork and in that case you should unblock SIGCHLD in your child process right after fork, at the beginning of your child process code (A child created via fork(2) inherits a copy of its parent's signal mask; see sigprocmask).
.
Something that many times is forgotten. Be aware of EINTR error. dup2, waitpid/wait, read and many others are affected by this error.
If your parent process dies before your child process you should try to kill the child process if you do not want it to become an orphan one.
Take a look at _exit. Perhaps you should use it in your child process instead of exit.

How to make sure that `waitpid(-1, &stat, WNOHANG)` collect all children processes

Extracted from Unix Network Programming Vol1 Third Edition Section 5.10 wait and waitpid functions
#include "unp.h"
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) {
printf("child %d terminated\n", pid);
}
return;
}
...
// in server code
Signal(SIGCHLD, sig_chld); // used to prevent any zombies from being left around
...
..
// in client code
The client establishes five connection with the server and then immediately exit
...
Reference waitpid:
Return Value
waitpid(): on success, returns the process ID of the child whose state
has changed; if WNOHANG was specified and one or more child(ren)
specified by pid exist, but have not yet changed state, then 0 is
returned. On error, -1 is returned.
Based on the above document, waitpid will return 0 if at the moment no child process has terminated. If I understood correctly, this will cause the function sig_chld break from the while statement.
Question> Thus how can we guarantee that this signal handler can make sure all terminated children processes are collected?
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) {
printf("child %d terminated\n", pid);
You wouldn't be in the signal handler if you didn't have a child to handle. The loop is because while you are in the handler itself a 2nd or 3rd child could have changed or terminated sending SIGCHLDs that would not be queued. Thus the loop actually prevents you from missing those possible dead children. It will return 0 or error out with a -1 (ECHILD) when there are no more children to be reaped at the moment.

Zombie process and fork

i have a code like this...
c = fork();
if(c==0) {
close(fd[READ]);
if (dup2(fd[WRITE],STDOUT_FILENO) != -1)
execlp("ssh", "ssh", host, "ls" , NULL);
_exit(1);
}
close(fd[WRITE]);
fd[READ] and fd[WRITE] are pipe file descriptors.
when i run it continuously, there are a lot of zombie processes when i use ps ax. How to rectify this? Is this because i am not using the parent to wait for the exit status of the child process...
If you have no intention to wait for your child processes, set the SIGCHLD handler to SIG_IGN to have the kernel automatically reap your children, eg.
signal(SIGCHLD, SIG_IGN);
Yes, the parent must wait for the child return status. You can do it asynchronously by catching SIGCHILD in the parent process and then call waitpid in the capture method.
Yes, waitpid() should be called from parent. waitpid() will clean-up any child process of the parent process, which is currently in terminated state.
You can add below code to your program :
if(c>0)
{
while(1){
ret = waitpid(-1,&status,0);
if(ret>0){
if(WIFEXITED(status)){
if(WEXITSTATUS(status) == 0){
printf("child process terminated normally and successfully\n");
}
else{
printf("child process terminated normally and unsuccessfully\n");
}
}
else{
printf("child process terminated abnormally and unsuccessfully\n");
}
}
if(ret<0) {
break;
}
}
}
FYI : more on waitpid.
First parameter is set to -1 such that waitpid() will clean-up any child process of this parent process, which is currently in terminated state.The first parameter can also be +ve - in this case, waitpid() will cleanup only the specific child process.Most common use is to set first parameter to -1 also refer to manual page of waitpid().
Second parameter is used to extract the termination/exit status code of the child process - waitpid() system call API fills the status field when the system call API is invoked.
Last field is the flags field - currently unused - in most cases, flags field will be set to 0 - meaning, default behaviour of the system call API !!! if you really need to use flags, refer to manual page of waitpid().
Note:
In the code you submitted, _exit(1) will be called iff execlp() fails. so you can put a condition for execlp() fail and that condition _exit() can be called. The Reason is, execlp() functions only return if an error has occurred.
Modified code can be like below :
c = fork();
if(c==0) {
close(fd[READ]);
if (dup2(fd[WRITE],STDOUT_FILENO) != -1)
ret_execlp = execlp("ssh", "ssh", host, "ls" , NULL);
if(ret_execlp == -1 ) {
printf("execlp is failed");
_exit(1);
}
}
close(fd[WRITE]);
I appreciate the above 2 answers. Wish this answer may give more clarity. Thank you.

Spawned child exits with state = 127

I use posix_spawnp to execute different processes and I check the status (with waitpid) to make sure the child was created properly
int iRet = posix_spawnp(&iPID, zPath, NULL, NULL, argv, environ);
if (iRet != 0)
{
return false;
}
int iState;
waitpid(static_cast<pid_t>(iPID), &iState, WNOHANG);
cout << "Wait: PID " << iPID << " | State " << iState << endl;
if (WIFEXITED(iState)) {
printf("Child exited with RC=%d\n",WEXITSTATUS(iState));
}
else if (WIFSIGNALED(iState)) {
printf("Child exited via signal %d\n",WTERMSIG(iState));
}
else
{
printf("Child is NORMAL");
}
At first this executes properly and I get the following message:
Wait: PID 15911 | State 0 Child exited
with RC=0
After executing the same process several times, the child process starts to exit with status 127.
Wait: PID 15947 | State 32512 Child
exited with RC=127
After this happens, I could not get the child to spawn again. I enclosed the section of code given above in a for loop but it wouldn't spawn properly.
If I restart the parent process, it works for a while but the same problem crops up again after a while.
What am I doing wrong here?
Check this link.
For example:
EINVAL The value specified by file_actions or attrp is invalid.
The error codes for the posix_spawn and posix_spawnp subroutines are affected by the following conditions:
If this error occurs after the calling process successfully returns from the posix_spawn or posix_spawnp function, the child process might exit with exit status 127.
It looks as if it might exit with 127 for a whole host of reasons.
Check the return code from waitpid() to be sure that it isn't having problems.
The way the code reads suggests that you are only spawning one child process at a time (otherwise there'd be no need to call waitpid() within the loop). However in that case I wouldn't expect to use WNOHANG.