Last active
May 8, 2017 02:55
-
-
Save himanshugoel2797/e895226581e3169bdbdf107ecc17501f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //Fork, setup shared buffer, signals to notify of buffer activity. When everything is finished, main process outputs table, child exits. | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <stdbool.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/sem.h> | |
| #include <sys/shm.h> | |
| #include <sys/ipc.h> | |
| #include <sys/signal.h> | |
| #include <sys/wait.h> | |
| #include <unistd.h> | |
| #define PROD_SEM 0 | |
| #define CONS_SEM 1 | |
| #define PROD_SIG (SIGUSR1) | |
| #define CONS_SIG (SIGUSR2) | |
| static char *buffer_base; | |
| static char *buffer; | |
| static char *progress_buffer = NULL; | |
| static char *progress_cursor = NULL; | |
| static key_t semaphore; | |
| static pid_t cons_pid = 0, prod_pid = 0, parent_pid = 0; | |
| static size_t iFileLen = 0; | |
| int sem_up(int idx) { | |
| struct sembuf op; | |
| op.sem_num = idx; | |
| op.sem_op = 1; | |
| op.sem_flg = 0; | |
| return semop(semaphore, &op, 1); | |
| } | |
| int sem_down(int idx) { | |
| struct sembuf op; | |
| op.sem_num = idx; | |
| op.sem_op = -1; | |
| op.sem_flg = 0; | |
| return semop(semaphore, &op, 1); | |
| } | |
| void producer_signal(int sig) { | |
| *(progress_cursor++) = 'P'; | |
| } | |
| void consumer_signal(int sig) { | |
| *(progress_cursor++) = 'C'; | |
| } | |
| int producer_proc(FILE *iFile){ | |
| for(size_t i = 0; i < iFileLen; i++) { | |
| char nChar = 0; | |
| fread(&nChar, 1, 1, iFile); | |
| usleep((rand() % 3 + 1) * 100000); | |
| sem_down(CONS_SEM); | |
| //Submit the character | |
| *(buffer++) = nChar; | |
| sem_up(PROD_SEM); | |
| kill(parent_pid, SIGUSR1); | |
| } | |
| fclose(iFile); | |
| return 0; | |
| } | |
| int consumer_proc(FILE *oFile){ | |
| for(size_t i = 0; i < iFileLen; i++) { | |
| usleep((rand() % 3 + 1) * 100000); | |
| sem_down(PROD_SEM); | |
| char nChar = *(buffer++); | |
| sem_up(CONS_SEM); | |
| kill(parent_pid, SIGUSR2); | |
| fwrite(&nChar, 1, 1, oFile); | |
| } | |
| fclose(oFile); | |
| return 0; | |
| } | |
| int main(int argc, char *argv[]) { | |
| bool showHelp = false; | |
| if(argc != 3) | |
| showHelp = true; | |
| if(argc > 1 && strcmp(argv[1], "-h") == 0) | |
| showHelp = true; | |
| if(!showHelp) { | |
| FILE *iFile = fopen(argv[1], "rb"); | |
| FILE *oFile = fopen(argv[2], "wb"); | |
| fseek(iFile, 0, SEEK_END); | |
| iFileLen = ftell(iFile); | |
| fseek(iFile, 0, SEEK_SET); | |
| if(iFile == NULL) | |
| { | |
| printf("Failed to open input file.\n"); | |
| return 0; | |
| } | |
| if(oFile == NULL) | |
| { | |
| printf("Failed to open output file.\n"); | |
| return 0; | |
| } | |
| //Setup shared memory region | |
| int ident = shmget(IPC_PRIVATE, iFileLen, IPC_CREAT | 0666); | |
| if(ident < 0) { | |
| perror("Shared memory allocation failed"); | |
| return 0; | |
| } | |
| //Initialize the semaphores | |
| semaphore = semget(IPC_PRIVATE, 2, IPC_CREAT | 0666); | |
| semctl(semaphore, PROD_SEM, SETVAL, 0); | |
| semctl(semaphore, CONS_SEM, SETVAL, iFileLen); | |
| //Setup shared memory | |
| buffer = buffer_base = shmat(ident, NULL, 0); | |
| if((int)buffer == -1){ | |
| perror("shmat Failed."); | |
| return 0; | |
| } | |
| //Allocate progress buffer | |
| progress_cursor = progress_buffer = calloc(iFileLen * 2 + 1, sizeof(char)); | |
| //setup signal handlers | |
| signal(PROD_SIG, producer_signal); | |
| signal(CONS_SIG, consumer_signal); | |
| //Get the parent process pid | |
| parent_pid = getpid(); | |
| //Fork processes | |
| cons_pid = fork(); | |
| //Create consumer | |
| if(cons_pid == 0) { | |
| fclose(iFile); | |
| consumer_proc(oFile); | |
| }else{ | |
| //Create producer | |
| prod_pid = fork(); | |
| if(prod_pid == 0) { | |
| fclose(oFile); | |
| producer_proc(iFile); | |
| } | |
| } | |
| shmdt(buffer); | |
| //Following only runs in the parent process | |
| if(cons_pid != 0 && prod_pid != 0) { | |
| //TODO: Wait for both processes to exit | |
| int status = 0; | |
| int cnt = 0; | |
| while(true) { | |
| pid_t pid = waitpid(-1, &status, 0); | |
| if(errno == ECHILD) { | |
| cnt++; | |
| errno = 0; | |
| } | |
| if(cnt >= 2) | |
| break; | |
| } | |
| shmctl(ident, IPC_RMID, 0); | |
| semctl(semaphore, IPC_RMID, 0); | |
| printf("%s\n", progress_buffer); | |
| } | |
| free(progress_buffer); | |
| printf("Exit "); | |
| if(cons_pid == 0) | |
| printf("Consumer\n"); | |
| else if(prod_pid == 0) | |
| printf("Producer\n"); | |
| else | |
| printf("Parent\n"); | |
| }else { | |
| printf("%s [input file] [output file]\r\n", argv[0]); | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment