Skip to content

Instantly share code, notes, and snippets.

@himanshugoel2797
Last active May 8, 2017 02:55
Show Gist options
  • Select an option

  • Save himanshugoel2797/e895226581e3169bdbdf107ecc17501f to your computer and use it in GitHub Desktop.

Select an option

Save himanshugoel2797/e895226581e3169bdbdf107ecc17501f to your computer and use it in GitHub Desktop.
//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