Unix signal function with fork() and exec() - c

I have a little problem with signal function.
My program in a brief:
void sigfunc(int sn)
{
if(sn == SIGINT)
printf("SIG TEXT!");
}
int main(void)
{
...
// spawn 10 children and execl my another programs
for (i = 0; i < 10; i++) {
pid = fork();
if (pid != 0) {
signal(SIGINT, sigfunc);
continue;
} else if (pid == 0) {
execl(pathtoprog[i], progname[i], NULL);
}
// wait for sig (only parent waits because programs from execl have their own while(1))
if(pid > 0)
while(1) {}
}
Problem is simple: when I press Ctrl+C I'll see SIG TEXT! but programs started by execl will crash/hang(I'm not sure, because they stop working but still exists in process monitor). How to write this sigfunc to react only for parent process and leave all children with execl alone?

Related

is possible to get the exit status from the child of a child process in the parent

I try to get the exit code from a child of a child process in the parent process.
If the process goes in the while loop to fork again i don't get the exit code.
I tried some options for waitpid like WNOHANG but then the program hangs.
Maybe what i wan't is not possible because it's some like a zombie child?
This is my code.
void parrent_process(t_token *token, t_info *info)
{
pid_t pid;
int wstatus;
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
child_process(token);
}
if (info->in)
close(info->in);
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus))
info->exit_code = WEXITSTATUS(wstatus);
}
void child_process(t_token *token)
{
t_token *cmd_token;
pid_t pid;
pid = 0;
cmd_token = token;
while (token->next && ((token->next)->type == GREAT))
{
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
redirect_output(token);
break;
}
token = token->next->next;
}
if (execve(cmd_token->path, cmd_token->args, cmd_token->envp) == -1)
{
print_error_msg(CMD_NOT_FOUND, "minishell", cmd_token->args[0]);
exit(127);
}
}
In most POSIX-like systems, the answer is "No — a process can only wait on its own children, those it created directly with fork()1".
However, on Linux, there is the prctl(2) system call. The option PR_SET_CHILD_SUBREAPER allows a process to wait for more distant descendants (grandchildren, great-grandchildren, …) too. However, if the direct parent of a process waits for it, the ancestral process will not get the exit status information.
1 Or posix_spawn()

How can I handle SIGSTOP with SIGCONT?

what i am trying to do is that when my program receives SIGSTOP, it should send SIGCONT to itself. if i do it on terminal, it works but i want to do it in my program. I tried something like this, but it doesn't work..
can you help me?
int main()
{
pid_t pid;
pid = fork();
if(pid > 0)
{
int i = 0;
while(1)
{
if(i == 5)
{
kill(getpid(), SIGSTOP);
}
printf("i = %d\n" ,i);
i++;
sleep(1);
}
}
if(pid == 0)
{
while(1)
{
kill(getpid(), SIGCONT);
}
}
return 0 ;
}
You're mixing up which PID is which. The child is sending itself SIGCONT, which does nothing since it's already running. Make it send the parent SIGCONT instead.

If I register a custom signal handler on a process before forking, will the subsequent child processes also have the custom signal handler registered?

When we call SIGINT (ctrl+c) on a parent process, I understand that the parent process will relay the signal to its child processes. However, will the child processes handle the signal in the same way as the parent, assuming that I have registered a custom signal handler before forking. For example:
void interruptHandler(int sig) {
int thisPid = (int) getpid();
while (1) {
int childPid = wait(NULL);
if (childPid == -1) break;
printf("\t[%d] terminated.\n", childPid);
}
printf("PID[%d] Ended.\n", thisPid);
exit(1);
}
int main(int argc, char const *argv[]) {
if (signal(SIGINT, interruptHandler) == SIG_ERR) {
printf("Handler registration error");
}
for (int count = 0; count < 10; count++) {
int pid = fork();
if (pid == 0) {
return 0;
}
}
while (1);
return 0;
}
Executing ctrl+c when the above process is running seems to give me the impression that the parent only handles the signal with the custom handler, while the child process handle the signal with the default handler.
This is what the output looks like: 1
Is there a way to get the child processes to use the custom handler?
When you do this:
for (int count = 0; count < 10; count++) {
int pid = fork();
if (pid == 0) {
return 0;
}
}
You're telling the child processes to exit immediately, so they never get a chance to get the signal. Instead, have the children break out of the loop:
for (int count = 0; count < 10; count++) {
int pid = fork();
if (pid == 0) {
break;
}
}
Then the child processes will be active when CTRL-C is pressed.
Some notes: Your use of stdio is badly messed up with respect to both signals and forking. Unless (roughly speaking; the detailed rules can be found in the POSIX XSH 2.5.1) you flush the stream before forking, only one forked child can continue to use a given stream (in your case, stdout) after the fork. In general it's unsafe to call functions which are not classified as "async-signal safe" from a signal handler too, but as long as you've reached the while loop before you hit Ctrl-C that should not affect you.
With that said, your problem just seems to be that your child processes are immediately exiting:
if (pid == 0) {
return 0;
}

Signal handlers in mini shell project

This is what happens in my signal handler. Also signal_flag is a global variable.
volatile sig_atomic_t signal_flag = 0;
void sig_handler(int signo) {
if (signo == SIGTSTP) {
signal_flag = 1;
}
}
This the condition that occurs, provided my fork() works as its supposed to. I have the sleep set to 5 so I have enough time to press CTRL+Z after a command I'll give as an input and suspend the process.
pid_t child_pid = fork();
int status;
//GOT A SIGNAL.
if (signal(SIGTSTP, sig_handler) != SIG_ERR) {
signal(SIGTSTP, SIG_IGN);
kill(child_pid, SIG_IGN);
insert_suspended_process(child_pid, ACTIVE);
//_exit(EXIT_SUCCESS);
}
if (child_pid < 0) {
fprintf(stderr, "execute: fork failed.\n");
exit(EXIT_FAILURE);
}
if (child_pid == 0) {
/* child process. */
//print_child_messages();
char bin[512];
strcpy(bin, command[0]);
//strcat(bin, command[0]);
if (bars > 0) {
//Houston, we have pipes, I REPEAT, WE HAVE PIPES!
int pipefd[2], status;
pid_t cpid;
if (pipe(pipefd) == -1) {
fprintf(stderr, "execute: pipe failed.\n");
exit(EXIT_FAILURE);
}
cpid = fork();
pipe(pipefd);
}
sleep(3);
//executing...
execvp(bin, command);
_exit(EXIT_SUCCESS); //safer than exit().
}
else {
/* parent process. */
//print_parent_messages(child_pid);
//signal(SIGTSTP, SIG_IGN);
waitpid(child_pid, NULL, 0);
}
I'm making a shell as part of homework, and I'm requested to handle the SIGTSTP signal in a way that, when the user presses CTRL+Z my shell will suspend the ongoing process(i have set sleep(3) so I can suspend even a simple ls -al process)
My problem is that my code adds the process with that pid to my list via the insert_suspended_process(pid_t) function but this occurs without me pressing the CTRL+Z signal. Any thoughts or quidelines?
You don't seem to check the result of the fork() in the if (i==12). Also installing the signal handler AFTER the fork is a problem waiting to happen ..

Interprocess Communication fork() - Timing wait() and/or sleep()

I've been asked to develop the consumer (client) side to a producer (server), where the producer creates processes, waits until the consumer has read shared memory and deleted processes, then passes control back to the producer for the killing of processes and the shutting down of the shared memory block.
I've researched the difference between sleep and wait, and realise that as soon as fork() is called, the child process begins running.
The below code is after the creation of processes and checks if they're parent processes. If they are, they wait(0). *Now for my question, how do I know where the code in the consumer starts to be executed, and how do I pass it back? *
else if(pid > 0)
{
wait(0);
}
Below can be seen the main loop the producer uses.
int noToCreate = atoi(argv[2]); // (user inputs on cmd line "./prod 20 10 5" - 20 size of shared mem, 10 process to be created, 5 processes to be deleted)
while(*memSig != 2)
{
while(*memSig == 1) // set memsignature to sleep while..
{
sleep(1);
}
for(B = 0; B < noToCreate; B++)
{
pid = fork();
if(pid == -1)
{
perror("Error forking");
exit(1);
}
else if(pid > 0)
{
wait(0);
}
else
{
srand(getpid());
while(x == 0)
{
if(*randNum == 101)
{
*randNum = rand() % (100 -
1) + 1;
*pidNum = getpid();
printf("priority: %d
Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
else
{
*randNum++;
*pidNum++;
}
}
exit(0);
}
} /* Closes main for loop */
if(*memSig == 0)
{
*memSig = 1;
}
} /* Closes main while loop */
Thanks a bunch guys :)
wait make parent blocked until any child end .You can use waitpid let parent wait specific child.
When a child process end, it will set a signal SIG_CHILD.
The pid is zero for the child process after the fork, so you are in the child process at your call to the srand function.
The other pid is that for the child process which allows he original thread to wait for the child to finish. If you wish to pass data between the processes consider using a pipe. A popen call returns two file descriptors, one to write end and the other to the read end. Set this up before the fork and the two processes can communicate.
wait makes the parent wait for any child to terminate before going on (preferably use waitpid to wait for a certain child), whereas sleep puts the process to sleep and resumes it, as soon as the time passed as argument is over.
Both calls will make the process block.
And it is NOT said that the child will run immediately, this is indeterminate behavior!
If you want to pass data between producer and consumer, use pipes or *NIX sockets, or use the return-value of exit from the child if a single integer is sufficient.
See man wait, you can get the return value of the child with the macro WEXITSTATUS.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}

Resources