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; }
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; }
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; }