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?
Related
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 am writing a shell for an assignment in C. My only problem now is that when I call an external program with execvp() and then close is using CTRL + C, any further commands that I send are printed after the prompt not before it. I made an dummy program that is just an infinite loop to test this.
So after closing this program if I try and run a program that doesn't exist, it will print out
MINISHELL (cwd) $: and then a blank line
and then it will print my error message saying that I have entered a program that does not exist and then it will not print a prompt since it already has. So It ends with an empty new line and it appears that the program has not ended but it actually has.
It ONLY does this after I have closed a non terminating program with CTRL + C. Otherwise it works fine executing programs. Am I not using close() somewhere to close a file descriptor? I am not sure. Any help is appreciated. Thank you.
#include "minishell.h"
void intHandler(int sig)
{
my_char('\n');
}
int main(int argc, char **argv)
{
int n;
int pid = 0;
char* s = (char*)malloc(256*sizeof(char));
char cwd[1024];
char** input;
while (1)
{
signal(SIGINT, intHandler);
my_str("MINISHELL:");
if (getcwd(cwd, sizeof(cwd)) != NULL)
my_str(cwd);
else
{
my_str("Error in current directory");
return -1;
}
my_str(" $: ");
n = read(0, s, 256);
s[n] = '\0';
if (n > 1)
{
input = my_str2vect(s);
if (my_strcmp(input[0], "cd") == 0)
{
/*CHANGE DIRECTORY*/
if (input[1] != '\0')
{
if (chdir(input[1]) < 0)
my_str("MINISHELL: Error in path. Make sure the directory exists.\n");
}
else
my_str("MINISHELL: Error. No directory specified.\n");
}
else if (my_strcmp(input[0], "help") == 0)
{
/*HELP*/
my_str("\nMINISHELL COMMANDS:\n\ncd *directory\nChanges the current working directory to *directory\n\nexit\nExits the minishell\n\nhelp\nPrints a help message listing the built in commands\n\n");
}
else if (my_strcmp(input[0], "exit") == 0)
{
/*EXIT*/
my_str("Thank you for using MINISHELL\n");
exit(0);
}
else if (input[0] != NULL)
{
/*EXECUTE AN EXTERNAL PROGRAM*/
if ((pid = fork()) < 0)
my_str("MINISHELL: Error forking\n");
else if (pid > 0)
{
wait(NULL);
}
else
{
if (execvp(input[0], input) < 0)
{
my_str("MINISHELL: Error. Program does not exist in current directory.\n");
}
else
{
exit(0);
close(0);
}
}
}
else
{
my_str("MINISHELL: Error reading command. Type help to see available commands.");
}
}
}
return 0;
}
You cannot expect that the error message will always print before your prompt. The forked process is running in parallel with your main program. The order in which the output to stdout from the two programs occur is dependent upon how the OS scheduler runs the processes.
I think most real shells like bash actually do the check for the file existing in the main process before doing the fork(). Alternatively you could use pipe() and manually redirect the output. Then you can enforce flushing the entire contents before doing your prompt.
this is my code. Please have a look. Can you explain the process flow? it is actually a past paper question. But, I frankly don't understand the concept of fork system calls.
main()
{
int i = 1;
int ret_val= 0;
while(i <= 5)
{
fork();
if(ret_val == 0) /*child code*/
{
printf("in child %d. \n", i);
exit(0);
}
else
{ /*parent code*/
i = i+1;
}
}
}
First of all, in the core image of your program, you initialise two values, ret_val, and i which acts as a counter.
From there on, for 5 times, you fork() the program, creating another process with the same image (code). At this point I am assuming your code is wrong, because you are using the ret_val variable to check if it's the child or parent process, but to do so, you need to assign it the value from fork() like this:
ret_val = fork();
if (ret_val == 0)
// do something as child
else
// parent code here
In essence, your code, for 5 times, increments the value of i and has each child process display the current value of i.
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.
I'm supposed to implement a signal handler which stops all the threads in the program the first time a certain signal is called, and resume them if they are already stopped. I implemented a demon thread running in the background using the following code:
void *handle_sig(void *arg)
{
sigset_t set;
//set set...
struct timespec to;
to.tv_sec = 1;
to.tv_nsec = 0;
while (_keepListening) {
int ret = sigtimedwait(&set, NULL, &to);
if (ret < 0)
if (errno == EAGAIN) {
continue; /* no signal sent*/
} else {
fprintf(stderr, "Failed...\n");
exit(1);
}
if (_state == PAUSE_STATE) { /* was blocked*/
//do something
} else {
` //do something else
}
}
return NULL;
}
The problem is that if a signal is sent and detected, and then another is sent before the while loop is entered again - the second signal is ignored, which can leave the program paused forever. is there a way of detecting if a signal was sent since the last call to sigtimedwait?
Thank you
You might think about making your processing asynchronous.
For example by starting a thread for "doing something" or "doing something else".