Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _GNU_SOURCE
- #include <stdlib.h>
- #include <stdio.h>
- #include <signal.h>
- #include <time.h>
- #include <sys/wait.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #define ERR(source) (fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
- perror(source),kill(0,SIGKILL),\
- exit(EXIT_FAILURE))
- #define CHILDREN_COUNT 3
- #define CHILD_DELAY_MIN 3
- #define CHILD_DELAY_MAX 7
- #define BLOCK_SIZE 3000
- void usage(char *name) {
- fprintf(stderr,"USAGE: %s t1 t2 t3\n",name);
- fprintf(stderr,"200 <= t1, t2, t3 <= 250\n");
- exit(EXIT_FAILURE);
- }
- void shuffle(int *array, size_t n)
- {
- if (n > 1)
- {
- size_t i;
- for (i = 0; i < n - 1; i++)
- {
- size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
- int t = array[j];
- array[j] = array[i];
- array[i] = t;
- }
- }
- }
- void setHandler(int signal, void (*handler)(int)) {
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = handler;
- if (sigaction(signal, &action, NULL) == -1)
- ERR("sigaction");
- }
- volatile sig_atomic_t childrenLeft = 0;
- void handleZombie() {
- while (1) {
- pid_t pid = waitpid(0, NULL, WNOHANG);
- if (pid < 0) {
- if (errno == ECHILD)
- return;
- ERR("waitpid");
- }
- if (pid == 0)
- return;
- childrenLeft--;
- }
- }
- void generateRandomLettersBlock(char *buffer, ssize_t size) {
- int i,
- alphabetLength = 'Z' - 'A' + 1;
- for (i=0; i < size-1; i++)
- buffer[i] = 'A' + rand() % alphabetLength;
- buffer[size - 1] = '\0';
- }
- ssize_t bulkWrite(int fd, char *buf, size_t count) {
- ssize_t bytesWritten = 0;
- ssize_t totalBytesWritten = 0;
- while (count > 0) {
- bytesWritten = TEMP_FAILURE_RETRY(write(fd, buf, count));
- if (bytesWritten < 0)
- return bytesWritten;
- totalBytesWritten += bytesWritten;
- buf += bytesWritten;
- count -= bytesWritten;
- }
- return totalBytesWritten;
- }
- volatile sig_atomic_t signalsReceived[CHILDREN_COUNT];
- void handleSignal(int signal) {
- int i;
- for (i=CHILDREN_COUNT-1; i > 0; --i)
- signalsReceived[i] = signalsReceived[i-1];
- signalsReceived[0] = signal;
- }
- void childTimeout() {
- printf("[%d] terminates by alarm\n", getpid());
- exit(EXIT_SUCCESS);
- }
- void childWorker(int t, int signalToSend) {
- srand(getpid());
- int s = CHILD_DELAY_MIN + rand() % (CHILD_DELAY_MAX - CHILD_DELAY_MIN + 1);
- printf("[%d] s = %d, t = %d, signalToSend = %d\n", getpid(), s, t, signalToSend);
- setHandler(SIGALRM, childTimeout);
- alarm(s);
- struct timespec timeLeft;
- while (1) {
- timeLeft.tv_sec = 0;
- timeLeft.tv_nsec = t * 1000 * 1000;
- while (nanosleep(&timeLeft, &timeLeft) != 0)
- continue;
- printf("[%d] sends %d\n", getpid(), signalToSend);
- kill(getppid(), signalToSend);
- }
- }
- void parentWorker(int signalsToReceive[], char *outputFileName) {
- srand(getpid());
- // Set SIG_BLOCK on signals to receive
- sigset_t blockMask, oldMask;
- sigemptyset(&blockMask);
- int i;
- for (i=0; i < CHILDREN_COUNT; i++)
- sigaddset(&blockMask, signalsToReceive[i]);
- if (sigprocmask(SIG_BLOCK, &blockMask, &oldMask) != 0)
- ERR("sigprocmask");
- // Add handlers for those signals
- for (i=0; i < CHILDREN_COUNT; i++)
- setHandler(signalsToReceive[i], handleSignal);
- // Shuffle signals to receive array
- shuffle(signalsToReceive, CHILDREN_COUNT);
- printf("[PARENT=%d] started\n", getpid());
- for (i=0; i < CHILDREN_COUNT; i++)
- printf("[PARENT=%d] %d signal to receive = %d\n", getpid(), i+1, signalsToReceive[i]);
- char *buffer = malloc((BLOCK_SIZE + 2) * sizeof(char));
- if (buffer == NULL)
- ERR("malloc");
- int outputFd = TEMP_FAILURE_RETRY(open(outputFileName, O_WRONLY | O_CREAT | O_TRUNC, 0777));
- if (outputFd < 0)
- ERR("open");
- while (childrenLeft > 0) {
- sigsuspend(&oldMask);
- int unmatchedSignal = 0;
- for (i=0; i < CHILDREN_COUNT; i++) {
- if (signalsReceived[i] != signalsToReceive[i]) {
- unmatchedSignal = 1;
- break;
- }
- }
- printf("[PARENT=%d] last signals: %d", getpid(), signalsReceived[0]);
- for (i=1; i < CHILDREN_COUNT; i++)
- printf(", %d", signalsReceived[i]);
- printf("\nRequested order: %d", signalsToReceive[0]);
- for (i=1; i < CHILDREN_COUNT; i++)
- printf(", %d", signalsToReceive[i]);
- printf("\n");
- if (!unmatchedSignal) {
- // Signals match
- printf("[PARENT=%d] signals match\n", getpid());
- generateRandomLettersBlock(buffer, BLOCK_SIZE+1);
- printf("[PARENT=%d] random letters block:\n", getpid());
- printf("%s", buffer);
- bulkWrite(outputFd, buffer, BLOCK_SIZE);
- }
- }
- if (TEMP_FAILURE_RETRY(close(outputFd)) == -1)
- ERR("close");
- free(buffer);
- }
- int main(int argc, char **argv) {
- if (argc != CHILDREN_COUNT+2)
- usage(argv[0]);
- int t[CHILDREN_COUNT],
- i,
- signalsToSend[CHILDREN_COUNT] = { 10, 12, 16 };
- for (i=0; i < CHILDREN_COUNT; i++) {
- t[i] = atoi(argv[i+1]);
- if (t[i] < 200 || t[i] > 250)
- usage(argv[0]);
- }
- char *outputFileName = argv[CHILDREN_COUNT+1];
- setHandler(SIGCHLD, handleZombie);
- for (i=0; i < CHILDREN_COUNT; i++)
- setHandler(signalsToSend[i], SIG_IGN);
- for (i=0; i < CHILDREN_COUNT; i++) {
- pid_t pid = fork();
- if (pid < 0)
- ERR("fork");
- if (pid == 0)
- childWorker(t[i], signalsToSend[i]);
- }
- childrenLeft = CHILDREN_COUNT;
- // Parent
- parentWorker(signalsToSend, outputFileName);
- while (wait(NULL) > 0)
- continue;
- printf("[PARENT=%d] terminates\n", getpid());
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement