I have the following code:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h> // may not be needed
#include <sys/stat.h> // may not be needed
#include <stdlib.h>
#include <string.h>
typedef struct {
int pid;
char arg[100];
int nr;
} Str;
int main() {
int c2p[2];
pipe(c2p);
int f = fork();
if (f == 0) {
Str s;
s.pid = 1234;
strcpy(s.arg, "abcdef");
s.nr = 1;
close(c2p[0]);
write(c2p[1], &s, sizeof(Str));
close(c2p[1]);
exit(0);
}
wait(0);
close(c2p[1]);
Str s;
read(c2p[0], &s, sizeof(Str));
printf("pid: %d nr: %d arg: %s", s.pid, s.nr, s.arg);
close(c2p[0]);
return 0;
}
I have to say that it worked just fine until now (pid, nr and arg were never altered), but:
When the child process is done, is the memory segment (used by the child) destroyed (marked as free)?
If so, is there the risk that between the time of writing and the time of reading to lose the acces to that segment or the data to be altered?
(The original question was this: Sending structure through pipe without losing data )
Although the child process' memory is given back to the operating system when the process exits, I suspect this is not what you're really asking about.
You are more likely concerned about what happens to the data that was written to the pipe after the child process exits. As the pipe(2) man page states:
Data written to the write end of the pipe is buffered by the kernel
until it is read from the read end of the pipe.
So your data will arrive, even if the process that wrote it has already exited.
Related
Note: For simplicity, I don't include much error checking and my sample code doesn't really serve any practical purpose.
What I want:
I want a program that fork()s a child process and has it invoke a process using execl(). My parent then retrieves the exit code for that process. This is fairly trivial.
What I tried:
int main(int argc, char** argv) {
int ch = fork();
if(ch == -1) {
perror(NULL);
}else if(ch == 0) {
// In child, invoke process
execl("/path/process", "process", 0);
}else {
// In parent, retrieve child exit code
int status = 0;
wait(&status);
// print exit status
if(WIFEXITED(status)) printf("%d\n", WEXITSTATUS(status));
}
}
My issue:
WEXITSTATUS() only retrieves the lower 8 bits of the exit value while I need all the bits from the int value. Specifically, process performs a calculation and the result may be larger than 8 bits. It may even be negative, in which case, the highest bit will be needed to represent the correct value.
What else I tried:
Also, while looking around, I found the pipe() function. However, I'm not sure how to use it in this situation since, after calling execl(), I can't write to a file descriptor from within the child.
So how can I go about retrieving a child's exit status that is larger than 8 bits?
I don't think that what you are trying to accomplish it's possible, because in Linux (actually i think it's UX specific), a process exit code is an 8bit number (max 256): 0-255 (and as a convention, 0 means success, anything else means error) and lots of stuff rely on this fact (including the macros you used). Take the following piece of code:
// a.c
int main() {
return 257;
}
If you compile it (gcc a.c), and run the resulting executable (a.out) checking (echo $?) its exit code (that will be truncated by the OS; hmm or is it the shell?) it will output 1 (wrap around arithmetic): 257 % 256 = 1.
As an alternative as you mentioned, you could use pipe (this post is pretty descriptive) or sockets (AF_UNIX type).
this code is from: How to send a simple string between two programs using pipes?
writer.c
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
return 0;
}
reader.c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
return 0;
}
the code, probably the parent/reader, should delete the fifo node, perhaps by calling rm.
Otherwise the fifo entry is left in existence, even across a re-boot, just like any other file.
This is a quiz from my class, and it invovles concept around fork and pipe. I just have a several confusions about this code.
1) What does if((pid = fork() == 0) means? is it just checking fork using pid(process id), why does loop start with this?
2)close (p[1]); what does this part mean? closing the first integer of array P?
3)The while loop start after close, does it mean it read into p[0]'s size if it is not zero?
4.The two write lines, what does that mean, and why are they both named 1? are they happening at the same time?
#include <stdio.h>
#include <stdlib>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int p[2];
int i, pid, status;
char buffer[20];
pipe(p);
if((pid = fork() == 0) {
close (p[1]);
while (( i = read (p[0], buffer, sizeof("abcdefghi"))) != 0)
{ buffer [i] = '\0';
printf("read %d bytes: %s\n", i, buffer);
}
close(p[0]);
exit (0);
}
write(p[1], "abcdefghi', sizeof("abcdefghi"));
write(p[1], "123456789', sizeof("123456789"));
close(p[0]);
close(p[1]);
while(wait(&status)!= pid);
return(0);
}
You really should RTFM but :-
fork() creates an identical copy of the current procedure running from the same line of code. The only difference between the two copies is the return code from fork(). This will be 0 if you are in the newly created copy or the process id of the newly created copy if you are in the original executable (or -1 if something went wrong).
pipe(p) creates a pipe and returns two file handles in the array "p". the first handle is the output from the pipe opened for reading, the second handle is the input to the pipe open for writing. So close(p[1]) closes the input to the pipe ( this is in the new process which reads from the pipe, it is considered good practice to close the file descriptor you are not using!)
The while loop is checking "i" the return code from the read from the pipe file, this will return 0 when there is nothing to read.
int main()
{
char *msg="hello";
char buff[MAX];
int p[2];
pipe(p);
int i,pid=fork();
if(pid>0){
//close(p[1]);
read(p[0],buff, MAX);
}
else
{
printf("child exiting\n");
}
}
Why does the above code end up blocking ? But then if we remove the comment and place
close(p[1])
then why does the code end immediately ?
Once you create a pipe, it gets four ends:
A reading end p[0] in the parent process
A writing end p[1] in the parent process
A reading end p[0] in the child process
A writing end p[1] in the child process
UNIX will not deliver EOF to the reader unless both writing ends have been closed, because it knows that the pipe is still writeable.
When the child process exits, it closes both ends of the pipe on its side. However, the parent still has one writeable end open, so reading from the pipe blocks instead of delivering an EOF to the parent. That is why UNIX manual instructs to close the unused ends of the pipe right away:
An application that uses pipe(2) and fork(2) should use suitable close(2) calls to close unnecessary duplicate file descriptors; this ensures that end-of-file and SIGPIPE/EPIPE are delivered when appropriate.
Here is an example of how to make your program not block without closing p[1] on the parent side:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* write_pipe(void* pp) {
int* p = (int*)pp;
char msg[] = "Hello from another thread!";
write(p[1], msg, sizeof(msg));
return NULL;
}
int main()
{
char buff[100];
int p[2];
pipe(p);
int pid=fork();
if(pid>0){
pthread_t thread1;
pthread_create (&thread1, NULL, &write_pipe, (void *)p);
read(p[0],buff, 100);
printf("%s\n", buff);
printf("parent exiting\n");
}
else
{
printf("child exiting\n");
}
return 0;
}
The code above writes to the writing end of the pipe from a thread within the parent process, instead of writing to it from the child process. This is a legitimate use of a pipe, too, illustrating why UNIX cannot deliver EOF unless the parent's writing end of the pipe is closed.
Read is a blocking call and it returns only when it receives EOF . If you wont close the write end of the pipe, read end wont get the EOF and hence,program will remain blocked
I'm completly new to the C language and Unix systems. I might formulate myself badly or wrong. I have a C program where two processes increments a global variable up to 30. I am aware that order of output is random with parallel processing. But when using the | more pipe, the output is always the same: Child 1-30 -> Parent 1-30. How come?
I've been told that when using printf to print a variable, the variable content is sent to a buffer before printing to screen. And apparently you can use new line (\n) to flush the buffer right away. Is this information connected?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int g_ant = 0;
void writeloop(char *text)
{
long i = 0;
while (g_ant < 30)
{
if (++i % 100000 == 0)
printf("%s: %d\n", text, ++g_ant);
}
}
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
{ /* child */
writeloop("Child");
exit(0);
}
writeloop("Parent"); /* parent */
waitpid(pid, NULL, 0);
return 0;
}
Your information is basically correct.
When the output goes to the terminal, the output is line buffered. When the output goes to a pipe, the output is fully buffered, so one of the processes finishes its output first. You could add fflush(stdout) after each iteration in writeloop(), or use setvbuf() to make it line buffered, or even unbuffered output.
Incidentally, note that the global variable is not shared between the child and the parent process; they each have their own copy of the variable.
So i was experimenting on how to use fork and semaphores for a homework and it seems everytime i run the program fork always returns a number >0, while what i wanted was to first have several processes be made then be stopped using semaphores and then have some of them restart again.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
int main(int argc,char *argv[])
{
int i,count;
count = 0;
pid_t *Pc;
Pc=(pid_t *) malloc((argc-2)*sizeof(pid_t));
sem_t *sem;
sem = (sem_t *) malloc((argc-2)*sizeof(sem_t));
for (i = 0; i <= argc-2; i++){
sem_init(&sem[i], 0, 0);
}
for (i =0; i<=argc-2; i++){
Pc[i] = fork();
if (Pc[i] == 0){
printf(" child");
sem_wait(&sem[i]);
printf("Experiment was a success!");
}
if (Pc[i]>0){
printf("Parent");
}
}
for (i =0; i<=argc-2; i++){
if (Pc[i] > 0)
count++;
}
for (i= 0; i<=3; i++){
if ( count == argc-2){
sem_post(&sem[i]);
}
}
}
nameofprogram 1 2
prints: Parent
Child
Parent
Child
You need to read the man page for sem_init(). The type of semaphore you are creating right now is not shared across processes. This requires a non-trivial change to your program, because you also need to set up shared memory. Refer to this question for a lengthy explanation of how to make your program work.
When a program calls fork, a new process is created with a new exact copy of the memory space. This mean that sem in your child process is not the same as sem in your parent process. So, when you call sem_post, you child process can not be notified of the change and get out of the wait function.
To solve this, you have different possibilities:
Create a shared memory which can be read by all your processes and create this semaphore in this shared memory, as already suggested.
Use named semaphores with sem_open. This kind of semaphore can be shared across different processes as it work like a file handle. This seems to be an easier way if you only need a shared semaphore (example here). You will have to generate a unique name for each semaphore in your array (may be only one semaphore on which you call sem_post multiple times would be enough for your use).
Keep your semaphores and use threads instead of processes (but I guess your homework is about processes so this may not be an option for you)