/* 
 * image.c
 *
 * This program initializes and 'image' and lets some workers 'process' it.
 * 
 * This could be used as an skeleton code whenever parts of a 
 * multi-dimentional array are to be processed by different tasks.
 *
 * By Kamran Karimi
 */  

#include "image.h"
#include <string.h>

int semid = -1;
int shmid = -1;
char (*image)[COLUMN] = (char (*)[]) -1;

/* this array will be used to initialize the picture */
static char orig[4] = { '-', '/', '|', '\\' };

static void sig_handler(int signo)
{
 fprintf(stderr,"Image: Quiting\n");

 if(semid > -1)
  semctl(semid, 2, IPC_RMID, 0);
 if(image != (char (*)[]) -1) 
  shmdt((char *)image);
 if(shmid > -1) 
  shmctl(shmid, IPC_RMID, 0);
 exit(5);
}

/* note that this example does not actually check for possible
   differences in the architectures. In this case DIPC_SIG_READER
   and DIPC_SIG_WRITER are ignored. 

static void shm_sig_handler(int signo)
{
 if(signo == DIPC_SIG_READER)
  fprintf(stderr,"Image: BECAME A READER!\n");
 else if(signo == DIPC_SIG_WRITER)
  fprintf(stderr,"Image: BECAME A WRITER!\n"); 
 else
  fprintf(stderr,"Image: SIGNAL %d\n", signo);  
}
*/


int main()
{
 int i, j, num;
 unsigned short seminit[2]; 
 struct sigaction sact;
 struct sembuf sem[2];
 
 /* The following should become 'shm_sig_handler' if used in a 
    heterogeneous system */
 sact.sa_handler = SIG_IGN; 
 sigemptyset(&sact.sa_mask);
 sact.sa_flags = 0;

 if(sigaction(DIPC_SIG_READER, &sact, NULL) < 0)
 {
  fprintf(stderr,"Image:  ERROR: Can't Catch Signal");
  fprintf(stderr,"  BECAUSE: %s\n",strerror(errno));
 }
 
 if(sigaction(DIPC_SIG_WRITER, &sact, NULL) < 0)
 {
  fprintf(stderr,"Image:  ERROR: Can't Catch Signal");
  fprintf(stderr,"  BECAUSE: %s\n",strerror(errno));
 }

 sact.sa_handler = sig_handler;
 if(sigaction(SIGINT, &sact, NULL) < 0)
 {
  fprintf(stderr,"Image: Can't Catch Signal");
  fprintf(stderr,"  BECAUSE: %s\n",strerror(errno));
 }
 semid = semget(SEM_KEY, 2, SEM_MODE | IPC_CREAT);
 if(semid < 0)
 {
  fprintf(stderr,"Image: semget() failed BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 }
 /* sem[0] for initialization, sem[1] for result */
 seminit[0] = seminit[1] = 0;
 if(semctl(semid, 2, SETALL, (union semun) seminit) < 0)
 {
  fprintf(stderr,
    "Image: can't initialize the semaphores BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 }  
 
 fprintf(stderr,"Image: semaphor initialized.\n");
 shmid = shmget(SHM_KEY, SHM_SIZE, SHM_MODE | IPC_CREAT);
 if(shmid < 0) 
 {
  fprintf(stderr,"Image: shmget() failed BECAUSE %s\n",strerror(errno));
  raise(SIGINT);
 }
 
 image = (char (*)[])shmat(shmid,0,0);
 if(image == (char (*)[]) -1)
 {
  fprintf(stderr,"Image: shmat() failed BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 }
 /* initialize the picture */
 for(num = 0; num < 4; num++)
 {
  for(i = bounds[num].row1; i < bounds[num].row2; i++)
  {
   for(j = bounds[num].col1; j < bounds[num].col2; j++)
    image[i][j] = orig[num];
  } 
 }
 /* display it */
 for(i = 0; i < ROW; i++)
 {
  for(j = 0; j < COLUMN; j++)
   putchar(image[i][j]);
  putchar('\n'); 
 } 
 fprintf(stderr,"Image: Picture Initialized. Press Return to continue..."); 
 i = getchar();
 sem[0].sem_num = 0;
 sem[0].sem_op = NUM_WORKERS; /* allow workers to access the shared memory */
 sem[0].sem_flg = SEM_UNDO;
 
 if(semop(semid, &sem[0], 1) <0)
 {
  printf("Image: semop() failed BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 }   
 
 fprintf(stderr,"Image: starting remote tasks\n");
 if(fork() == 0)
 { /* child */
  if(execlp("sh","sh","image_s", NULL) < 0)
   fprintf(stderr,"Image: execlp failed BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 } 
 sem[1].sem_num = 1;
 sem[1].sem_op = -NUM_WORKERS; /* wait until workers are done */
 sem[1].sem_flg = SEM_UNDO;
 if(semop(semid, &sem[1], 1) < 0)
 {
  fprintf(stderr,"Image: semop() failed BECAUSE %s\n", strerror(errno));
  raise(SIGINT);
 }
 fprintf(stderr,"\nImage: The Transformed Image:\n");
 for(i = 0; i < ROW; i++)
 {
  for(j = 0; j < COLUMN; j++)
   putchar(image[i][j]);
  putchar('\n'); 
 }          
 raise(SIGINT);
 exit(0);
}
