Why synchronization with pipe semaphore behaves in this strange way? - c

I'm trying to solve some simple example of process synchronization; in this particular example I want three processes: one prints "A", another prints "B" and the last prints "C". I want to print "A" first, then "B" or "C" and again "A", "B" or "C". To be more clear I want an output pattern like "ABACACABACABABACA...."
Below there is my symple code, termination is not managed because this is just an example to understand how things work.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void semaphore_init (int* sw){
if (pipe(sw) == -1) {
printf ("Error\n");
exit (-1);
}
}
void semaphore_wait (int* sw){
char buffer;
if (read(sw[0],&buffer,1) != 1) {
printf ("Error\n");
exit (-1);
}
}
void semaphore_signal (int* sw){
if (write(sw[1],"X",1) != 1) {
printf ("Error\n");
exit (-1);
}
}
int s1[2];
int s2[2];
void childA();
void childB();
void childC();
int main(){
pid_t pid;
semaphore_init(s1);
semaphore_init(s2);
semaphore_signal(s1);
pid=fork();
if(pid==0) childA();
else{
pid=fork();
if (pid==0) childB();
else {
pid=fork();
if(pid==0) childC();
}
}
wait(NULL);
return 0;
}
void childA(){
while(1){
semaphore_wait(s1);
printf("A-");
semaphore_signal(s2);
}
exit(0);
}
void childB(){
while(1){
semaphore_wait(s2);
printf("B-");
semaphore_signal(s1);
}
exit(0);
}
void childC(){
while(1){
semaphore_wait(s2);
printf("C-");
semaphore_signal(s1);
}
exit(0);
}
I don't understand why the output of this code is something like:
A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-C-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-A-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B
If, instead, I put the "\n" after the char I get the right output.
Could someone, kindly, explain me the reason of that?

In many implementations, including Linux, stdout is line buffered. This means any printf characters are stored to a (memory) buffer until a newline is encountered or the line buffer fills or the stream is flushed. In the example code this results in each process writing to their own local buffer every time it gains the semaphore. So even though the sequencing is correct as you intended but because there are three seperate buffers the final output result is not as you expect. Each process eventually flushes their buffer to stdout but each of those buffers only contain the same letter repeatedly.
The solution is to either add a newline to the printf (as you have found) or to do an explicit fflush(stdout). Another alternative is to use stderr which is not buffered by default: e.g. fprintf(stderr, "A-");

Related

What is the importance of adding "\n" to stdout when it's redirected to another process?

So, I'm playing with pipes in c, and I have an exercise where I call a program through command line as this: "./self 1" which then calls itself with execlp but with an argument 2: "./self 2" which further on calls itself with argument 3: "./self 3". The point of these processes is this: process1 takes a line from keyboard and puts it in pipe1, then process2 gets the line from pipe1 and puts it in pipe2, then process3 gets it from pipe2 and counts the number of space characters. This code never works if I dont print a newline character on the screen before taking inputs with fprintf(stdout,"\n"); . Why is that?
Here is the code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (strcmp(argv[1], "1") == 0) {
int fdpipe1[2];
if (pipe(fdpipe1)) {
printf("Error pipe1\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe1[1]);
dup2(fdpipe1[0], 0);
execlp("./self", "./self", "2", NULL);
} else {
close(fdpipe1[0]);
fprintf(stdout, "\n");
dup2(fdpipe1[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "2") == 0) {
int fdpipe2[2];
if (pipe(fdpipe2)) {
printf("Error pipe2\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe2[1]);
dup2(fdpipe2[0], 0);
execlp("./self", "./self", "3", NULL);
} else {
close(fdpipe2[0]);
fprintf(stdout, "\n");
dup2(fdpipe2[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "3") == 0) {
char input[100];
gets(input);
int i = 0, counter = 0;
while (input[i] != '\0') {
if (input[i++] == ' ') counter++;
}
printf("%d\n", counter);
}
return;
}
In this kind of construct, when you connect stdout from a process to stdin of another process via unnamed pipe, a newline character is added usually to ensure the stream is sent, i.e. the stdout buffer is flushed, as a parallel example, when you use scanf, only when you hit enter (a newline is added to stdin) is the stream read, a similar principle applies here.
I would suggest you use STDIN_FILENO and STDOUT_FILENO
built in macros instead of the hard coded file descriptors, if not for anything else, it makes the code more readable for someone who is unfamiliar with the matter.
Please avoid using gets, this is a dangerous function, it does not check the bounds of the destination buffer, it can cause all kinds of trouble, so much so it was deprecated and later removed from the standard, though it still can be used with some compilers, for legacy reasons I would imagine, check this fantastic answer on a post about this topic:
Why is the gets function so dangerous that it should not be used?
The advice is to use fgets instead.

With vs without the C pipe() function- what's causing this behavior?

I wrote a simple script (taken from a tutorial) which writes data to one end of a pipe in a child process, and reads it from the other end of the pipe in the parent process:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int mypipefd[2];
int ret;
char buf[20];
ret = pipe(mypipefd);
if (ret == -1) {
printf("Pipe failed.\n");
exit(1);
}
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!";
write(mypipefd[1], msg, strlen(msg) + 1);
} else {
printf("Parent process.\n");
read(mypipefd[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This works fine and outputs the results I expect:
Parent process.
Child process.
Buf: Hello there!
[ project ] $
Then as I got more familiar with the code, I wondered why we need to use mypipefd[2] and pipe() to achieve this goal, or whether mypipefd[1] by itself would work. So I tried it out with the following code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int my_array[1];
char buf[20];
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!\n";
write(my_array[0], msg, strlen(msg) + 1);
} else {
// wait(NULL);
printf("Parent process.\n");
read(my_array[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This code outputs the same text, but it hangs after it finishes printing.
Parent process.
Child process.
Buf: Hello there!
No prompt, this time. I even tried un-commenting that call to wait(NULL), on the off-chance that the root cause was a conflict between parent and child processes. No such luck.
What's going on here? Why am I unable to read and write to a length-of-one array in this way without the program hanging? What exactly is the compiler stuck on?
A pipe, on computers as well as in real life, have two ends. And like pipes in real life, data flows from one end of the pipe (the write end) to the other (the read end).
The pipe function gives you those two ends by writing them to an array of two file-descriptors. The first element of the pair is read-only, and the second is write-only.
The pipe() function accepts an array of 2 integer as an input argument.
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
It then generates a new pipe object, and initializes the pipefd array with file descriptors for read and write operation.
What you try to do is call read() and write() using some arbitrary, uninitialized ints (or file descriptor). Meaning the OS did not allocate a pipe object and did not provide you with file descriptors (the pipe's API) to be use with read() and write().
This (calling read() or write() with uninitialized file descriptor) will result in "undefined behavior".
"I find that a good working definition of "undefined behaviur" is "works for me, works for you, works during development and QA, but blows up in your most important customer's face"" --- Scott Meyers

C fork program explanation

I have a code as below
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("a\n");
fork();
printf("b\n");
if(fork() == 0) {
printf("c\n");
exit(0);
}
printf("d\n");
return 0;
}
Output :
a
b
d
a
b
c
a
b
d
a
b
c
I don't know why the output duplicated many times.
I don't know why the output duplicated many times
Because printf() is buffered.
When a process calls fork(), the resulting child process obtains a copy of the parent's output buffer.
You can empty this output buffer by placing fflush(stdout) just before each call to fork(). In that case output should be:
a
b
b
d
c
d
c
Note that if the output refered to a terminal, it would be line-buffered by default, i.e.: the buffer would be dumped every time a \n is sent to the output. Not so if you are redirecting the output to a file.
When you call fork() it gets a copy of output buffer of the calling process. Buffering is enabled by default, so you get this behavior.
You can use
fflush(stdout);
before a call to fork(). Or, you can also disable buffering using
setbuf(stdout, NULL);
You can read more about fork here. Let me know if you need any more help.
The answer is already in the comments. You are calling fork() twice. So the solution is to just call it once and save the result in a variable like this int pid = fork(). Also, you should check if the fork-call failed (if it does, it returns a negative value).
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("a\n");
int pid = fork();
if (pid < 0)
{
fprintf(stderr, "Can't fork!");
exit(1);
}
printf("b\n");
if(pid == 0)
{
printf("c\n");
}
else
{
printf("d\n");
}
return 0;
}

Stop some commands used in the system() function

I have a problem with system() function.
I need to implement a simple bash, one of the modules of the my project is to permit user types some bash command to execute it.
Above what i'm doing actually:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// similar to gets
int reads(char* str)
{
#ifndef WIN32
fflush(stdout);
strcpy(str,GetServiceLine());
#else
gets(str);
#endif
return 1;
}
int main(void) {
char str[100];
while(strcmp(str, "exit")) {
printf("\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
reads(str);
system(str);
}
return 0;
}
My problem is with commands like ping.
When i run this code on my PC and i try execute ping command for a legal IP it works fine, i can stop the ping process using CTRL+C, but when i run it on my target on the same way i can't use CTRL+C and my process keep always at system() call.
Does somebody can help me?
Note: i read this post about how to use CTRL+C to break a system function. I tried the suggestion but didn't work.
Thanks.
Since you hadn't tried it yet I'll throw it up here as a suggestion. You can always install a signal handler to catch signals that you are interested in.
Here's a quick example using (mostly) your code which demonstrates how it's done:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void intHandler(int dummy)
{
exit(1); // Do whatever you want here to handle it...
}
int main(void)
{
char str[100];
signal(SIGINT, intHandler);
signal(SIGKILL, intHandler);
while(strcmp(str, "exit")) {
printf("\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
gets(str);
system(str);
}
return 0;
}
I can catch a ctrl+C using this, but I'm not sure if it's what you're looking for.
After the comments above i just thought of explaining why exactly you can't control this in a graceful manner (some hacks are suggested in comments though).
system command is going to behave exactly if you forked a child process and then called exec on the child for executing the binary passed to exec as an argument.
The system() function shall ignore the SIGINT and SIGQUIT signals, and shall block the SIGCHLD signal, while waiting for the command to terminate. If this might cause the application to miss a signal that would have killed it, then the application should examine the return value from system() and take whatever action is appropriate.
Remember, this is very much OS specific behavior and there is no standard as such.
system() function call in Linux
Internally ping utility would run on icmp and waits until a response is received from the other node.
You might write a signal handler as suggested in another answer and call a killpid() but it would be blocked until the call to system() returns. This is stated in the specs of the function. So you might be able to terminate but only AFTER the call has returned. :)
Below the code used to fix my problem. I don't know if is the better solution, but solved my problem in this case.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// similar to gets
int reads(char* str)
{
#ifndef WIN32
fflush(stdout);
strcpy(str,GetServiceLine());
#else
gets(str);
#endif
return 1;
}
void getCommandName(char input[], char output[])
{
int count=0;
while (input[count] != NULL && input[count] != ' ' && input[count] != '\0') {
output[count] = input[count];
count++;
}
}
int killLastCommand(int pid)
{
char commandKill[30];
memset(commandKill, 0, 30);
sprintf(commandKill, "kill -9 %d", pid);
return(!system(commandKill));
}
int main(void) {
FILE *fp; //Will be used with popen()
char str[100];
char lastCommandName[50];
char pidofCommand[50];
char strLastPIDCommand[10];
int lastPIDCommand=0;
memset (str, 0, 100);
while(strcmp(str, "exit")) {
if (lastPIDCommand == 0) {
memset (lastCommandName, 0, 50); //Clean lastCommandName array
memset (pidofCommand, 0, 50); //Clean pidofCommand array
memset (strLastPIDCommand, 0, 10); //Clean strLastPIDCommand array
printf("\n\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
reads(str);
if (strcmp(str, "exit")) {
sprintf(str, "%s &", str);
}
getCommandName(str, lastCommandName);
system(str);
sleep(1); //Sleep to guarantee than command will end
sprintf(pidofCommand, "pidof %s", lastCommandName);
//Saving PID
fp = popen(pidofCommand, "r");
if (fp) {
fgets(strLastPIDCommand, 10, fp);
lastPIDCommand = atoi(strLastPIDCommand);
} else {
//Handle error
}
pclose(fp);
printf("commandName = %s\r\n", lastCommandName);
printf("pid = %d\r\n", lastPIDCommand);
} else {
printf("\n\nYou have a command running, press 'kill' to stop it before to type another command\n");
printf("EITVBash$ \n\n");
reads(str);
// if (str[0] == 0x03) { //CTRL+C hexa code
if (!strcmp(str, "kill")) {
if (killLastCommand(lastPIDCommand)) {
lastPIDCommand = 0;
}
}
}
}
return 0;
}
My implementation probably isn't clean, but i don't have much experience with c.
Thanks everybody.

I have a problem with the WIFSIGNALED()/WTERMSIG() macros, after using waitpid()

In this code C i launch a program from the command line and when it is closed from a signal different from SIGTERM (signal for normal end) my code should relaunch the initial program passed from the command line. But it is not so, in fact my code never relaunchs program saying that it is properly terminated.In practice my condition"if(WTERMSIG(status)!=SIGTERM)" works bad, WHY????? :'(
This is my code:
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char*argv[])
{
pid_t pid;
int* status=(int*)malloc(sizeof(int));
int term;
if(argc<2)
{
printf("Error: Too few arguments\n");
exit(EXIT_FAILURE);
}
while(1)
{
pid=fork();
if(pid!=0) /*father*/
{
waitpid(pid,status,0);
//term=WIFSIGNALED(status);
if(WIFSIGNALED(status))
{
if(WTERMSIG(status)!=SIGTERM)
{
printf("The program %d ended abnormally:\nRelaunching...\n",pid);
sleep(1);
}
else
printf("The program %d is properly terminated...\n",pid);
break;
}
else
{
printf("Can not read the reason for termination\n");
}
}
else /*child*/
{
execvp(argv[1],argv+1);
exit(EXIT_SUCCESS);
}
}
return 1;
}
The WIFSIGNALED() and WTERMSIG() macros both expect plain ints, not pointers to ints. This means that in your code, where status is a pointer to an int, you need to use *status when calling the macros, to pass them the value of the integer.
That said: why are you calling malloc() to allocate room for a single int, anyway? Just use a normal variable, and &status if you need a pointer to it.
Also, you should return EXIT_SUCCESS from main() on successful completion of your program, not 1.

Resources