Пример #1
0
int pipes_close_chain(struct pipes_chain chain[]) {
	int status = 0;

	for (struct pipes_chain *ptr = chain; ptr->argv; ++ ptr) {
		if (pipes_close(&ptr->pipes) != 0) {
			status = -1;
		}
	}

	return status;
}
Пример #2
0
int pipes_open(char const *const argv[], char const *const envp[], struct pipes* pipes) {
	int infd  = -1;
	int outfd = -1;
	int errfd = -1;

	const int inaction  = pipes->infd;
	const int outaction = pipes->outfd;
	const int erraction = pipes->errfd;

	// stdin
	if (inaction == PIPES_PIPE) {
		int pair[] = {-1, -1};
		if (pipe2(pair, O_CLOEXEC) == -1) {
			goto error;
		}

		infd = pair[0];
		pipes->infd = pair[1];
	}
	else if (inaction == PIPES_NULL) {
		infd = open("/dev/null", O_RDONLY);

		if (infd < 0) {
			goto error;
		}
	}
	else if (inaction > -1) {
		infd = inaction;
		pipes->infd = -1;
	}
	else if (inaction == PIPES_TEMP) {
		infd = pipes_temp_fd();
		pipes->infd = infd;

		if (infd < 0) {
			goto error;
		}
	}
	else if (inaction != PIPES_LEAVE) {
		errno = EINVAL;
		goto error;
	}

	// stdout
	if (outaction == PIPES_PIPE) {
		int pair[] = {-1, -1};
		if (pipe2(pair, O_CLOEXEC) == -1) {
			goto error;
		}

		pipes->outfd = pair[0];
		outfd = pair[1];
	}
	else if (outaction == PIPES_NULL) {
		outfd = open("/dev/null", O_WRONLY);

		if (outfd < 0) {
			goto error;
		}
	}
	else if (outaction == PIPES_TO_STDOUT || outaction == PIPES_TO_STDERR) {
		// see below
	}
	else if (outaction > -1) {
		outfd = outaction;
		pipes->outfd = -1;
	}
	else if (outaction == PIPES_TEMP) {
		outfd = pipes_temp_fd();
		pipes->outfd = outfd;

		if (outfd < 0) {
			goto error;
		}
	}
	else if (outaction != PIPES_LEAVE) {
		errno = EINVAL;
		goto error;
	}

	// stderr
	if (erraction == PIPES_PIPE) {
		int pair[] = {-1, -1};
		if (pipe2(pair, O_CLOEXEC) == -1) {
			goto error;
		}

		pipes->errfd = pair[0];
		errfd = pair[1];
	}
	else if (erraction == PIPES_NULL) {
		errfd = open("/dev/null", O_WRONLY);

		if (errfd < 0) {
			goto error;
		}
	}
	else if (erraction == PIPES_TO_STDOUT || erraction == PIPES_TO_STDERR) {
		// see below
	}
	else if (erraction > -1) {
		errfd = erraction;
		pipes->errfd = -1;
	}
	else if (erraction == PIPES_TEMP) {
		errfd = pipes_temp_fd();
		pipes->errfd = errfd;

		if (errfd < 0) {
			goto error;
		}
	}
	else if (erraction != PIPES_LEAVE) {
		errno = EINVAL;
		goto error;
	}

	pid_t pid = fork();

	if (pid == -1) {
		goto error;
	}

	if (pid == 0) {
		// child

		// close unused ends
		if (pipes->infd > -1 && pipes->infd != infd) {
			close(pipes->infd);
			pipes->infd = -1;
		}

		if (pipes->outfd > -1 && pipes->outfd != outfd) {
			close(pipes->outfd);
			pipes->outfd = -1;
		}

		if (pipes->errfd > -1 && pipes->errfd != errfd) {
			close(pipes->errfd);
			pipes->errfd = -1;
		}

		pipes_redirect_fd(infd, STDIN_FILENO, "redirecting stdin");

		if (outaction == PIPES_TO_STDERR) {
			if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1) {
				perror("redirecting stdout");
				exit(EXIT_FAILURE);
			}
		}
		else {
			pipes_redirect_fd(outfd, STDOUT_FILENO, "redirecting stdout");
		}

		if (erraction == PIPES_TO_STDOUT) {
			if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) {
				perror("redirecting stderr");
				exit(EXIT_FAILURE);
			}
		}
		else {
			pipes_redirect_fd(errfd, STDERR_FILENO, "redirecting stderr");
		}

		if (envp) {
			environ = (char**)envp;
		}

		if (execvp(argv[0], (char * const*)argv) == -1) {
			perror(argv[0]);
		}
		exit(EXIT_FAILURE);
	}
	else {
		// parent
		pipes->pid = pid;

		if (inaction  != PIPES_TEMP && infd  > -1) close(infd);
		if (outaction != PIPES_TEMP && outfd > -1) close(outfd);
		if (erraction != PIPES_TEMP && errfd > -1) close(errfd);
	}

	return 0;

error:
	pipes->pid = -1;

	int errnum = errno;

	if (infd  > -1) close(infd);
	if (outfd > -1) close(outfd);
	if (errfd > -1) close(errfd);

	pipes_close(pipes);

	if (errnum != 0) {
		errno = errnum;
	}

	return -1;
}
Пример #3
0
int main(int argc, char **argv)
{
    if (argc < 3)
        err_quit("wrong number of parameters");

    GraphData *data;
    Pipe *red_pipe, **blue_pipe;

    int st, fail, i, j, r, b, **vmatrix, mark, red_balance, msg_balance;
    int sem[2], monster_pipe[2];
    pid_t *blue_pids;
    pid_t *red_pids;
    pid_t monster_pid, pid, rpid;

    const int mark_new_msg = 1;
    const int mark_dead_msg = -1;
    const int mark_dead_red = 0;

    data = data_read();

    b = data->b;
    r = data->r;
    vmatrix = data->vmatrix;

    red_pipe = pipes_create(r);
    blue_pipe = blue_pipe_create(data);

    blue_pids = (pid_t*) malloc(sizeof(pid_t) * b);

    //sync pipes
    if (pipe(sem))
        err_sys("sync pipe failed");

    //blue processes
    for (i = 0; i < b; i++) {
        if ((pid = fork()) == 0) {
            Message *msg;
            Message **r_msg, **w_msg;
            Pipe *read_pipe;

            int *redp, redp_num, *isdead;
            int lock, l, k, s;
            int r_num;

            lock = 0;
            redp = (int*) malloc(sizeof(int) * r);
            isdead = (int*) malloc(sizeof(int) * r);
            //closing red pipes
            for (k = 0, j = 0; j < r; j++) {
                if (data->red[j].node == i) {
                    isdead[k] = 0;
                    redp[k++] = red_pipe[j].fd[0];
                    close(red_pipe[j].fd[1]);
                    continue;
                }
                close(red_pipe[j].fd[0]);
                close(red_pipe[j].fd[1]);
            }
            redp_num = k;

            //copy pipes from which we read for faster access
            //and close them for writing, also close other pipes which we don't use in this process
            read_pipe = (Pipe*) malloc(sizeof(Pipe) * data->read_num[i]);
            for (k = 0, j = 0; j < b; j++) {
                if (j == i)
                    continue;
                if (vmatrix[j][i] == 1) {
                    for (lock = -1, l = 0; l < data->write_num[j]; l++)
                        if (blue_pipe[j][l].to == i) {
                            read_pipe[k++] = blue_pipe[j][l];
                            lock = l;
                            break;
                        }
                }
                for (l = 0; l < data->write_num[j]; l++) {
                    if (l == lock) {
                        close(blue_pipe[j][l].fd[1]);
                        continue;
                    }
                    close(blue_pipe[j][l].fd[0]);
                    close(blue_pipe[j][l].fd[1]);
                }
            }

            r_msg = (Message**) calloc(data->read_num[i], sizeof(Message*));
            w_msg = (Message**) calloc(data->write_num[i], sizeof(Message*));

            //don't read from pipes in which we write
            for (j = 0; j < data->write_num[i]; j++)
                close(blue_pipe[i][j].fd[0]);

            //main loop
            while (1) {
                r_num = -1;
                msg = NULL;
                //try to read from red pipes
                for (s = 0, j = 0; j < redp_num; j++)
                    if (!isdead[j] && (msg = message_read(redp[j], &s, NULL)) != NULL) {
                        //if we've received something from red pipe
                        //we have a new packet in network
                        st = write(sem[1], &mark_new_msg, sizeof(int));
                        break;
                    } else if (s == -1) {
                        //eof in pipe, so red is dead, and we will not receive smth from this one
                        st = write(sem[1], &mark_dead_red, sizeof(int));
                        isdead[j] = 1;
                        s = 0;
                    }

                //try to read from blue pipes if nothing was read from red ones
                if (msg == NULL) {
                    for (j = 0; j < data->read_num[i]; j++)
                        if ((msg = message_read(read_pipe[j].fd[0], NULL, r_msg[j])) != NULL) {
                            if (msg->len > msg->sv_r) {
                                r_msg[j] = msg;
                                r_num = j;
                                msg = NULL;
                            } else {
                                r_msg[j] = NULL;
                                debug("full - %d | id: %d", msg->len, msg->id);
                            }
                            break;
                        }
                }

                //try again
                if (msg == NULL) {
                    for (j = 0; msg == NULL && j < data->write_num[i]; j++)
                        if (w_msg[j] != NULL)
                            msg = w_msg[j];

                    if (msg == NULL) {
                        usleep(100);
                        continue;
                    }
                }

                //check the message
                if (!msg->ch) {
                    st = message_check(data, i, msg);
                    fflush(stdout);
                    if (st == MSG_ERROR || st == MSG_END) {
                        //message is dead now
                        st = write(sem[1], &mark_dead_msg, sizeof(int));
                        message_destroy(msg);
                        continue;
                    }
                    //st == MSG_OK
                    //send message
                    for (j = 0; j < data->write_num[i]; j++) {
                        if (blue_pipe[i][j].to == msg->node[0] - 1) {
                            msg->num_w = j;
                            msg->fd[1] = blue_pipe[i][j].fd[1];
                            break;
                        }
                    }

                    j = msg->num_w;
                    if (w_msg[j] != NULL) {
                        Message *cur = w_msg[j];
                        while(cur->next != NULL)
                            cur = cur->next;
                        cur->next = msg;
                        msg = w_msg[j];
                    } else {
                        w_msg[j] = msg;
                    }
                }

                st = message_send(msg->fd[1], msg);
                if (st == 0) {
                    w_msg[msg->num_w] = w_msg[msg->num_w]->next;
                    message_destroy(msg);
                }
            }

            exit(EXIT_SUCCESS);
        } else if (pid == -1) {
            err_sys("failed on %d's blue fork", i);
        }

        blue_pids[i] = pid;
    }

    //close all blue pipes
    for (i = 0; i < b; i++) 
        pipes_close(blue_pipe[i], data->write_num[i]);

    //create red processes
    red_pids = (pid_t*) malloc(sizeof(pid_t) * r);
    for (i = 0; i < r; i++) {
        if ((pid = fork()) == 0) {
            char *filename = data->red[i].filename;
            char *name = argv[1];
            char num_buf[10];
            int pfd = red_pipe[i].fd[1];

            dup2(pfd, 1);
            pipes_close(red_pipe, r);
            close_pipe(sem);

            sprintf(num_buf, "%d", i + 1);
            for (j = strlen(name); j > 0 && name[j] != '/'; j--)
                ;

            execlp(name, name + j + 1, num_buf, filename, NULL);
            err_sys("%d red process exec failed", i);
        } else if (pid == -1) {
            err_sys("%d red process fork failed", i);
        }

        red_pids[i] = pid;
    }

    //close all red pipes
    pipes_close(red_pipe, r);

    //create monster pipe and monster process
    if (pipe(monster_pipe) < 0)
        err_sys("monster pipe failed");
    if ((monster_pid = fork()) == 0) {
        int *pfd = monster_pipe;
        char *name = argv[2];

        dup2(pfd[0], 0);
        close_pipe(sem);
        close_pipe(pfd);

        for (i = strlen(name); i > 0 && name[i] != '/'; i--)
            ;

        execlp(name, name + i + 1, NULL);
        err_sys("monster process exec failed");
    } else if (monster_pid == -1) {
        err_sys("monster process forking failed");
    }
    close(monster_pipe[0]);

    //wait red processes
    for (i = 0; i < r; i++) {
        rpid = wait(&st);

        //check if dead process was red
        //do we need this check or not?
        for (fail = 1, j = 0; j < r; j++)
            if (rpid == red_pids[j])
                fail = 0;
        if (fail) {
            err_quit("an error in blue process has occured, terminating...");
        }
    }

    //wait all packets to reach their destination
    //and all red pipes to be read
    red_balance = r;
    msg_balance = 0;

    while (red_balance || msg_balance) {
        st = read(sem[0], &mark, sizeof(int));
        if (st == 0)
            break;
        if (st == sizeof(int)) {
            if (mark == 0)
                red_balance--;
            else if (mark == 1)
                msg_balance++;
            else if (mark == -1)
                msg_balance--;
            continue;
        }
        err_sys("error in sync pipe");
    }

    //tell monster to kill our children
    st = write(monster_pipe[1], &b, sizeof(int));
    for (i = 0; i < b; i++) {
        st = write(monster_pipe[1], &blue_pids[i], sizeof(int));
    }
    close(monster_pipe[1]);

    //wait him to do his dirty work, ignoring our children deaths
    while (wait(&st) != monster_pid);

    //will close everything that was opened and free everything that was allocated
    return 0;
}