I am writing on a UNIX shell.
When CTRL-C is pressed, the SIGINT signal is sent. (Is working!)
But when CTRL-Z is pressed, the process which gets the signal is stopped, but I cannot return to my shell. Only if I close the process, i can return.
Here is my signal_handler():
// in the main()
signal(SIGINT, signal_handler);
signal(SIGTSTP, signal_handler);
// when pid == 0, right over execvp()
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
// signal handler
void signal_handler(int signum) {
switch(signum) {
case SIGINT:
cout << "[caught SIGINT]" << endl;
kill(pid, SIGINT);
break;
case SIGTSTP:
cout << "[caught SIGTSTP]" << endl;
kill(pid, SIGTSTP);
break;
default:
break;
}
}
pid_t pid; // is a global variable
// this would be my main()
if((pid = fork()) < 0) {
cout << "Error" << endl;
exit(1);
} else if(pid == 0) { // child
setpgid(0,0);
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
execvp(arguments[0], &arguments[0]);
cout << "Argument not found" << endl;
exit(1);
} else if(checkIfBackground(inputNew) == false) { // mother
int status;
pid_t pid_r;
if(waitpid(pid, &status, 0) < 0) {
cout << "Error" << endl;
}
} else {
cout << "Process is in background" << endl;
}
You'll need to check the status of your children to see when they've stopped with the UNTRACED flag:
pid_t child = waitpid(-1, &status, WUNTRACED | WCONTINUED);
if (WIFSTOPPED(status))
... the child has stopped
else if (WIFCONTINUED(status))
... the child has been continued
else if (WIFEXITED(status))
... the child has exited with exit
else if (WIFSIGNALLED(status))
... the child exited with a signal
Note that if you don't care about switches to running status (the WIFCONTINUED case), you don't need the WCONTINUED flag.
Related
I'm trying to create a program where a parent process does some computation and sends it over to the child process, The child process forks another process and does some more computation and sends it over to the child2 process for further processing.
I can't seem to figure out how to do this.
My Output is all messed up, sometimes child 2 runs before child 1. sometimes child 1 is finished last.
I want the other processes to wait for them.
This is i think how the code should look like
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[])
{
int fd[6];
pipe(fd);
pipe(fd + 2);
pipe(fd + 4);
pid_t id = fork();
if (id == -1)
return 1;
if (id == 0)
{
wait(NULL);
pid_t id2 = fork();
if (id2 == -1)
return 2;
if (id2 == 0)
{
wait(NULL);
pid_t id3 = fork();
if (id3 == -1)
return 2;
if (id3 == 0)
{
wait(NULL);
cout << "Child 3" << endl;
// Read data from pipe and display
}
else
{
cout << "Child 2" << endl;
// Read Data from pipe and Display
// Some Computation
for (int i = 0; i < 10000; i++)
{
}
// Send Data to Child 3 through pipe
wait(NULL);
}
}
else
{
cout << "Child 1" << endl;
// Read Data from pipe
// Some Computation
for (int i = 0; i < 100000000; i++)
{
}
// Send Data to Child 2 through pipe
wait(NULL);
}
}
else
{
cout << "Parent" << endl;
// Some Computation
for (int i = 0; i < 2000; i++)
{
}
// Send Data to Child 1 through pipe
wait(NULL);
}
}
The wait call returns as soon as any child in the same process group terminates (thus including any grandchildren).
When you want to wait for a specific process, use waitpid instead. You should also check the exit code and the status.
Finally, you should wait for the child to exit after interacting with it via the pipe, not before, and you should not wait before starting the child.
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
void die(const char* msg) {
perror(msg);
exit(1);
}
int main(int argc, char* argv[]) {
int fd[6];
pipe(fd);
pipe(fd + 2);
pipe(fd + 4);
pid_t id = fork();
if (id == -1)
die("fork");
if (id == 0) {
pid_t id2 = fork();
if (id2 == -1)
die("fork 2");
if (id2 == 0) {
pid_t id3 = fork();
if (id3 == -1)
die("fork 3");
if (id3 == 0) {
cout << "Child 3" << endl;
// Read data from pipe and display
// Done. Nothing to wait for - just exit child 3
cout << "Child 3 exiting" << endl;
} else {
cout << "Child 2" << endl;
// Read Data from pipe and Display
// Some Computation
// Send Data to Child 3 through pipe
// Wait for child 3 to finish before exiting child 2
if (waitpid(id3, NULL, 0) < 0)
die("waitpid 3");
cout << "Child 2 exiting" << endl;
}
} else {
cout << "Child 1" << endl;
// Read Data from pipe
// Some Computation
// Send Data to Child 2 through pipe
// Wait for child 2 to finish before exiting child 1
if (waitpid(id2, NULL, 0) < 0)
die("waitpid 2");
cout << "Child 1 exiting" << endl;
}
} else {
cout << "Parent" << endl;
// Some Computation
// Send Data to Child 1 through pipe
// Wait for child 1 to finish before exiting parent
if (waitpid(id, NULL, 0) < 0)
die("waitpid 1");
cout << "Parent exiting" << endl;
}
}
Prints:
Parent
Child 1
Child 3
Child 2
Child 3 exiting
Child 2 exiting
Child 1 exiting
Parent exiting
Note that Child 1/2/3 are printed in random order - that's because all children run in parallel, which is perfectly normal (we want the processes to run in parallel, it's the whole point of forking). The ordering will be enforced when reading/writing the pipes - the child reading from a pipe will wait until the data arrives.
I have some questions regarding the use of SIGINT and SIGTSTP in relation to managing processes in my own unix shell. But first of the code here:
void execute(vector<char *> argvv, bool x){
pid_t pid;
int status;
int error;
pid = fork();
a = pid;
argvv.push_back(NULL);
if(pid == -1){
cout << "error" << endl;
}else if(pid == 0){
error = execvp(argvv[0],argvv.data());
if(error == -1){
exit(-1);
}
// In Child Process
}else{
// If no "&", then wait for process
if(x == false){
if(wait(&status) != pid){
perror("wait()");
}
}else{
cout << "Pid des Hintergrundprozesses: " << pid << endl;
}
// in parent process
}
}
This function just receives the entered operation and parameters, forks a new process and executes it.
Now my signalhandler functions:
void signalHandlerSigInt(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGINT);
cout << "Killed Process: " << a << endl;
}
void signalHandlerSigTStp(int signum){
cout << "Interrupt Signal (" << signum <<") received." << endl;
kill(a,SIGTSTP);
cout << "Stop process..: " << a << endl;
}
and my main.cpp:
int main(int agc, char** argv) {
bool opBackground;
string operation;
vector<string> arguments;
vector<char *> argvv(arguments.size() + 1);
signal(SIGINT, signalHandlerSigInt);
signal(SIGTSTP, signalHandlerSigTStp);
while(true){
cout << "myshell>";
getline(cin,operation);
if(operation == "logout"){
logout();
}else{
opBackground = befehlUebersetzen(operation, &arguments);
vector<char *> argvv(arguments.size() + 1);
for(size_t i = 0; i != arguments.size(); ++i){
argvv[i] = &arguments[i][0];
}
execute(argvv, opBackground);
arguments.clear();
}
}
return 0;
}
The shell itself works fine, I now need to extend it to be able to kill the foreground process by pressing CTRL+C or stop the process with CTRL+Z.
I think I understood what a Signalhandler does, but is kill(a,SIGINT) the right way to transmit the signal SIGINT to my process? ("a" is a global variable for my forked pid, that means the last process I forked).
My problem is, when starting a process in the background and then start another process in the foreground it kills both processes when pressing CTRL+C.
Also the SIGTSTP signalhandler doesnt seem to work at all (does nothing - process just keeps running in the foreground).
Am I completely wrong with what im doing?
I have an assignment where I have to write a subshell in C++. Essentially, I am forking (if the input is not jobs or exit) and in the child process, I am calling exec to run the command. It needs to run alongside the parent process, so for example if I call sleep 100, the program should immediately be ready to run the next command since the parent is not "waiting" for it since I am using WNOHANG. However, my issue is when I need to track the actual state- if sleep is still running, I want to be able to get that the command is still running, but I am unable to do so. It always shows up as exited, when I use the various macros. I have no idea how to approach this differently and would appreciate some guidance.
(i didn't include the declarations of the variables since the editor on this website was messing it up for some reason)
do{
cout << "# ";
getline(cin, input);
if (input == "jobs")
{
cout << "Process ID | State | Command " << endl;
cout << "-----------+--------------+-----------------------------------------------" << endl;
//jobs stuff goes here, need to print pids, states, and commands
if(counter == 0)
{
cout << " [NO PROCESSES] " << endl;
}
else
{
for(i = 0; i < counter; i++)
{
cout << pidArray[i] << " ";
cout << statusArray[i] << " ";
cout << cmdArray[i] << endl;
}
}
}
else
{
cmdArray[i] = input;
i++;
counter++;
pid = fork();
if( pid == 0)
{
execl("/bin/sh", "sh", "-c", input.c_str(), (char *)0);
//break;
}
else if (pid == -1)
{
break;
}
else
{
pidArray[i-1] = pid;
//int rc = waitid(P_PID, pid, NULL, WNOHANG);
// int rc =waitpid(pid, &status, WNOHANG | WNOWAIT );
//exitChecker = waitpid(pid, &status, WNOHANG);
usleep(100000);
if (WIFEXITED(status))
{
cout << "terminated" << endl;
}
else
{
cout << "running" << endl;
}
}
}
}while(input != "exit");
return 0;
}
Thanks in advance.
I am writting an OpevCV program,a multi-thread program,one of threads should receive alarm signal.It's a little complicated.To show where the problem is,i wrote the test code,like below:
MainThread:
int main(int argc,char **argv)
{
cout << "main thread = " << pthread_self() << endl;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_BLOCK, &set, NULL);
struct sigaction sa;
sa.sa_handler = int_handler;
sa.sa_flags |= SA_INTERRUPT;
sigaction(SIGALRM,&sa,NULL);
pthread_t thread;
if(pthread_create(&thread, NULL, capturePictures, NULL) < 0)
{
cerr << "pthread_create error" << endl;
return -1;
}
alarm(5);
pthread_join(thread, NULL);
return 0;
}
ChildThread:
void *capturePictures(void* arg)
{
cout << "capturePictures thread = " << pthread_self() << endl;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
string rtsp = "rtsp://admin:admin12345#192.168.0.81:554/h264/cha1/main/av_stream";
VideoCapture vcap;
if(!vcap.open(rtsp)) {
cout << "open stream error" << endl;
return (void *)-1;
}
unsigned int picIndex = 0;
int index = 0;
Mat image;
while(1){
if (!vcap.read(image)){
cout <<"read image error" << endl;
return (void*)-1;
}
if (picIndex++ % 25 != 0) continue;
char fileName[30];
sprintf(fileName,"pictures/%d.jpg",++index);
imwrite(fileName, image);
}
}
int_handler:
void int_handler(int signum)
{
cout << "int_handler = " << pthread_self() << endl;
}
This test code doesn't mean anthing,just want to show you where the problem is.
The output is like this:
main thread = 140334223800320
capturePictures thread = 140333923575552
int_handler = 140333931968256
int_handler isn't called in main thread nor capturePictures thread(child thread),i don't even know which thread's id is 140333931968256,i just create one child thread...
If i want to achieve my goal,how can i do?
What this code should do is: there are parent.cpp and child.cpp. Parent will send whatever is in the buffer to child and child will send back whatever received to parent. I do not know what I am doing wrong. I am confused what is missing in the parent and what else I should include into the child.
//parent.cpp
//Check for fork error
if ( (pid = fork()) < 0 )
{
cerr << "FORK ERROR" << endl;
return -3;
}
else if (pid == 0) // Child
{
close(fd1[1]);//Close parent's stdout-write
close(fd2[0]);//Close child's stdin-read
if (fd1[0] != STDIN_FILENO)//Make sure file desc. matches
{
if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO)
{
cerr << "dup2 error to stdin" << endl;
}
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO)//Make sure file desc. mathces
{
if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO)
{
cerr << "dup2 error to stdout" << endl;
}
close(fd2[1]);
}
if ( execl("./child", "child", (char *)0) < 0 )
{
cerr << "system error" << endl;
return -4;
}
return 0;
}//end of child
else //parent
{
int rv;
close(fd1[0]);//Close parent's read
close(fd2[1]);//close child's write
if ( write(fd1[1], buffer, strlen(buffer)) != strlen(buffer))
{
cerr << "Write ERROR FROM PIPE" << endl;
}
if ( (rv = read(fd2[0], buffer, MAXLINE)) < 0 )
{
cerr << "READ ERROR FROM PIPE" << endl;
}
else if (rv == 0)
{
cerr << "Child Closed Pipe" << endl;
return 0;
}
cout << "Output of child is: " << buffer;
return 0;
}//end of parent
//child.cpp
char line[1000];
int MAXLEN=1001;
read(STDIN_FILENO, line, MAXLEN);
My guess is that your processes are blocked. You write a small amount of data to the child, which the child processes. The child produces no output, however, but is waiting for more data. The parent is now waiting for the child to give it some data, and the child is waiting for the parent, and you have a classic deadlock. Try closing fd1[1] after the write in the parent, and before the read. The child will realize there is no more data and will produce output prior to terminating.