How to use signals in C++ and How they react? - c++

I am trying to learn all interactions about signals and I discovered a funny interaction in it I can't understand.
Here's an abstract of the program, Im instructed to do execvp with grandchild, while child needs to wait for grandchild to finish. It runs correctly when without any signal interactions.
void say_Hi(int num) { printf("Finished\n"); }
int main() {
int i = 2;
char *command1[] = {"sleep", "5", NULL};
char *command2[] = {"sleep", "10", NULL};
signal(SIGCHLD, SIG_IGN);
signal(SIGUSR1, say_Hi);
while(i > 0) {
pid_t pid = fork();
if (pid == 0) {
pid_t pidChild = fork();
if (pidChild == 0) {
if (i == 2) {
execvp(command1[0], command1);
} else {
execvp(command2[0], command2);
}
} else if (pidChild > 0) {
waitpid(pidChild, 0, 0);
// kill(pid, SIGUSR1);
printf("pid finished: %d\n", pidChild);
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
} else {
//parent immediately goes to next loop
i--;
}
}
cin >> i; //just for me to pause and observate answers above
return 0;
}
As shown above, kill(pid, SIGUSR1); is commented, the program runs correctly.
Output:
pid finished: 638532 //after 5 sec
pid finished: 638533 //after 10 sec
However, when it is uncommented. Output becomes:
Finished
pid finished: 638610 //after 5 sec
Finished
Finished
Finished
Finished
pid finished: 638611 //after 5 sec too, why?
Finished
I would like to ask:
The whole program finished at once after 5 secs and a total of 6 "Finished" is printed out. Why is so?
Is there a way for me to modify it so that say_Hi function run in a total of two times only, in a correct time interval?
Please forgive me if my code looks stupid or bulky, I'm a newbie in programming. Any Comments about my code and help are appreciated!

void say_Hi(int num) { printf("Finished\n"); }
printf cannot be called in a signal handler. None of the C or the C++ library functions (with few exceptions) can be called in the signal handler. You can't even allocate or delete any memory from a signal handler (using either the C or the C++ library), except by using low-level OS calls like brk() or sbrk(). This is because of a very simple reason: that none of the C or the C++ library functions are signal-safe (with very few exceptions). Only function calls that are explicitly designated as "signal-safe" can be called from a signal handler. None of the C or C++ library functions or classes (with few exceptions) are signal-safe. The End.
The only thing that can be called from a signal handler are low-level operating system calls, like read() and write(), that operate directly on file handles. They are, by definition, signal-safe.
For this simple reason the shown code, when it comes to signals, is undefined behavior. Trying to analyze or figure out your programs behavior, from that respect, such as why or why not you see this message, is completely pointless. It cannot be logically analyzed. This is undefined behavior.

Answer:
kill(getpid(), SIG_USR1);

Related

terminate called without an active exception when calling pthread_exit in segmentation fault handler

How are you?
I am going to fix the segmentation fault in a worker thread on Ubuntu 18.04.
My code is the following.
#include <thread>
#include <signal.h>
#include <string.h>
#include <pthread.h>
#include <opencv2/opencv.hpp>
void sigsegv_handler(int signum, siginfo_t *info, void *data)
{
printf("The thread was crashed\n");
pthread_exit(NULL);
}
void sleep_ms(int milliseconds)
{
#ifdef WIN32
Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
#else
usleep(milliseconds * 1000);
#endif
}
void thread_func(int i)
{
if(i == 3)
{
int *p = 0;
*p = 10;
}
printf("A new thread ran successfully\n");
}
int main()
{
/* Set SIGSEGV handler. */
struct sigaction handler;
sigemptyset(&handler.sa_mask);
handler.sa_sigaction = &sigsegv_handler;
handler.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &handler, NULL) == -1)
fprintf(stderr, "Cannot set SIGSEGV handler: %s.\n", strerror(errno));
int i = 0;
while(1)
{
std::thread writer_thread(thread_func, i);
writer_thread.detach();
sleep_ms(1000);
printf("%d\n", i++);
}
return 0;
}
The code works well.
The output of this code are following.
A new thread ran successfully
0
A new thread ran successfully
1
A new thread ran successfully
2
The thread was crashed
3
A new thread ran successfully
4
A new thread ran successfully
5
A new thread ran successfully
6
A new thread ran successfully
7
But if I change the function "thread_func" as the following, the program is crashed.
void thread_func(int i)
{
if(i == 3)
{
int *p = 0;
*p = 10;
}
cv::Mat img(100, 100, CV_8UC3); // newly inserted
cv::resize(img, img, cv::Size(200, 200)); //newly inserted
printf("A new thread ran successfully\n");
}
The error messages are the following.
A new thread ran successfully
0
A new thread ran successfully
1
A new thread ran successfully
2
The thread was crashed
terminate called without an active exception
Aborted (core dumped)
Of course, I am sure there is no issue in OpenCV module.
Could u help me to fix this issue?
Thanks
The simple answer is you can't do this:
void sigsegv_handler(int signum, siginfo_t *info, void *data)
{
printf("The thread was crashed\n");
pthread_exit(NULL);
}
First, per 7.1.4 Use of library functions, paragraph 4 of the C 11 standard:
The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration.
Or, as summarized by footnote 188:
Thus, a signal handler cannot, in general, call standard library functions.
So, absent specific guarantees from your platform about what functions you can safely call from a signal handler, you can not make any function calls from within a signal handler.
But since you are calling pthread_exit(), assuming you're using a POSIX system, POSIX does provide some guarantees about what functions you can call, termed "async-signal-safe, at https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03. The Linux-specific list can be found at https://man7.org/linux/man-pages/man7/signal-safety.7.html
Note that neither printf() nor pthread_exit() are on either list.
Calling printf() from within a SIGSEGV signal handler is going to be dangerous - most implementations of printf() will use some form of malloc()/free(), and SIGSEGV is often a result of a malloc()/new/free()/delete operation encountering that corrupted heap. Heap operations tend to happen under a lock of some sort to protect against simultaneous modification of heap state, so calling printf() in a SIGSEGV handler of all things creates a huge deadlock risk.
And pthread_exit() will also cause huge problems - it's not only trying to change process state in the process's address space, it's trying to make changes to the process state in kernel space. From within a signal handler, that's simply not going to work.

I want to restart my program after the few seconds what I set

In present, I try to make a watchdog for my project.
Also, I want to make a restart timer.
I mean if the few seconds pass, the program will start from first.
Surely, I can use while loop in main function. I don't want this.
I just want to make some class such as a timer or watchdog,
After the main function passes the time I set, I want to let my program start again.
Is there any good idea?
int main(void)
{
Timer timer(5) // setting my timer to 5 secs
//If time takes over the 5 secs in this loop,
//I want to restart the main loop.
while(1)
{
//Do Something...
}
return 0;
}
If you can get your code to keep an eye on the clock and voluntarily return after so-many-seconds have elapsed, that's usually the best way; however, since you mentioned a watchdog, it sounds like you don't want to trust your code to do that, so (assuming you have an OS that supports fork()) you can spawn a child process to run the code, and then the parent process can unilaterally kill() the child process after 5 seconds and then launch a new one. Here's an example, with a child process counting a random number of potatoes, one per second; if it tries to count more than 5 of them, it will be killed by the parent process.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
// The code you want to be able to abort and restart would go in here
static void FunctionThatMightTakeALongTime()
{
srand(time(NULL)); // just so we get different random values each time
const int countTo = (rand()%12)+1;
for (int i=0; i<countTo; i++)
{
printf("%i potato... (out of %i)\n", i+1, countTo);
sleep(1);
}
}
int main(int argc, char ** argv)
{
while(1)
{
pid_t pid = fork();
if (pid == -1)
{
perror("fork"); // fork() failed!?
return 10;
}
else if (pid == 0)
{
// We're in the child process -- do the thing
printf("Starting child process...\n");
FunctionThatMightTakeALongTime();
printf("Child process completed!\n");
return 0;
}
else
{
// We're in the parent/watchdog process -- wait
// 5 seconds, and then if the child process is
// still running, send it a SIGKILL signal to kill it.
// (if OTOH it has already exited, the SIGKILL isn't
// required but it won't do any harm either)
sleep(5);
printf("Watchdog: killing child process now\n");
if (kill(pid, SIGKILL) != 0) perror("kill");
// Now call waitpid() to pick up the child process's
// return code (otherwise he'll stick around as a zombie process)
if (waitpid(pid, NULL, 0) == -1) perror("waitpid");
}
}
}
Note: If your OS doesn't support fork() (i.e. your OS is Windows), this technique is still possible, but it requires the use of Windows-specific APIs and is significantly more work to implement.

fork() and exec() Two Child Processes

I am calling fork() twice to create two child processes. I want child process A to do an exec() call and child process B to also do an exec() call. The problem I am having with the given code is that after the first exec() from child process A, the next fork() does not seem to occur and the program exits. I think that it has to do with how exec() overlays the parent process. What I want to accomplish is to call exec() from each of the child processes created by fork().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
int main() {
pid_t cpid_a, cpid_b;
cpid_a = fork();
if(cpid_a < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
cpid_b = fork();
if(cpid_b < 0) {
std::cout << "Fork failed." << '\n';
return 1;
}
else if(cpid_b == 0) { // code for child process B
execlp("/bin/ls", "ls", NULL);
}
}
else { // code for parent process
while(wait(NULL) != -1);
}
return 0;
}
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
If this calls succeeds, the following statement, and nothing that follows will ever be executed. That's how exec() works. The immediately-following fork() never occurs. That's simply how exec() works. If exec() succeeds, it never returns. The replacement process gets executed in its place.
You even added the 100% correct comment, above: "code for child process A". Everything inside the if() statement is "code for child process A", and gets executed when fork() returns 0.
You also correctly stated that you want the parent process to fork a second process. Well, you need to have that code obviously get executed by the parent process, and not the child process:
else if(cpid_a == 0) { // code for child process A
execlp("/bin/ls", "ls", NULL);
exit(1);
} else {
cpid_b = fork();
// The rest of the code.
Now, the parent process goes ahead and fork() a second time, proceeded on the rest of your plan.
P.S. The exit() is just for a good measure. The only time exec() returns is when exec() fails to execute the given process. Highly unlikely, in the case of /bin/ls; if it's missing you have bigger problems to worry about. Still, that's the technically correct thing to do, since continuing execution at that point will result in complete chaos. Again, if /bin/ls is missing that's going to be the least of the problems, but this can also happen if, say, the system ran out of memory and can't execute it for that reason; in which case there's no need to add fuel to the fire; but rather have the process die anyway.

C++ Timed Process

I'm trying to set up some test software for code that is already written (that I cannot change). The issue I'm having is that it is getting hung up on certain calls, so I want to try to implement something that will kill the process if it does not complete in x seconds.
The two methods I've tried to solve this problem were to use fork or pthread, both haven't worked for me so far though. I'm not sure why pthread didn't work, I'm assuming it's because the static call I used to set up the thread had some issues with the memory needed to run the function I was calling (I continually got a segfault while the function I was testing was running). Fork worked initially, but on the second time I would fork a process, it wouldn't be able to check to see if the child had finished or not.
In terms of semi-pseudo code, this is what I've written
test_runner()
{
bool result;
testClass* myTestClass = new testClass();
pid_t pID = fork();
if(pID == 0) //Child
{
myTestClass->test_function(); //function in question being tested
}
else if(pID > 0) //Parent
{
int status;
sleep(5);
if(waitpid(0,&status,WNOHANG) == 0)
{
kill(pID,SIGKILL); //If child hasn't finished, kill process and fail test
result = false;
}
else
result = true;
}
}
This method worked for the initial test, but then when I would go to test a second function, the if(waitpid(0,&status,WNOHANG) == 0) would return that the child had finished, even when it had not.
The pthread method looked along these lines
bool result;
test_runner()
{
long thread = 1;
pthread_t* thread_handle = (pthread_t*) malloc (sizeof(pthread_t));
pthread_create(&thread_handle[thread], NULL, &funcTest, (void *)&thread); //Begin class that tests function in question
sleep(10);
if(pthread_cancel(thread_handle[thread] == 0))
//Child process got stuck, deal with accordingly
else
//Child process did not get stuck, deal with accordingly
}
static void* funcTest(void*)
{
result = false;
testClass* myTestClass = new testClass();
result = myTestClass->test_function();
}
Obviously there is a little more going on than what I've shown, I just wanted to put the general idea down. I guess what I'm looking for is if there is a better way to go about handling a problem like this, or maybe if someone sees any blatant issues with what I'm trying to do (I'm relatively new to C++). Like I mentioned, I'm not allowed to go into the code that I'm setting up the test software for, which prevents me from putting signal handlers in the function I'm testing. I can only call the function, and then deal with it from there.
If c++11 is legit you could utilize future with wait_for for this purpose.
For example (live demo):
std::future<int> future = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::future_status status = future.wait_for(std::chrono::seconds(5));
if (status == std::future_status::timeout) {
std::cout << "Timeout" <<endl ;
} else{
cout << "Success" <<endl ;
} // will print Success
std::future<int> future2 = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::future_status status2 = future2.wait_for(std::chrono::seconds(1));
if (status2 == std::future_status::timeout) {
std::cout << "Timeout" <<endl ;
} else{
cout << "Success" <<endl ;
} // will print Timeout
Another thing:
As per the documentation using waitpid with 0 :
meaning wait for any child process whose process group ID is equal to
that of the calling process.
Avoid using pthread_cancel it's probably not a good idea.

waitpid/wexitstatus returning 0 instead of correct return code

I have the helper function below, used to execute a command and get the return value on posix systems. I used to use popen, but it is impossible to get the return code of an application with popen if it runs and exits before popen/pclose gets a chance to do its work.
The following helper function creates a process fork, uses execvp to run the desired external process, and then the parent uses waitpid to get the return code. I'm seeing odd cases where it's refusing to run.
When called with wait = true, waitpid should return the exit code of the application no matter what. However, I'm seeing stdout output that specifies the return code should be non-zero, yet the return code is zero. Testing the external process in a regular shell, then echoing $? returns non-zero, so it's not a problem w/ the external process not returning the right code. If it's of any help, the external process being run is mount(8) (yes, I know I can use mount(2) but that's besides the point).
I apologize in advance for a code dump. Most of it is debugging/logging:
inline int ForkAndRun(const std::string &command, const std::vector<std::string> &args, bool wait = false, std::string *output = NULL)
{
std::string debug;
std::vector<char*> argv;
for(size_t i = 0; i < args.size(); ++i)
{
argv.push_back(const_cast<char*>(args[i].c_str()));
debug += "\"";
debug += args[i];
debug += "\" ";
}
argv.push_back((char*)NULL);
neosmart::logger.Debug("Executing %s", debug.c_str());
int pipefd[2];
if (pipe(pipefd) != 0)
{
neosmart::logger.Error("Failed to create pipe descriptor when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
pid_t pid = fork();
if (pid == 0)
{
close(pipefd[STDIN_FILENO]); //child isn't going to be reading
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
if (execvp(command.c_str(), &argv[0]) != 0)
{
exit(EXIT_FAILURE);
}
return 0;
}
else if (pid < 0)
{
neosmart::logger.Error("Failed to fork when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
else
{
close(pipefd[STDOUT_FILENO]);
int exitCode = 0;
if (wait)
{
waitpid(pid, &exitCode, wait ? __WALL : (WNOHANG | WUNTRACED));
std::string result;
char buffer[128];
ssize_t bytesRead;
while ((bytesRead = read(pipefd[STDIN_FILENO], buffer, sizeof(buffer)-1)) != 0)
{
buffer[bytesRead] = '\0';
result += buffer;
}
if (wait)
{
if ((WIFEXITED(exitCode)) == 0)
{
neosmart::logger.Error("Failed to run command %s", debug.c_str());
neosmart::logger.Info("Output:\n%s", result.c_str());
}
else
{
neosmart::logger.Debug("Output:\n%s", result.c_str());
exitCode = WEXITSTATUS(exitCode);
if (exitCode != 0)
{
neosmart::logger.Info("Return code %d", (exitCode));
}
}
}
if (output)
{
result.swap(*output);
}
}
close(pipefd[STDIN_FILENO]);
return exitCode;
}
}
Note that the command is run OK with the correct parameters, the function proceeds without any problems, and WIFEXITED returns TRUE. However, WEXITSTATUS returns 0, when it should be returning something else.
Probably isn't your main issue, but I think I see a small problem. In your child process, you have...
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO); //but wait, this pipe is closed!
But I think what you want is:
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd for both, can close
I don't have much experience with forks and pipes in Linux, but I did write a similar function pretty recently. You can take a look at the code to compare, if you'd like. I know that my function works.
execAndRedirect.cpp
I'm using the mongoose library, and grepping my code for SIGCHLD revealed that using mg_start from mongoose results in setting SIGCHLD to SIG_IGN.
From the waitpid man page, on Linux a SIGCHLD set to SIG_IGN will not create a zombie process, so waitpid will fail if the process has already successfully run and exited - but will run OK if it hasn't yet. This was the cause of the sporadic failure of my code.
Simply re-setting SIGCHLD after calling mg_start to a void function that does absolutely nothing was enough to keep the zombie records from being immediately erased.
Per #Geoff_Montee's advice, there was a bug in my redirect of STDERR, but this was not responsible for the problem as execvp does not store the return value in STDERR or even STDOUT, but rather in the kernel object associated with the parent process (the zombie record).
#jilles' warning about non-contiguity of vector in C++ does not apply for C++03 and up (only valid for C++98, though in practice, most C++98 compilers did use contiguous storage, anyway) and was not related to this issue. However, the advice on reading from the pipe before blocking and checking the output of waitpid is spot-on.
I've found that pclose does NOT block and wait for the process to end, contrary to the documentation (this is on CentOS 6). I've found that I need to call pclose and then call waitpid(pid,&status,0); to get the true return value.