C pipe sends not all of the numbers - c

So I have this program where the initial process sends numbers to the child, then the child performs certain operations with numbers and sends them to the next child...
My problem is that where the program has to send the numbers starting from two (2), the first number the child gets is 3. What could the problem be?
Here is my code:
void start(int num_of_nums){
if (num_of_nums <= 0) return;
int pipefd[2];
pid_t cpid;
int pipe_res = pipe(pipefd);
if (pipe_res == -1) {
printf("pipe error in start\n");
perror("pipe error");
exit(EXIT_FAILURE);
}
//create a new process
cpid = fork();
if (cpid == -1) {
printf("fork error in start\n");
perror("fork error");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // child
printf("child in start\n");
close(pipefd[1]); // close write end
int num_from_parent = pipefd[0]; //where the number is read
printf("num from parent is %d\n", num_from_parent); //prints out 3...
filter(num_from_parent);
} else { // parent
printf("parent in start\n");
close(pipefd[0]); // close read end
for (int i = 2; i <= num_of_nums + 1; i++){
write(pipefd[1], &i, sizeof(int)); //WHERE THE NUMBERS ARE SENT
}
close(pipefd[1]);
}
}
Help would be much appreciated...

Related

Passing data from one pipe to another

I am new to pipes but how do I redirect the output from child_1 to the input for child_2?
I am trying to pass the value from the parent to child_1, adds 1 to the value, print the value, then use that output and pass it into child_2, add 1 again, and finally print the value.
The code below has the right output value for child_1, but not for child_2, how do I redirect the output from child_1 to the input for child_2?
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[]) {
int fd[2];
int PID;
pipe(fd); //fd1[0] = read | fd1[1] = write
PID = fork(); // spawn child_1
if (PID < 0){ // failed to fork
perror("Unable to fork child");
exit(1);
}
if (PID > 0) { // parent
int value = 100;
// since parent is only writing, close the reading end of pipe
close(fd[0]);
// write the data to the write end of the pipe
write(fd[1], &value, sizeof(int));
// then close the writing end of the pipe (parent)
close(fd[1]);
/**********************************************************/
} else { // child 1
int val = 0;
// read from the parent pipe
read(fd[0], &val, sizeof(int));
val += 1;
// is this how to redirect from one pipe to another?
dup2(fd[0], fd[1]);
// this prints the right value for val (val [101] = value [100] + 1)
printf("Child [%d] read value %d\n", getpid(), val);
// close the reading end of the pipe for child_1
close(fd[0]);
int PID2 = fork(); // make child 2
if(PID2 == 0) { // child 2
int val2 = 0;
close(0); // close stdin since we are trying to take the value from child_1
// read input from child_1 pipe (NOT WORKING?)
read(fd[0], &val2, sizeof(int));
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
}
}
return EXIT_SUCCESS;
}
The way you have things set up, there's no need to use dup2() or any other I/O redirection.
Add #include <unistd.h> to the list of include files (and remove #include <string.h> — it seems to be unused)
Delete: dup2(fd[0], fd[1]);
Delete: close(fd[0]);
Delete: close(0);
Before the second fork(), add write(fd[1], &val, sizeof(val));
When you have close(fd[0]) in the first child, you effectively close fd[0] for the second child too.
You should check the status of the read and write operations before using the results.
Those changes lead to:
/* SO 7383-1815 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd[2];
int PID;
pipe(fd);
PID = fork();
if (PID < 0)
{
perror("Unable to fork child");
exit(EXIT_FAILURE);
}
if (PID > 0)
{
int value = 100;
close(fd[0]);
write(fd[1], &value, sizeof(int));
close(fd[1]);
}
else
{
int val = 0;
if (read(fd[0], &val, sizeof(val)) != sizeof(val))
{
perror("read() failed in child 1");
exit(EXIT_FAILURE);
}
val += 1;
printf("Child [%d] read value %d\n", getpid(), val);
if (write(fd[1], &val, sizeof(val)) != sizeof(val))
{
perror("write() failed in child 1");
exit(EXIT_FAILURE);
}
int PID2 = fork();
if (PID2 == 0)
{
int val2 = 0;
if (read(fd[0], &val2, sizeof(val2)) != sizeof(val2))
{
perror("read() failed in child 2");
exit(EXIT_FAILURE);
}
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
close(fd[1]);
}
}
return EXIT_SUCCESS;
}
When compiled (cleanly with options set fussy), it produces output such as:
Child [34520] read value 101
Child [34521] out 102
I believe this is what was wanted.

Pipe is successfully written to but the target process won't read

I'm trying to create a piped multithreaded, multiprocess program where the parent process will create a thread that will read from a pipe from a sending child and then write to another pipe to the target child. But when the sending child process invokes piped write() to the parent process, the parent process won't read; it continues to block.
Pipe creation and the parent process creating the thread
int value1 = pipe(to_parent[index]);
int value2 = pipe(from_parent[index]);
if(value1 == -1) {
perror("pipe");
continue;
}
if(value2 == -1) {
perror("pipe");
continue;
}
/* fork for every connection to the server*/
int pid = fork();
/*go back to the beginning of loop if fork fails*/
if(pid == -1) {
perror("fork failed");
continue;
}
/* parent process will go back to the beginning of the loop */
if(pid != 0) {
close(from_parent[index][0]);
close(to_parent[index][1]);
pthread_create(&parent_listen_to_child[index], NULL, listen_to_child, &index);
continue;
}
/*PIPE
CHILD => PARENT*/
void * listen_to_child(void * ptr) {
int index = *(int*)ptr;
int index_to_kill;
printf("listen_to_child\n");
read(to_parent[index][0], &index_to_kill, sizeof(int));
printf("talk to child\n");
write(from_parent[index_to_kill][1], &index, sizeof(int));
}
Child processes create the thread that reads from parent through pipe and a thread which would soon write to the parent through the pipe
void respond(int index) {
char buffer[MAX];
int client_socket = clients[index].socket;
char name[MAX_NAME_SIZE];
strcpy(name, get_name(client_socket));
strcpy(clients[index].name, name);
printf("%s has connected to the server\n", name);
print_names();
printf("hello\n");
pthread_create(&command_processor, NULL, receive_command, &index);
/* close pipe ends in child*/
close(from_parent[index][1]);
close(to_parent[index][0]);
pthread_create(&child_listen_to_parent, NULL, listen_to_parent, &index);
pthread_join(child_listen_to_parent, NULL);
pthread_join(command_processor, NULL);
}
/* PIPE
PARENT => CHILD TO CANCEL*/
void * listen_to_parent(void * ptr) {
int index = *(int*)ptr;
int tattle;
printf("listen_to_parent\n");
read(from_parent[index][0], &tattle, sizeof(int));
printf("cancel %s\n", clients[index].name);
pthread_cancel(command_processor);
}
Where the write to the parent process from sending child is invoked
void send_talk(client sender, client target) {
printf("sender: %s\ntarget: %s\n", sender.name, target.name);
int sender_index = get_index(sender.socket);
int target_index = get_index(target.socket);
int write_value;
if(( write_value = write(to_parent[sender_index][1], &target_index, sizeof(int))) != -1) {
printf("write successful: wrote %d bytes\n", write_value);
}
else {
printf("write unsuccessful\n");
}
}

Creating a new child process when old one is terminated in C

I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.

C program to pipe multiple commands

I have written the below method to fork and execute commands separated by multiple pipes( test with : ls -lrt | grep "check" | wc -l . However it is not resulting in any output, could any one please spot my mistake. Thanks.
void execCmd (pInfo *info)
{
int i, j, k, m;
struct comType *comm, *comm1, *comm2;
if(info->noOfPipes > 2)
{
// DOES NOT WORK
printf("Start\n");
comm=&(info->cArr[0]);
comm2=&(info->cArr[(info->ppNum)-1]);
int fds[2];
pipe(fds);
pid_t pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
printf("1st child execution here\n");
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm->cmd,comm->parms);
}
for (k=1;k<=((info->ppNum)-1);k++)
{
printf("For loop executionn number %d",k);
comm1=&(info->cArr[k]);
printf ("comm 1 : %s\n",comm1->cmd);
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//2nd to n-1 child process
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm1->cmd,comm1->parms);
}
wait(NULL);
}
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//nth child process
printf("Last child execution\n");
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
execvp(comm2->cmd,comm2->parms);
}
close(fds[0]);
close(fds[1]);
wait(NULL);
wait(NULL);
}
}
This following code should give you an idea how to implement the pipelining:
#define STDIN 0
#define STDOUT 1
void exec_cmd(struct comType cmd) {
execvp(cmd->cmd, cmd->params);
}
void pipeCmds(struct comType* cmds) {
int fd[cmds_length * 2] = {0};
pid_t pid = 0;
for (int i = 0; i < cmds_length; i++) {
if (pid = fork() == 0) {
//child: make this cmd's output the other cmd's input
pipe(fd + (2*i) );
close(STDOUT);
dup(fd[i]);
if(i > 0) {
close(STDIN);
dup(fd[i-1]);
}
exec_cmd(cmds[i]);
close(fd[i]);
}
}
}
Note that the main idea is that each command is executed in a separate process (via fork) and the output goes to the next command's input rather than to the default stdout(with file descriptor 1), and the same for the input - stdin (file descriptor 0).

C Programming 2 pipes

I want to set up 2 pipes in my program. I have 1 pipe working fine, but I don't know where to place the second pipe.
The pseudo code of my setup is shown below,
Here is it with curly braces sorry about that
//the first pipe:
pipe(pipe1)
//the second pipe:
pipe(pipe2)
pid = fork()
if(pid == 0) {
dup2(pipe1[1], 1)
close(pipe1[0])
execvp(beforepipe)
}
if(pid > 0) { //everything below is in here
pid2 = fork()
if(pid2 == 0){
//pipe1
dup2(pipe1[0],0)
dup2(out,1)
close(pipe1[1])
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
}
if(pid2 > 0){
close(pipe[0])
close(pipe[1])
wait() //this is an infinite for loop
pid3 = fork()
if(pid3 == 0){
dup2(pipe2[0],0)
dup2(out,1)
close(pipe2[1])
execvp(afterpipe2)
}
if(pid3 > 0) {
close(pipe2[0])
close(pipe2[1])
wait()
}
}
The position of the second pipe is in the wrong place or the code is altogether wrong.
Any suggestions?
Your main problem is that you are not closing anywhere near enough file descriptors. Given a file input1 in the current directory containing your string "eschew obfuscation\", this code works for me (but note how many file descriptors have to be closed!).
Rule of thumb: if a pipe is dup2()d or dup()d to standard input or output, close both file pipe file descriptors.
Example code (with debug tracing in place):
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* command pipeline: cat input1 | tr a-z A-Z | tr \\ q */
int main(void)
{
int pipe1[2];
int pipe2[2];
pid_t pid1;
char *cmd1[] = { "cat", "input1", 0 };
char *cmd2[] = { "tr", "a-z", "A-Z", 0 };
char *cmd3[] = { "tr", "\\", "q", 0 };
if (pipe(pipe1) != 0 || pipe(pipe2) != 0)
{
perror("pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0)
{
perror("fork 1 failed");
return 1;
}
if (pid1 == 0)
{
/* Child 1 - cat */
dup2(pipe1[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd1[0], cmd1);
perror("failed to execute cmd1");
return 1;
}
printf("pid 1 = %d\n", pid1);
fflush(stdout);
pid_t pid2 = fork();
if (pid2 < 0)
{
perror("fork 2 failed");
return 1;
}
if (pid2 == 0)
{
/* Child 2 - tr a-z A-Z */
dup2(pipe1[0], 0);
dup2(pipe2[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd2[0], cmd2);
perror("failed to execute cmd2");
return 1;
}
printf("pid 2 = %d\n", pid2);
fflush(stdout);
pid_t pid3 = fork();
if (pid3 < 0)
{
perror("fork 3 failed");
return 1;
}
if (pid3 == 0)
{
/* Child 3 - tr \\ q */
dup2(pipe2[0], 0);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd3[0], cmd3);
perror("failed to execute cmd3");
return 1;
}
printf("pid 3 = %d\n", pid3);
fflush(stdout);
/* Parent - wait for the kids to all die */
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
pid_t corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d died status 0x%.4X\n", corpse, status);
return 0;
}
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
I think the execvp() didnot return. So the code below the execvp() is irrelevent.

Resources