i want to try to program a small shell on my own, because it is a nice way to learn signals.
But somehow i have some problems to suspend a process and also continue it later.
execute_command() should be the interesting part, because before i'm only splitting the inputted information.
void execute_command(){
int status = 0;
pid_t childprocess= fork();
int wait_state=0;
if(arg_list[0] == NULL){
exit(0);
}
if(childprocess <0 ){
printf(" Could not create childprocess");
}else if (childprocess == 0){
int end_state =execvp(*arg_list,arg_list);
if(end_state < 0){
printf("Some kind of Error happens here \n");
}else if(end_state == 0){
// printf("Program exited with %d\n",end_state);
}
exit(0);
}else{
current_process_id = childprocess;
register_signals();
last_pid = getpid();
/*When i have found a '&' */
if(!background_process){
do{
waitpid(childprocess,&status,WUNTRACED);
if( WIFSTOPPED(status) ) {
// later for conitinuing the suspended process
last_pid = childprocess;
kill(last_pid,SIGSTOP); // edited line of code !
}
}while( !WIFEXITED(status) && !WIFSIGNALED(status));
}
}
}
void register_signals(){
signal(SIGINT,signal_int_handler);
signal(SIGTSTP,signal_stop_handler);
}
mysignal.c:
void signal_int_handler(int signum){
printf("[caught SIGINT]\n");
}
void signal_kill_handler(int signum){
}
void signal_stop_handler(int signum){
printf("[caught SIGTSTP]\n");
}
When i press "Ctrl+z" the signal_action execute and print the message from the command signal_stop_handler.
But the program is still running in the do-while-loop.
Maybe i have misunderstood something.
My test input is : sleep 50
I only want to suspend a process and also continue it later.
Can someone give me a hint?
Edit: i have edit the code, depend on the answer, but it doesn't works
If you catch SIGTSTP in your program, it won't be suspended. Suspend is its default behavior and it goes away once a custom handler is installed. There is also SIGTSTOP which can't be diverted and suspends the process in all cases.
Related
I asked quesiton, before this. And Thanks to help from others, I made sample code that runs bc command continuously until I enter '1'.
In this code, I use tcsetpgrp() to give child the control of terminal.
When I run the code, bc command works well. However, when I enter 'quit', child process receives SIGSTP and code is ended. (What I want is continuing while loop!!)
int main()
{
while(1){
int n;
scanf("%d", &n);
execute();
if (n == 1)
break;
}
}
void execute()
{
char *args[] = {"bc", 0};
pid_t pid = fork();
if (pid == 0){
execvp("bc", args);
}
if (pid > 0){
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, getpgid(pid);
wait(0);
}
}
I think that I should change child to background and parent to foreground after execvp. However, after execvp function, child process terminates, so it seems possible to do that.
So, I also added
signal(SIGSTP, handler);
where handler function is
void handler(int sig){
tcsetpgrp(STDIN_FILENO, getpgid(getppid()));
exit(0);
}
However, handler function does not executed when I enter 'quit' while bc command is executed.
So, now, I don't know how to solve it. I really want to handle this problem. Please help me..
In my main program, I have the following code
while(flag == 0)
;
and I have
void sigint_handler(int sig)
{
count = 1;
return;
}
So I am just setting a global flag to 1 when the user presses ctrl+c. However, this does not work for some reason. I then changed my main program to
while(flag == 0)
sleep(1);
and this does work. This is rather strange. Could someone help me understand what is going on here and why it did not work initially?
Ok so I wrote this tiny program in order to test how tcsetpgrp behaves and in general handling signals, now I've seen a few posts here asking about tcsetpgrp but for some reason the solutions in those posts are not working for me.
int main() {
signal(SIGINT,sig_handler);
static char line[4096];
int line_num = 0;
pid_t id = fork();
if(id == 0 )
{
while (fgets(line, 4096, stdin)) {
printf("\nyou wrote something");
}
}
else
{
int pgid_child = id;
printf("child group : %d", pgid_child);
signal(SIGTTOU, SIG_IGN);
tcsetpgrp(0, pgid_child);
wait(NULL);
}
return 1;
}
what I expect to happen:
the terminal will ask for input as long as the user continues to write into it, but if the user presses ctrl+c then the program will end.
what actually happens:
as soon as the child process is set to foreground group the SIGTTOU is called to all other processes and the parent process also stops, even though I've asked to ignore that signal.
does anyone know why is this happening?
I have written a program where I have created a child process. Both the parent process and child process do calculation in two parts- parent_part1 , parent_part2 and child_part1, child_part2.
My aim is to run the (parent_part1,child_part1,parent_part2 ,child_part2) sequence for let us say 5 times. For this purpose I have used while(var_child++<10) and while(var_par++<10) and successfully achieved it.
Now, I will define ONE SUCCESSFUL calculation is execution of (parent_part1,child_part1,parent_part2 ,child_part2) sequence for 5 times and display the final correct value.
I want to find such 100 SUCCESSFUL calculation and for the same purpose I have used OUTER loop (i.e., while(t1++<100) ), but I am not getting the SUCCESSFUL calculation for 100 times , sometimes I got 40 SUCCESSFUL result, and hanged after parent_part1 or parent_part2 or child_part1 or child_part2 etc. and some other times I got 20 or 95 SUCCESSFUL result, and hanged after parent_part1 or parent_part2 or child_part1 or child_part2 etc.
What is the reason and how to overcome this ?
Thank you in advance . The program is as below.
#include<stdio.h>
#include<signal.h>
int flagp=0,flagc=0,var_child=0,var_par=0;
void write_child()
{
if(flagc==0)
{
/* do some computation here*/
printf("Child_part1 \n");
flagc=1;
}
else
{
/* do some computation here*/
flagc=0;
printf("Child_part2 \n");
}
}
void write_parent()
{
if(flagp==0)
{
/* do some computation here*/
printf("Parent_part1 \n");
flagp=1;
}
else
{
/* do some computation here*/
printf("Parent_part2 \n");
flagp=0;
}
}
int main(int ac, char **av)
{
printf("Starting...\n");
int t1=0;
pid_t childpid = fork();
printf("childpid=%d,getppid()=%d \n",childpid,getppid());
while(t1++<100)
{
var_child=0;
var_par=0;
if ( childpid == 0 )
{
// child process
printf("\n\nt1=%d ",t1);
while(var_child++<10)
{
kill(getppid(), SIGCONT); //sending singal to parent
signal(SIGCONT, write_child);
pause();
}
}
else
{
//parent process
printf("\n\nt1=%d ",t1);
while(var_par++<10)
{
kill(childpid, SIGCONT); //sending singal to child
signal(SIGCONT, write_parent);
pause();
}
} // end of else
}
return 0;
}
Are you sure this logic is correct?
while(var_par++<10)
Apart from that, you are not catching the signal from the parent process. you are creating a lot of zombie processes when the child terminates and by killing the parent from child, you are creating orphans. Both will take system resources and might hit the upper limit on consecutive executions. Try catching the signal and see how it behaves.
I'm writing a shell which forks, with the parent reading the input and the child process parsing and executing it with execvp.
pseudocode of main method:
do{
pid = fork();
print pid;
if (p<0) { error; exit; }
if (p>0) { wait for child to finish; read input; }
else { call function to parse input; exit; }
}while condition
return;
what happens is that i never seem to enter the child process (pid printed is always positive, i never enter the else). however, if i don't call the parse function and just have else exit, i do correctly enter parent and child alternatingly.
full code:
int main(int argc, char *argv[]){
char input[500];
pid_t p;
int firstrun = 1;
do{
p = fork();
printf("PID: %d", p);
if (p < 0) {printf("Error forking"); exit(-1);}
if (p > 0){
wait(NULL);
firstrun = 0;
printf("\n> ");
bzero(input, 500);
fflush(stdout);
read(0, input, 499);
input[strlen(input)-1] = '\0';
}
else exit(0);
else { if (parse(input) != 0 && firstrun != 1) { printf("Error parsing"); exit(-1); } exit(0); }
}while(strcmp(input, "exit") != 0);
return 0;
}
EDIT:
-that else exit(0) just something i forgot there from playing around
-adding a newlines to the prints shows that it does in fact correctly fork and enter the child process; thank you, the problem seems to be in the parse
One culprit is else exit(0);
That would execute in the child shell, which means it never gets to the parsing stage. The code is also syntactically invalid because after that you have another else.
`if (p >= 0) {
if (p == 0) {/* chile process */}
else if (p > 0) {/* parent process */}
} else {
/* handle the error returned by fork() */
}`
I'd do it like the above pseudo code.
else exit(0); is what the child process is doing in your code.
Your core is a tad messy with all the nested if's and else's. There are some dangling else statements as well (else exit(0);). I'd start by cleaning those up. I can't see any other logical problems with your code. It's simple enough.
Swap the lines
else exit(0);
and
else { if (parse(input) != 0 && firstrun != 1) { printf("Error parsing"); exit(-1); } exit(0); }
Apart from everything everybody else has said about the fact that the else's are a complete mess, there are some other issues you will hit when you have fixed them.
In the child, the input array will be garbage on the first run because you don't put anything in it before forking.
It seems completely pointless to fork at all since you are not exec'ing anything in the child but you are waiting for the child to finish in the parent. Why not just call parse from the parent?