Do objects gets destroyed properly with kill? - c++

In the following, the child process creates the object. It uses signal to kill itself after certain period of time:
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class Wut{
public:
Wut(){cout<<"obj being created" << endl;}
~Wut(){cout<<"obj being destroyeed" << endl;}
};
void alarmHandler(){
cout << "Alarm! Forcing child to kill itself" << endl;
kill(getpid(), SIGKILL);
}
int main(int argc, char* argv[]){
int status;
pid_t pid;
if((pid = fork()) == 0){
Wut hi;
signal(SIGALRM, (sighandler_t)alarmHandler);
alarm(1);
alarm(7);
sleep(10);
cout << "this will not get printed" << endl;
} else {
wait(&status);
cout << "Parent dies" << endl;
}
sleep(10);
return 0;
}
But I am not sure if the object it creates gets destroyed properly because it never calls the destructor.

The KILL signal is actually not sent to the process; it's a signal for the operating system to forcibly stop the program execution. That means that destructors will not be called.
Use a signal like SIGTERM to see the expected behaviour:
kill(getpid(), SIGTERM);

Unix processes can't handle SIGKILL in any way. Your process is dead as a doornail, immediately. If you want a graceful exit, look into SIGTERM. You can then register a handler to do whatever cleanup you need.
You can use the handler to put your program into a state where it exits normally (e.g. by setting a flag or such), allowing the destructors to run.

SIGKILL is (in most cases) the same as kill -9, so all of the memory allocated to that process is reclaimed by the operating system.

Related

How can I resume a stopped process?

Following this documentation, I am testing how to stop and resume a process. I have basic code to test as follows:
#include <iostream>
#include <csignal>
#include <unistd.h>
int main() {
std::cout << "Hello" << std::endl;
int pid = getpid();
kill(pid, SIGSTOP);
kill(pid, SIGCONT);
std::cout << "Bye" << std::endl;
return 0;
}
The output is:
Hello
It stops the process, but it never resumes it. How should I fix it?
A solution, if a bit complicated, is to create a child process to start and stop the parent. Here is a small code example, that might help:
#include <iostream>
#include <csignal>
#include <unistd.h>
int pid; //Include declaration outside so it transfers to the child process
int main() {
std::cout << "Hello" << std::endl;
pid = getpid();
int returned_pid = fork(); //Duplicate process into 2 identical processes
if(returned_pid) {
// If it is the parent process, then fork returns the child process pid
// This is executed by the parent process
usleep(1000); // Sleep a millisecond to allow for the stop command to run
} else {
// If fork returns 0, then it is the child process
// The else is executed by the child process
kill(pid, SIGSTOP); // Stop parent process
usleep(3000000); // Delay 3 seconds
kill(pid, SIGCONT); // Resume parent process
}
if(returned_pid) { // Only print if parent process
std::cout << "Bye" << std::endl;
}
return 0;
}
Clarification: The fork command returns 2 different values in the 2 processes: 0 in the child, and the pid of the child process in the parent.
Other note: When running this in a terminal, it will look weird, as the terminal may note that the process was stopped and give a new command line, but then the process resumes, so prints Bye over it. Just a note.

C++ killing child thread stops execution of the main thread

I am completely confused with timers and how threads (pthread) work in C++
Timers arent timers but clocks and you cant (I at least cant) kill a thread without killing main thread.
What I need - a bit of code which executes once in 24hrs on a separate thread.
However if the app needs to stop it - I cant do anything but send SIGKILL to it (because join will wait till midnight). Once I kill that thread the app (main thread) seems to kill itself also.
I am open to suggestions.
On condition - I cannot use std::threads and I dont want to wake this thread more than once a day
But easiest for me would be to kill a child thread without stopping execution of the main thread (why this is the case anyway??)
Here is the sample:
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <thread>
#include <pthread.h>
#include <signal.h>
using namespace std;
void* Logger(void* arg) {
int* thread_state = (int*)arg;
cout << "Logger started" << endl;
sleep(24 * 60 * 60);
cout << "Logger thread exiting" << endl;
pthread_exit(0);
}
int main()
{
int thread_state = 0;
pthread_t logger_t;
int rc = pthread_create(&logger_t, NULL, Logger, (void*)&thread_state);
sleep(2);
//thread_state = 1;
pthread_kill(logger_t, SIGKILL);
cout << "i wuz here" << endl;
return 0;
}
output:
Logger started
Killed
I dont know how I missed it but if I call pthread_cancel instead of pthread_kill it works just fine.

Child process becomes Defunct after fork and exec

I am learning fork and exec and creating multiple child processes using fork and execlp and all I do in the child process is let it sleep. Basically I just want all my child to be alive. But as soon as i start my monitor.cpp which creates processes all of the child exit immediately and they do defunct!
Monitor which forks multiple children
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
for(size_t i=0; i<std::stoi(argv[1]) ; ++i)
{
int pid = fork();
if(pid == 0)
{
execlp("child", "child", std::string(std::to_string(i)).c_str(), (char *)0);
std::cout << "child exiting " << std::endl;
exit(1);
}
else if(pid > 0)
{
std::cout <<"child started with " << pid << std::endl;
}
else
{
std::cout << "fork failed" << std::endl;
}
}
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(100000));
}
return 0;
}
Child Code
#include <iostream>
#include <thread>
#include <chrono>
int main(int argc, char* argv[])
{
std::cout << " child started with id " << argv[1] << std::endl;
std::cout <<"child sleeping " << argv[1] << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1000));
std::cout << "child exiting " << argv[1] << std::endl;
return 0;
}
Output:
child started with 1834
child started with 1835
child exiting
child started with 1836
child exiting
child started with 1837
child started with 1838
child started with 1839
child exiting
child started with 1840
child started with 1841
child exiting
child started with 1842
child started with 1843
child exiting
child exiting
child exiting
child exiting
child exiting
child exiting
ps -ef shows all of my child processes as Defunct even though my parent is still alive.
Can you please explain what am I missing?
From the 'execlp' man page:
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
Since "child exiting" is being printed in two places, it's not obvious if it's exiting. You need to check it's return value and errno.
You need to reap the child-process as they exit. This is done using wait or waitpid calls.
Until the parent has done this, they will be visible as defunc / zombie processes. (init, process 1, is responsible for reaping all process that do not have a parent after they exit)

SIGTSTP signal not stopping child?

I'm trying to write a program that forks, the child executes a command and then returns control to the parent. I am having trouble getting the SIGTSTP (C-z) signal to work as intended, though... I want the parent to ignore it, but the child to stop and return control to the parent, so that the child can later be resumed or killed (with a builtin command). I isolated the relevant code into a smaller program just to test it, and it seems like A) the child doesn't stop when C-z is typed, or B) it does stop, but does not return control to the parent (I'm leaning towards this because when I use cat for stdin, it behaves differently after the C-z). Here is my code.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <signal.h>
int main(){
std::cout.setf(std::ios::unitbuf);
std::vector<std::string> vec; vec.push_back("cat");
std::vector<char*> chvec;
for(unsigned int i = 0; i < vec.size(); i++){
chvec.push_back(&vec[i][0]);
}
chvec.push_back(NULL);
vec.erase(vec.begin(), vec.begin() + chvec.size());
char** argv = &chvec[0];
signal(SIGTSTP,SIG_IGN);
pid_t pid;
if((pid = fork()) == 0){
signal(SIGTSTP,SIG_DFL);
/*pid = getpid();
setpgid(pid,pid);*/
std::cout << "before exec" << std::endl;
execvp(argv[0],argv);
perror("exec");
}
else{
//setpgid(pid,pid);
int status;
waitpid(pid,&status,0);
if(WIFEXITED(status) || WIFSIGNALED(status)){
std::cout << "exited or signaled" << std::endl;
}
if(WIFSTOPPED(status)){
std::cout << "process stopped" << std::endl;
}
//std::cout << "process exited" << std::endl;
pause();
}
return EXIT_SUCCESS;
}
It was already pointed out in the comments that you need to fix the undefined behavior as a result of the vec vector being erased. That's the first problem.
I see that your code is checking the exit status of a process using WIFSTOPPED.
Let's review the documentation for the wait(2) system call, and see what it says about this:
WIFSTOPPED(wstatus)
returns true if the child process was stopped by delivery of a
signal; this is possible only if the call was done using WUN‐
TRACED or when the child is being traced (see ptrace(2)).
So, with that information at hand, after fixing the previously mentioned undefined behavior, and after changing your waitpid() call to:
waitpid(pid,&status,WUNTRACED);
Then I was able to send a kill -TSTP <pid> message to the spawned cat process, and obtain the expected
process stopped
message from your test program.
P.S. By stracing the child process, I could see that the child process was receiving the TSTP signal, and stopping just fine. The issue was simply that the parent wasn't handling it, without the required option to waitpid().

C++ Process fork and sigalarm

The goal of this program is to fork and have the child sleep while parent loops infinitely waiting for an interrupt. When I hit ^C, it calls the void parent function. This part works however, the message from the kill ( pid, SIGALRM ) is not working. I checked and pid is the correct process ID for the child.
I've searched for awhile, but I haven't found what I'm doing wrong. I used the kill ( pid, SIGALRM ) before from the child process to the parent but I can't figure out why this isn't working..
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int pid;
void parent ( int sig )
{
kill ( pid, SIGALRM );
cout << "I'm a parent " << getpid() << " My child is " << pid << endl;
}
void child ( int sig )
{
cout << "I am " << getpid() << "my parent is " << getppid()<< endl;
cout << "Use ctrl+backslash to actually end the program" << endl;
}
int main()
{
pid = fork();
if(pid == 0)
{ //Child process
cout << "Child pid = " << getpid() << " Waiting for interrupt." << endl;
(void) signal ( SIGALRM, child );
pause();
}
else if(pid > 0)
{ //Parent
sleep(2);
cout << "child pid = " << pid << endl;
struct sigaction act;
act.sa_handler = parent;
sigemptyset ( &act.sa_mask);
sigaction (SIGINT, &act, 0);
while(1)
{
sleep ( 1 );
}
}
return 0;
}
Ok, so I figured out the problem.
When I was pressing ^C, it would catch the interrupt in the main process, but kill the child process. When I ran a system("ps") from inside the program, it showed the child a.out process to be defunct.
To fix this I added the following to the child's process:
struct sigaction act;
act.sa_handler = CHILD_PRESERVER;
sigemptyset ( &act.sa_mask);
sigaction (SIGINT, &act, 0);
Where CHILD PRESERVER was a dummy function that did nothing except keep it alive.
It doesn't see that this solution is very elegant, so if anyone has a more correct way of doing this please post it.
You can do the same thing as your sigaction solution by just using signal(SIGINT, SIG_IGN);
The thing that tripped you up initially (and often trips up new programmers dealing with ctrl-C and signals) is that ctrl-C sends a signal to AN ENTIRE PROCESS GROUP, rather than to a single process -- every process in the group will get the signal. The process group the signal is sent to is the foreground process group of the terminal.
So this gives you lots of ways of dealing with/controlling ctrl-C interrupts. You can have each process install its own SIGINT handler (as you have done). Or you can carefully manage your process groups, putting children into their own process group (which will generally not be the foreground process group), so they won't get the signal in the first place.
You manage process groups with the setpgrp(2)/setpgid(2) system call.