/* -------------------------- loader.c ----------------------- */
/* This is the shell for developing the loader cpu and printer */
/* for csc 389 project */
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/shm.h>
#define SLEEP_INC 1
#define BADADDR (char *)(-1) /* used in getting shared memeory */
#define NUM_OF_SEMS 8 /* the number of sems to create */
#define OK_TO_LOAD0 0
#define OK_TO_LOAD1 1
#define OK_TO_EXEC0 2
#define OK_TO_EXEC1 3
#define OK_TO_SET_OUTPUT0 4
#define OK_TO_SET_OUTPUT1 5
#define OK_TO_PRINT0 6
#define OK_TO_PRINT1 7
#define HOWMANY_PROCESSES 3
#define HOWMANY_JOBS 2
#define MALLOC(x) ((x *) malloc(sizeof(x)))
#define CLR system("clear")
#define TRUE 1
#define FALSE 0
int my_semid, my_shrmemid; /* semaphore id and shared memory ids */
int my_key; /* key used to get shared memory */
int my_semval;
char *my_shrmemaddr; /* address of shared memory */
typedef struct _pcb
{ int start_loc, num_instructions, output_loc;}
pcb_type;
typedef struct _mem
{ char operation; int operand1, operand2, result;}
memory_type;
int * load_job, *print_job;
pcb_type *pcbs;
memory_type *memory;
int size_of_memory;
int s, i;
char input[100]; /* print to file or print to screen */
char str1[100];
char str2[100];
FILE
*f
= fopen("cpu.output", "w");
/* functions to be invoked later */
void V(); /*release semaphore */
static void semcall(); /* call semop */
void P(); /* acquire semaphore */
void init_sem(); /* initialize semaphores */
void syserr(); /* print error messages */
void remove_shrmem(); /* remove shared memory */
void remove_sem(); /* remove semaphores */
void driver(); /* driver for forking processes */
void loader();
void cpu();
void printer();
int fill_memory();
void execute_memory();
void print_memory();
main ()
{ /* main program */
/* this program uses semaphores and shared memory. Semaphores are
used to protect the shared memory which serves as a message area
for and sender and receiver process */
printf("Do you want to print the output to screen or file: \n"); /* Ask if the user wants to print to screen or file */ fgets(input
, 100, stdin
); /* Take user input and store it in variable input */
int i ;
/* get semaphore id and a given number of semaphores */
if ((my_semid = semtran(NUM_OF_SEMS)) != -1)
{
/* initialize the semaphores */
init_sem(my_semid, OK_TO_LOAD0, 1);
init_sem(my_semid,OK_TO_LOAD1, 1);
init_sem(my_semid,OK_TO_EXEC0, 0);
init_sem(my_semid,OK_TO_EXEC1, 0);
init_sem(my_semid,OK_TO_SET_OUTPUT0, 1);
init_sem(my_semid,OK_TO_SET_OUTPUT1, 1);
init_sem(my_semid,OK_TO_PRINT0, 0);
init_sem(my_semid,OK_TO_PRINT1, 0);
}
/* get shared memory segement id and attach it to my_shrmemaddr */
size_of_memory = 2*sizeof(*load_job) + 2*sizeof(*print_job) +
4*sizeof(*pcbs) + 40 * sizeof(*memory);
if ((get_attach_shrmem(size_of_memory,&my_shrmemaddr,
&my_shrmemid)) != -1)
/* connect to shared memory at my_shrmemaddr */
load_job = (int *) my_shrmemaddr;
print_job = load_job + 2;
pcbs = (pcb_type *) (print_job + 2);
memory = (memory_type *) (pcbs + 4);
/* call driver to do the work of forking senders and receivers */
driver();
/* wait until all processes have completed their work */
for (i = 1; i <= HOWMANY_PROCESSES; i++) wait(&s);
/* remove the semaphores */
remove_sem(my_semid);
/* remove the shared memory */
remove_shrmem(my_shrmemid, my_shrmemaddr);
} /* end of main */
void driver() /* driver to fork processes for readers and writers*/
{
int pid;
/* fork processes to handle the work */
if (( pid = fork() ) == -1) syserr("fork");
if ( pid == 0 )
{
loader();
/* called printer just to test if loader
was loading the shared memory */
}
if (( pid = fork() ) == -1) syserr("fork");
if ( pid == 0 )
{
cpu();
}
if (( pid = fork() ) == -1) syserr("fork");
if ( pid == 0 )
{
printer();
}
} /* end of driver */
void loader()
{
FILE *fid;
int memory_to_load, current_job;
int more_jobs;
int job_read;
if ((fid
= fopen ("cpu.dat", "r")) == 0) {
puts ("Unable to open file for reading."); return;
}
more_jobs = 2;
current_job = 0;
while (more_jobs)
{
if (current_job == 0)
{
P(my_semid, OK_TO_LOAD0);
memory_to_load = 0;
pcbs[current_job].start_loc = 0;
pcbs[current_job].output_loc = 20;
pcbs[current_job].num_instructions = 0;
job_read = fill_memory(fid, memory_to_load);
if (job_read != 4)
{
more_jobs = more_jobs - 1;
load_job[current_job] = -1;
}
else
load_job[current_job] = 1;
V(my_semid, OK_TO_EXEC0);
}
else
{
P(my_semid, OK_TO_LOAD1);
memory_to_load = 10;
pcbs[current_job].start_loc = 10;
pcbs[current_job].output_loc = 30;
pcbs[current_job].num_instructions = 0;
job_read = fill_memory(fid, memory_to_load);
if (job_read != 4)
{
more_jobs = more_jobs - 1;
load_job[current_job] = -1;
}
else
load_job[current_job] = 1;
V(my_semid, OK_TO_EXEC1);
}
current_job = (current_job + 1) % 2;
} /* end while more_jobs */
/* failed to read the four items */
return;
} /* end of load */
int fill_memory (fid, memory_to_fill)
FILE *fid;
int memory_to_fill;
{
int opcode_ok, end_of_job, bad_instruction;
char opcode, cr;
int operand1, operand2;
int elements_read, current_pcb ;
if (memory_to_fill == 0)
current_pcb = 0;
else
current_pcb = 1;
elements_read = TRUE;
end_of_job = FALSE;
while (elements_read )
{
elements_read
= fscanf (fid
, "%c %d %d%c", &opcode
, &operand1
, &operand2,&cr);
if (elements_read != 4)
{
return(elements_read);
}
else
{
switch (opcode)
{
case '+':
opcode_ok = TRUE;
break;
case '-':
opcode_ok = TRUE;
break;
case '*':
opcode_ok = TRUE;
break;
case '/':
opcode_ok = TRUE;
break;
case '%':
opcode_ok = TRUE;
break;
default :
if (opcode == '?')
{
bad_instruction = FALSE;
end_of_job = TRUE;
}
else
{
end_of_job = FALSE;
opcode_ok = FALSE;
bad_instruction = TRUE;
};
} /* end of switch */
} /* end of else elements read was 4 */
if (end_of_job == TRUE)
return( elements_read);
pcbs[current_pcb].num_instructions =
pcbs[current_pcb].num_instructions + 1;
memory[memory_to_fill].operation = opcode;
memory[memory_to_fill].operand1 = operand1;
memory[memory_to_fill].operand2 = operand2;
memory_to_fill = memory_to_fill + 1;
} /* end of while for fill memory */
} /* end of fill memory */
void cpu()
{
int memory_to_execute, current_job;
int where_to_output, memory_to_output;
int more_jobs;
current_job = 0;
more_jobs = 2;
while (more_jobs)
{
if (current_job == 0)
{
P(my_semid, OK_TO_EXEC0);
if (load_job[current_job] == -1)
{
more_jobs = more_jobs -1;
P(my_semid, OK_TO_SET_OUTPUT0);
print_job[current_job] = -1;
V(my_semid, OK_TO_LOAD0);
V(my_semid, OK_TO_PRINT0);
}
else
{
execute_memory(current_job);
P(my_semid, OK_TO_SET_OUTPUT0);
pcbs[current_job + 2] = pcbs[current_job];
memory_to_output = pcbs[current_job + 2].start_loc;
where_to_output = pcbs[current_job + 2].output_loc;
for (i = 1; i <= pcbs[current_job + 2].num_instructions; i++)
{
memory[where_to_output] = memory[memory_to_output];
memory_to_output = memory_to_output + 1;
where_to_output = where_to_output + 1;
}
load_job[current_job] = 0;
print_job[current_job] = 1;
V(my_semid, OK_TO_LOAD0);
V(my_semid, OK_TO_PRINT0);
} /* end for else for load job[current_job] != -1 */
}
else /* job is number 1 */
{
P(my_semid, OK_TO_EXEC1);
if (load_job[current_job] == -1)
{
more_jobs = more_jobs -1;
P(my_semid, OK_TO_SET_OUTPUT1);
print_job[current_job] = -1;
V(my_semid, OK_TO_LOAD1);
V(my_semid, OK_TO_PRINT1);
}
else
{
execute_memory(current_job);
P(my_semid, OK_TO_SET_OUTPUT1);
pcbs[current_job + 2] = pcbs[1];
memory_to_output = pcbs[current_job + 2].start_loc;
where_to_output = pcbs[current_job + 2].output_loc;
for (i = 1; i <= pcbs[current_job + 2].num_instructions; i++)
{
memory[where_to_output] = memory[memory_to_output];
memory_to_output = memory_to_output + 1;
where_to_output = where_to_output + 1;
}
load_job[current_job] = 0;
print_job[current_job] = 1;
V(my_semid, OK_TO_LOAD1);
V(my_semid, OK_TO_PRINT1);
} /* end for else for load job[1] != -1 */
}
current_job = (current_job + 1) % HOWMANY_JOBS;
} /* end while more jobs */
} /* end of cpu */
void execute_memory(current_job)
int current_job;
{
int memory_to_execute;
int i;
if (current_job == 0)
memory_to_execute = 0;
else
memory_to_execute =10;
for ( i = 1; i <= pcbs[current_job].num_instructions; i++)
{
switch (memory[memory_to_execute].operation)
{
case '+':
memory[memory_to_execute].result =
memory[memory_to_execute].operand1 +
memory[memory_to_execute].operand2 ;
break;
case '-':
memory[memory_to_execute].result =
memory[memory_to_execute].operand1 -
memory[memory_to_execute].operand2 ;
break;
case '*':
memory[memory_to_execute].result =
memory[memory_to_execute].operand1 *
memory[memory_to_execute].operand2 ;
break;
case '/':
memory[memory_to_execute].result =
memory[memory_to_execute].operand1 /
memory[memory_to_execute].operand2 ;
break;
case '%':
memory[memory_to_execute].result =
memory[memory_to_execute].operand1 %
memory[memory_to_execute].operand2 ;
break;
} /* end of switch */
memory_to_execute = memory_to_execute + 1;
}
} /* end execute_memory */
void printer()
{
/* print jobs */
/* the code below was added to test if the loader was filling
memory */
int memory_to_print;
int current_print_job;
int more_print_jobs;
current_print_job = 0;
more_print_jobs = 2;
while (more_print_jobs)
{
if (current_print_job == 0)
{
P(my_semid, OK_TO_PRINT0);
if (print_job[current_print_job] == -1)
{
more_print_jobs = more_print_jobs - 1;
V(my_semid, OK_TO_SET_OUTPUT0);
}
else
{
memory_to_print = 20;
print_memory(current_print_job, memory_to_print);
print_job[current_print_job] = 0;
V(my_semid, OK_TO_SET_OUTPUT0);
}
} /* end for current_print_job == 0 */
else
{
P(my_semid, OK_TO_PRINT1);
if (print_job[current_print_job] == -1)
{
more_print_jobs = more_print_jobs - 1;
V(my_semid, OK_TO_SET_OUTPUT1);
}
else
{
memory_to_print = 30;
print_memory(current_print_job, memory_to_print);
print_job[current_print_job] = 0;
V(my_semid, OK_TO_SET_OUTPUT1);
}
} /* end of else for current_print_job == 2 */
current_print_job = (current_print_job + 1) % 2;
} /* end of while */
} /* end of printer */
void print_memory( current_print_job, memory_to_print)
int current_print_job, memory_to_print;
{
int i;
if (strcmp(input
, str1
) == 0) { printf("output for current job %d \n", current_print_job
); for ( i =1; i <= pcbs[current_print_job + 2].num_instructions; i++)
{
printf("%c %d %d %d \n", memory
[memory_to_print
].
operation, memory[memory_to_print].operand1,
memory[memory_to_print].operand2,
memory[memory_to_print].result );
memory_to_print = memory_to_print + 1;
}
}
else if (strcmp(input
, str2
) == 0) { fprintf(f
,"output for current job %d \n", current_print_job
); for ( i =1; i <= pcbs[current_print_job + 2].num_instructions; i++)
{
fprintf(f
,"%c %d %d %d \n", memory
[memory_to_print
].
operation, memory[memory_to_print].operand1,
memory[memory_to_print].operand2,
memory[memory_to_print].result );
memory_to_print = memory_to_print + 1;
}
}
} /* end of print_memory */
#include "semshm.c"