Why this code with fork() generates Runtime Error in ejudge? - c

Why this code may generate Runtime Error in ejudge? This program counts the number of words from stdin input. Words can be separated by any amount of ' ' and '\n'.
It seems like fork() can cause a problem but I am not sure why I don't get the same error on my computer.
ejudge uses gcc - Plain C, 64 bit, using -std=c11 or -std=gnu11
The task:
On the standard input stream a text string is given which consists of
words (a sequence of non-space characters), between which there can be
any number of whitespace characters, including line feeds.
You need to calculate the number of words if you know there are not
more than 255, and output this value to the standard output stream.
Use creating new processes so that each process reads not more than
one word, e.g. using scanf("%s", ...).
You can only output the result from the process which was started
first (i.e. from the original program).
The resulting program must return with return code 0.
The size of each word does not exceed 4096 bytes.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define DBG(args...) fprintf(stderr, args)
//#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t pid;
pid_t first_child;
for (int i = 0; i < 256; ++i) {
pid = fork();
if (pid == 0) { // child continue reading
char str[4097];
if (scanf("%s", str) != EOF)
continue;
exit(1);
} else {
if (i == 1) {
first_child = pid;
}
if (wait(&status) == first_child) {
break;
} else {
exit(WEXITSTATUS(status) + 1);
}
}
}
fprintf(stdout, "%i\n", WEXITSTATUS(status));
fflush(stdout);
fclose(stdout);
return 0;
}

Rewrote the algorithm and it worked!
In the first version, many unnecessary forks were made. For example, if 6 were intended it created 12.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
// #define DBG(args...) fprintf(stderr, args)
#define DBG(args...)
int main(int argc, char* argv[])
{
int status;
pid_t first_pid;
pid_t pid = fork();
if (pid != 0) {
wait(&status);
printf("%i\n", WEXITSTATUS(status));
return 0;
}
for (int i = 0; i < 256; ++i) {
char str[4097];
if (scanf("%s", str) == EOF) {
DBG("PID %i\n", pid);
exit(0);
}
pid = fork();
if (pid != 0)
break;
}
DBG("PID %i waiting\n", pid);
wait(&status);
exit(WEXITSTATUS(status) + 1);
}

Related

Taking an exact number of bytes from input in C and synchronization between processes

Hi i need to take only 5 bytes from stdin, i've tried this but i have problem while executing it since it keeps asking me for input and at the end the string contained in buffer is wrong.
Also i'd like to know how to synchronize N processes while the parent is sleeping.
buffers[] is an array of buffers.
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fflush(stdin) while (getchar() != '\n')
char **filenames;
int *files;
char **buffers;
int n_proc;
int main(int argc, char **argv) {
long i;
pid_t pid;
int status;
if(argc < 2) {
puts("Usage error: prog file1 ... fileN.\n");
exit(1);
}
filenames = argv + 1;
n_proc = argc - 1;
puts("Bef malloc buff.\n");
if((buffers = malloc(sizeof(char *) * n_proc)) == NULL) {
puts("Buffers' malloc error.\n");
exit(1);
}
if((files = malloc(sizeof(int) * n_proc)) == NULL) {
puts("Files' malloc error.\n");
exit(1);
}
puts("After malloc buff.\n");
for(i = 0; i < n_proc; i++) {
if((files[i] = open(filenames[i], O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
printf("Error while opening file %ld.\n", i);
exit(1);
}
}
puts("After file open.\n");
for(i = 0; i < n_proc; i++) {
if((buffers[i] = (char *) mmap(NULL, 1028, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0)) == NULL) {
printf("Error in mapping buffer %ld.\n", i);
exit(1);
}
}
puts("After mapping.\n");
i = 0;
while(i < n_proc) {
printf("Fork %ld started.\n", i);
pid = fork();
if(pid < 0) {
printf("Error while forking %ld.\n", i);
exit(1);
} else if(pid == 0) {
puts("Please insert an input of max 5 characters.\n");
printf("Son %ld.\n", i);
fflush(stdout);
fgets(buffers[i], 6, stdin);
buffers[i][strcspn(buffers[i], "\n")] = 0;
//int j;
//for(j = 0; j < 5; j++)
//buffers[i][j] = getchar();
//printf("Buff has %s inside.\n", buff);
//fflush(stdout);
fflush(stdin);
//strcpy(buffers[i], buff);
printf("Buffer %d has string %s inside.\n", i, buffers[i]);
fflush(stdout);
write(files[i], buffers[i], 6);
} else {
printf("Parent %ld.\n", i);
wait(&status);
}
i++;
}
}
This is only a prototype of the code, since there's still synchronization needed and signal handling
Code requires when to write on command line N files and creating N processes that each take 5 bytes from stdin and put in their own file.
As an example if i try with
./a.out hello.txt hello1.txt
Bef malloc buff.
After malloc buff.
After file open.
After mapping.
Fork 0 started.
Parent 0.
Please insert an input of max 5 characters.
Son 0.
Hello
Hello
Buffer 0 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.
Son 1.
Hello
Hello
Buffer 1 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.
Son 1.
As you can see it doesn't take the input and keeps asking for it, same problem with the getchar().
Note that in case stdin is associated with a terminal, there may also be input buffering in the terminal driver, entirely unrelated to stdio buffering. (Indeed, normally terminal input is line buffered in the kernel.) This kernel input handling can be modified using calls like tcsetattr(3); (stdin(3) man page)
If you give it the input "12345\n":
#include <stdio.h>
int main(void) {
char buffers[1][5];
unsigned i = 0;
for(unsigned j = 0; j < 5; j++)
buffers[i][j] = getchar();
printf("%.5s", buffers[i]);
// read the newline. You may need to discard others.
int ch = getchar();
if(ch == '\n')
printf("\n");
return 0;
}
it will print:
12345

why I'm not getting the stdout result from the child process

I have two programs: Program "Vanilla", and program "verB".
My instructions are that the main process will deal with I\O from the user, and the child will call execve() and run the "Vanilla" process. To accomplish this, I have to use dup2() to replace stdin\stdout on both pipes. (The Vanilla program should use fgets() to read from the pipe).
Inside the "Vanilla" program I read two strings from the user until ctrl+D is pressed, Vanilla calls "xorMethod()" which is doing something (not relevant what) and returns a result.
When I run the "verB" program on Linux(), I only get the "Please insert first, the second string" and then nothing happens and the program stops running.
I want that the parent will continue getting two strings until ctrl+D is pressed, and print the result that he got from his child on the screen.
Vanilla.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Vanila.h"
#include "xor.h"
#define MAXLEN 80
int main()
{
char s1[MAXLEN + 1];
char s2[MAXLEN + 1];
while (!feof(stdin))
{
if (readString(s1) == -1)
break;
if (readString(s2) == -1)
break;
fflush(stdin);
int res = xorMethod(s1, s2);
printf("%s xor %s = %d", s1, s2, res);
}
return 1;
}
int readString(char * string)
{
if ((fgets(string, MAXLEN + 1, stdin) < 0 || feof(stdin)))
return -1;
string[strcspn(string, "\n")] = 0;
return 1;
}
verB.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Vanila.h"
#define MAXLEN 80
int readStr(char * string);
int main()
{
int pipeToChild[2];
int pipeToParent[2];
char * argv[] = { "./Vanilla",NULL };
if (pipe(pipeToChild) == -1)
return -1;
if (pipe(pipeToParent) == -1)
return -1;
pid_t pid = fork();
if (pid == -1)
return -1;
if (pid == 0) //CHILD proccess
{
close(pipeToChild[0]);
close(pipeToParent[1]);
dup2(pipeToChild[0], fileno(stdin));
dup2(pipeToParent[1], fileno(stdout));
execve(argv[0], argv, NULL);
}
else
{
char string1[MAXLEN + 1];
char string2[MAXLEN + 1];
char result[MAXLEN + 1];
close(pipeToChild[0]);
close(pipeToParent[1]);
while (!feof(stdin))
{
printf("Please insert first string : ");
if (readStr(string1) == -1)
return -1;
printf("Please insert second string : ");
if (readStr(string2) == -1)
return -1;
write(pipeToChild[1], string1, strlen(string1));
write(pipeToChild[1], string2, strlen(string2));
read(pipeToParent[0], &result, MAXLEN);
printf("%s\n", result);
}
wait(NULL);
}
return 1;
}
int readStr(char * string)
{
if ((fgets(string, MAXLEN + 1, stdin) < 0 || feof(stdin)))
return -1;
string[strcspn(string, "\n")] = 0;
return 1;
}
You close the wrong ends of the pipes in the child process. You close the read end of pipeToChild and then dup2 the standard input stream, so you child program will have a closed standard input stream. You should close the write end of pipeToChild and the read end of pipeToParent in the child process, and the other way around in the main process:
if (pid == 0) //CHILD proccess
{
close(pipeToChild[1]);
close(pipeToParent[0]);
/* ... */
else //PARENT
{
close(pipeToChild[0]);
close(pipeToParent[1]);

When using fork, scanf in parent reads input twice

When program is reading input from file like this ./a.out < inputFile after fork all input is printed twice to output like there would be no exit(0) in child of fork. My expectation was that everything would be printed only once, since program is only printing in parent, not child. Why does that happen?
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <wait.h>
int main() {
char currentChar;
int counter = 0;
while (scanf("%c", &currentChar) != EOF) {
printf("%c", currentChar);
fflush(stdout);
counter++;
if (counter == 10) {
// all characters after 10 characters are printed twice
int pid = fork();
if (pid == 0) {
// child;
exit(0);
} else {
// parent;
int status;
waitpid(pid, &status, 0);
}
}
}
return 0;
}

Piping between two programs in C

I've been stuck on getting piping to work between two programs for the last couple of hours and I'm stuck and not sure if I'm doing something wrong. The idea of my program is that I'm going to use interface.c to open a pipe, and then execute db.c. I want to use two pipes to communicate between the two different programs. Now, with interface.c being the 'parent' and db.c being the 'child', I'm not sure if I'm passing in the parameters to my pipe correctly via the execl command. Everything compiles correctly, but when I try to run the interface program, I'm getting an error stating: 'Bad File Number.' Is it possible that I'm not using pipes correctly? Currently, I'm just trying to get my program to send an integer, value, over the pipe to db.c. Any help would be much appreciated.
Code for interface.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
//PIPES:
//
//Parent: reads from P1_READ, writes on P1_WRITE
//Child: reads from P2_READ, writes on P2_WRITE
#define P1_READ 0
#define P2_WRITE 1
#define P2_READ 2
#define P1_WRITE 3
// the total number of pipe *pairs* we need
#define NUM_PIPES 2
int main(int argc, char *argv[])
{
//Create Pipe Array
int fd[2*NUM_PIPES];
//For Parameter Passing:
char param0[20]; //P1_Read
char param1[20]; //P2_Write
char param2[20]; //P2_Read
char param3[20]; //P1_Write
snprintf(param0, sizeof(param0), "%d" , fd[0]);
snprintf(param1, sizeof(param1), "%d" , fd[1]);
snprintf(param2, sizeof(param2), "%d" , fd[2]);
snprintf(param3, sizeof(param3), "%d" , fd[3]);
//Variables
pid_t pid;
int val = 42;
//Allocate the PIPES
for (int i=0; i<NUM_PIPES; ++i)
{
if(pipe(fd+(i*2)) < 0)
{
perror("Failed to allocate the pipes");
exit(EXIT_FAILURE);
}
}
//If the fork of the program does not work:
if ((pid = fork()) < 0)
{
perror("Failed to fork process");
return EXIT_FAILURE;
}
if(pid == 0)
{ //Child Process
execl("./db", "db", param0, param1, param2, param3, (char *)NULL);
}
else
{ //Parent Process
//SENDING VALUES HERE
close(fd[P2_READ]);
close(fd[P2_WRITE]);
printf("Interface is sending|%d| to DB\n", val);
if(write(fd[P1_WRITE],&val, sizeof(val)) != sizeof(val))
{
perror("Interfae failed to send value to DB");
exit(EXIT_FAILURE);
}
}
return 0;
}
This is for db.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
//Typedef-Class-
typedef struct Information
{
int accountId;
int checkNumber;
int date;
float amount;
} Information;
int main(int argc, char *argv[])
{
//For Input
//Account Data
Information acctData[25];
int dataStorageLooper = 0; //How many db entries
//For File Input
int aVal;
int bVal;
int cVal;
float dVal;
//Prepare for file input:
FILE * fp;
fp = fopen ("accountData.txt", "r");
//Reads Input
while(1)
{
if (fscanf(fp, "%d %d %d %f", &aVal, &bVal, &cVal, &dVal)!=4)
{
break;
}
//Puts data into appropriate arrays
acctData[dataStorageLooper].accountId= aVal;
acctData[dataStorageLooper].checkNumber= bVal;
acctData[dataStorageLooper].date= cVal;
acctData[dataStorageLooper].amount= dVal;
dataStorageLooper++;
}
//Decrement index to point to last item
dataStorageLooper--;
//Displays all values
printf("\nDisplaying AccountData.txt\n");
for( int i = 0; i < dataStorageLooper; i++)
{
printf("Line|%d|: Account|%d|: Check|%d|: Date|%d|: Amount|%.2f|\n",i,acctData[i].accountId,acctData[i].checkNumber,acctData[i].date,acctData[i].amount);
}
//Closes File
fclose(fp);
//End Input
//Parameter Receiving:
int pipes[4]; //Pipe Array
int value = 7;
int test;
//Build the pipes
pipes[0] = atoi(argv[1]); //P1_Read
pipes[1] = atoi(argv[2]); //P2_Write
pipes[2] = atoi(argv[3]); //P2_Read
pipes[3] = atoi(argv[4]); //P1_Write
//Troubleshooting
printf("The number of parameters: %d\n",argc);
printf("Parameter 1: %s\n", argv[0]);
printf("I stared correctly\n");
//Testing
close(pipes[0]);
close(pipes[3]);
//SHOULD RECEIVE VALUE HERE
test = read(pipes[2], &value, sizeof(value));
if (test < 0)
{
perror("DB: Failed to read data from parent");
exit(EXIT_FAILURE);
}
else if (test == 0)
{
//Unexpected
fprintf(stderr, "DB: Read End-Of-File from pipe");
}
else
{
//What did the child receive?
printf("DB: Received Value:(%d)\n", value);
}
close(pipes[2]);
close(pipes[1]);
return 0;
}
One of the things you're doing wrong is snprintfing the value of the various elements in fd before you've assigned any value to them. That's undefined behaviour, and the values you're passing as parameters are totally meaningless (at best).
This strikes me as a very odd way to do things, though. Usually you would just dup2 fds 0 and 1 so that the child's stdin and stdout are redirected to the appropriate pipe fds.

parent send command line arguments to child

I am writing a program that creates a pipe, forks, then the parent sends the command line arguments to the child one char at a time. The child is supposed to count them, and then the parent reaps the child and prints out how many arguments there were. Here is what I have so far:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
pid_t pid;
int status;
int comm[2];
char buffer[BUFSIZ];
// set up pipe
if (pipe(comm)) {
printf("pipe error\n");
return -1;
}
// call fork()
pid = fork();
// fork failed
if (pid < 0) {
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
// -- running in child process --
int nChars = 0;
close(comm[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
while(read(comm[0], buffer, sizeof(buffer)) != '\n')
nChars++;
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
close(comm[0]);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
char endl='\n';
for (int a = 1; a < argc; a++) {
for (int c = 0; c < strlen(argv[a]); c++) {
write(comm[1], &argv[a][c], 1);
}
}
write(comm[1], &endl, 1);
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
waitpid(pid, &status, 0);
printf("child counted %d chars\n", nChars);
return 0;
}
}
It seems to run endlessly. It must be stuck in one of the loops. What is going wrong?
Code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *argv[])
{
pid_t pid;
int status;
int comm[2];
char buffer[BUFSIZ];
// set up pipe
if (pipe(comm) < 0) {
printf("pipe error\n");
return -1;
}
// call fork()
if((pid = fork()) <0)
{
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
// -- running in child process --
int nChars = 0;
close(comm[1]);
//printf("%d \n",BUFSIZ);
// Receive characters from parent process via pipe
// one at a time, and count them.
int n;
while( (n =read(comm[0], buffer, BUFSIZ)) >0)
{
buffer[n] = 0;
int oneChar, i = 0,endflag = 0;
while((oneChar = buffer[i])!=0)
{
// printf("%d\n",oneChar);
if(oneChar!=EOF)
nChars++;
else
{
endflag = 1;
break;
}
i++;
}
//printf("%s\n",buffer);
if(endflag)
break;
}
printf("nChar : %d",nChars);
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
//int nChars = 0;
close(comm[0]);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
int a,c;
char endl='\n';
for ( a = 1; a < argc; a++) {
for ( c = 0; c < strlen(argv[a]); c++) {
write(comm[1], &argv[a][c], 1);
}
}
printf("write end\n");
int end = EOF;
write(comm[1],&end,4);
waitpid(pid, &status, 0);
printf("child counted %d chars\n", WEXITSTATUS(status));
return 0;
}
}

Resources