/* This is a personal academic project. Dear PVS-Studio, please check it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com */ #define _SVID_SOURCE 1 #define _XOPEN_SOURCE 500 #define _POSIX_C_SOURCE 2 #include #include #include #include #include #include #include #include "error.h" #include "shr_mem.h" #include #include "master.h" #include "siglib.h" static char viewLinked = 0; int slaveNum; int main(int argc, char *argv[]) { if (setvbuf(stdout, NULL, _IONBF, 0) != 0) printSystemError("setvbuf() -- ERROR"); if (argc == 1) printError("No arguments provided -- ERROR"); slaveNum = floor(log2(argc - 1) * 2); slaveNum = (slaveNum < MAX_SLAVES ? slaveNum : MAX_SLAVES); FILE * outputFile; if ((outputFile = fopen(OUTPUT_NAME, "w")) == NULL) printSystemError("fopen() -- ERROR"); char * shmPointer, * shmStart; int totalSize = (argc - 1) * MAX_OUTPUT_SIZE; int shmFd; printf("%d\n%d\n", argc - 1, getpid()); addSignalHandler(changeViewFlag); sleep(5); blockSignal(); if (viewLinked) { shmFd = createShm(totalSize); mapShm(&shmPointer, totalSize, shmFd); shmStart = shmPointer; } int pipesOutput[slaveNum][2], pipesInput[slaveNum][2]; createPipesAndSlaves(pipesOutput, pipesInput); int tasks = 1; for (int j = 0; tasks <= slaveNum && tasks < argc; tasks++) { if (sendTask(argv[tasks], pipesInput, j++) == 0) continue; } fd_set pipesOutputSet; FD_ZERO(&pipesOutputSet); char buf[MAX_SIZE], notFinished; int r, readBytes, count; if (tasks < slaveNum) { for (int k = tasks - 1; k < slaveNum; k++) { closePipes(pipesInput, pipesOutput, k, &pipesOutputSet); } } do { notFinished = 0; FD_ZERO(&pipesOutputSet); for (int n = 0; n < slaveNum; n++) { if (pipesOutput[n][0] != -1) { FD_SET(pipesOutput[n][0], &pipesOutputSet); notFinished = 1; } } if (notFinished) { if ((count = select(pipesOutput[slaveNum - 1][1] + 1, &pipesOutputSet, NULL, NULL, NULL)) <= 0) printSystemError("select() -- ERROR"); for (r = 0; r < slaveNum && count > 0; r++) { if (FD_ISSET(pipesOutput[r][0], &pipesOutputSet) && pipesOutput[r][0] != -1) { if ((readBytes = read(pipesOutput[r][0], buf, MAX_SIZE - 1)) < 0) printSystemError("read() -- ERROR"); buf[readBytes] = '\0'; shmPointer += writeOutput(buf, outputFile, shmPointer); count--; if (tasks < argc) { if (sendTask(argv[tasks++], pipesInput, r) == 0) continue; } else { closePipes(pipesInput, pipesOutput, r, &pipesOutputSet); } } } } } while (notFinished); if (fclose(outputFile) == EOF) printSystemError("fclose() -- ERROR"); if (viewLinked) { waitForSignal(); terminateShm(SHM_NAME, shmFd, shmStart, totalSize); } return EXIT_SUCCESS; } void changeViewFlag() { viewLinked = 1; } char sendTask(char * fileName, int pipesInput[slaveNum][2], int slave) { struct stat statBuf; if (stat(fileName, &statBuf) == -1) printSystemError("Error, one of the specified paths is incorrect"); if (!S_ISREG(statBuf.st_mode)) return EXIT_FAILURE; if ((write(pipesInput[slave][1], fileName, strlen(fileName) + 1)) < 0) printSystemError("write() -- ERROR"); return EXIT_SUCCESS; } void closePipes(int pipesInput[][2], int pipesOutput[][2], int slave, fd_set * set) { FD_CLR(pipesOutput[slave][0], set); if (close(pipesOutput[slave][0]) < 0) printSystemError("close1() -- ERROR"); if (close(pipesInput[slave][1]) < 0) printSystemError("close2() -- ERROR"); pipesOutput[slave][0] = -1; pipesInput[slave][0] = -1; } int writeOutput(char * output, FILE * outputFile, char * shmPointer) { int length = strlen(output); if (fwrite(output, sizeof(char), length, outputFile) != length) printSystemError("fwrite() -- ERROR"); if (viewLinked) writeShm(shmPointer, output, length); return length; } void createPipesAndSlaves(int pipesOutput[slaveNum][2], int pipesInput[slaveNum][2]) { pid_t pid[slaveNum]; for (int i = 0; i < slaveNum; i++) { if (pipe(pipesOutput[i]) < 0) printSystemError("pipe() -- ERROR"); if (pipe(pipesInput[i]) < 0) printSystemError("pipe() -- ERROR"); if ((pid[i] = fork()) == 0) { if (close(pipesOutput[i][0]) < 0) printSystemError("close() -- ERROR"); if (dup2(pipesOutput[i][1], STDOUT_FILENO) < 0) printSystemError("dup2() -- ERROR 1"); if (close(pipesOutput[i][1]) < 0) printSystemError("close() -- ERROR"); if (close(pipesInput[i][1]) < 0) printSystemError("close() -- ERROR"); if (dup2(pipesInput[i][0], STDIN_FILENO) < 0) printSystemError("dup2() -- ERROR 2"); if (close(pipesInput[i][0]) < 0) printSystemError("close() -- ERROR"); char * params[] = {"slave.o", NULL}; if (execv("slave.o", params) < 0) printSystemError("execv() -- ERROR"); } else if (pid[i] < 0) printSystemError("fork() -- ERROR"); if (close(pipesInput[i][0]) < 0) printSystemError("close() -- ERROR"); if (close(pipesOutput[i][1]) < 0) printSystemError("close() -- ERROR"); } }