/***************************************************************************
 * Copyright 1995, Technion, Israel Institute of Technology
 * Electrical Eng, Software Lab.
 * Author:    Michael Veksler.
 ***************************************************************************
 * File:      shm_semaph_test.c
 * Purpose:   Test semaphores handleingr shared memory operations.
 ***************************************************************************
 */
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "shm_semaph.h"
#include <sys/shm.h>
#define DEBUG_DEFINE_VARIABLES
#include <debug.h>

static volatile int * volatile data;
static int isparent=0;
#define DELAY (rand()%10)
shm_sem sem;

static void read_write(int num)
{
  int i,j ;
  volatile float dummy=0;
  int val;

  srand(num+time(NULL));
  for (i=0x3fff;i>=0;i--) {
     if((i&0x7ff)==0 && isparent)
	fprintf(stderr,"0x%06x\r",i);
     shm_write_wait(sem);
     *data= num;
     for (j=DELAY ; j>=0;j--)
	dummy*=2;
     if (*data!=num) {
	fprintf(stderr,"\nbad shm_write_wait(), num=%d\n",num);
	shm_write_signal(sem);
	return;
     }
     shm_write_signal(sem);
     for (j=DELAY ; j>=0 ;j--)
	dummy*=2;
     shm_read_wait(sem);
     val=*data;
     for (j=DELAY; j>=0 ;j--)
	dummy*=0.5;
     if (*data!=val) {
	fprintf(stderr,"\nbad shm_read_wait(), num=%d,val=%d,*data=%d\n",
		num,val,*data);
	shm_read_signal(sem);
	return;
     }
     shm_read_signal(sem);
  }
  if (isparent)
     fputc('\n',stderr);
}
static void child1()
{
  read_write(2);
}
static void child2()
{
  read_write(10);
}
static void parent()
{
  isparent=1;
  read_write(60);
}

int main()
{
  int shmid;
  int ret1, ret2;
  int pid1, pid2;
  int stat=0;
  
  shm_sem_init(&sem);
  shmid=shmget(IPC_PRIVATE, 0x100, IPC_CREAT | 0700);
  data= (int *)shmat ( shmid, NULL, 0);
  *data=0;
  
  switch (pid1=fork()) {
    case -1:
      perror("fork 1");
      return 1;
    case 0:
      fprintf(stderr,"child1\n");
      child1();
      fprintf(stderr,"child1 done\n");
      return 0;
    default :
  }
  switch (pid2=fork()) {
    case -1:
      perror("fork 2");
      stat|=1;
      break;
    case 0:
      fprintf(stderr,"child2\n");
      child2();
      fprintf(stderr,"child2 done\n");
      return 0;
    default :
  }
  fprintf(stderr,"parent\n");
  if (pid2>0) {			   /* if second fork did not fail */
     parent();
     fprintf(stderr,"parent done, waiting for child2\n");
     waitpid(pid2,&ret2,WUNTRACED);
     stat|=ret2;
  }
  fprintf(stderr,"parent done, waiting for child1\n");
  waitpid(pid1,&ret1,WUNTRACED);
  stat|=ret1;
  fprintf(stderr,"all done\n");

  shmctl(shmid, IPC_RMID,NULL);
  shm_sem_done(&sem);
  return stat;
}