Download | Plain Text | Line Numbers


/* define SUSv2 standard */
#define _XOPEN_SOURCE 500
 
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
 
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
 
#include <math.h>
#include <time.h>
#include <sys/time.h>
 
#define NUM_CHILDS 10
#define SIZE_RINGBUF 50
 
void P(int semaphoresId,int semaphoreNr);
void V(int semaphoresId,int semaphoreNr);
void child_write();
void child_read();
 
typedef struct
{
  unsigned buf[SIZE_RINGBUF];
  unsigned insert;
  unsigned remove;
} ringbuffer;
 
ringbuffer *ringbuf;
 
int main(int argv, char** argc)
{
  int shmid, semid, i, pid;
  int childs[NUM_CHILDS];
  struct sembuf sbuf;
 
  /* create shared memory */
  shmid = shmget(IPC_PRIVATE, sizeof(ringbuffer), IPC_CREAT | 0600);
 
  /* create + initialize semaphor */
  semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
  sbuf.sem_num = 0;
  sbuf.sem_op =  1;
  sbuf.sem_flg = 0;
  semop(semid, &sbuf, 1);
 
  /* attach and initialize shared memory */
  ringbuf = shmat(shmid, NULL, 0);
  ringbuf->insert = ringbuf->remove = 0;
 
  /* create and start childs */
  for(i = 0; i < NUM_CHILDS; i++)
  {
    if((pid = fork()) == 0)
    {
      /* child */
      while(1)
      {
        P(semid, 0);
        if (i % 2 == 0)
          child_write();
        else
          child_read();
        V(semid, 0);
        /*usleep(10000);*/
      }
 
      /* although this will never be reached this would be the correct shutdown behaviour */
      shmdt(ringbuf);
      exit(1);
    }
    else
    {
      /* parent */
      childs[i] = pid;
    }
  }
 
  /* wait for any key press */
  getchar();
 
  /* send sigterm to all childs */
  for(i = 0; i < NUM_CHILDS; i++)
  {
    kill(childs[i], SIGTERM);
    int status;
    waitpid(childs[i], &status, 0);
  }
 
  /* remove semaphor */
  semctl(semid, 0, IPC_RMID);
 
  /* detach and remove shared memory */
  shmdt(ringbuf);
  shmctl(shmid, 0, IPC_RMID);
 
  return 1;
}
 
void child_write()
{
  unsigned num;
  struct timeval tp;
 
  if (ringbuf->buf[ringbuf->insert] != 0)
    return;
 
  /* srand + some entropy */
  gettimeofday(&tp, NULL);
  srand(tp.tv_sec + tp.tv_usec + getpid());
  num = 1 + (unsigned) (RAND_MAX * (rand() / (RAND_MAX + 1.0)));
 
  ringbuf->buf[ringbuf->insert] = num;
  printf("[%d] W [%u] = %u\n", getpid(), ringbuf->insert, num);
 
  ringbuf->insert++;
  if (ringbuf->insert >= SIZE_RINGBUF)
    ringbuf->insert = 0;
}
 
void child_read()
{
  unsigned num;
 
  num = ringbuf->buf[ringbuf->remove];
  if (num == 0)
    return;
 
  ringbuf->buf[ringbuf->remove] = 0;
  printf("[%d] R [%u] = %d\n", getpid(), ringbuf->remove, num);
 
  ringbuf->remove++;
  if (ringbuf->remove >= SIZE_RINGBUF)
    ringbuf->remove = 0;
}
 
void P(int semaphoresId,int semaphoreNr)
{
  struct sembuf semaphoreOperation;
  semaphoreOperation.sem_num = semaphoreNr;
  semaphoreOperation.sem_op = -1;
  semaphoreOperation.sem_flg = 0;
  semop(semaphoresId, &semaphoreOperation, 1);
}
 
void V(int semaphoresId,int semaphoreNr)
{
  struct sembuf semaphoreOperation;
  semaphoreOperation.sem_num = semaphoreNr;
  semaphoreOperation.sem_op =  1;
  semaphoreOperation.sem_flg = 0;
  semop(semaphoresId, &semaphoreOperation, 1);
}