Shared Memory and Memory-Mapped I/O
/****************************  Shared Memory  ****************************/
#include <stdio.h>
#include <sys/types.h>   /**********  Shared memory "server" ***********/
#include <sys/ipc.h>     /**********  Executable = shm       ***********/
#include <sys/shm.h>
#include <sys/stat.h>
#include <signal.h>

int memid;
main()
{
      char *shmptr;
      void handler(void);

      signal(SIGINT, handler);
/********************  Map 26 bytes of shared memory.  *****************/
/********************  Key is name of executable (shm).*****************/
      if ((memid = shmget(ftok("shm",0), 26, SHM_R | SHM_W |
                          SHM_R >> 3 | SHM_W >> 6 | IPC_CREAT)) < 0)
      {
           printf("Cannot create shared memory!\n");
           exit(1);
      }

/********************  Attach memory to process space.  *********************/
/********************  Return a pointer to it.          *********************/
      if ((shmptr = shmat(memid, NULL, 0)) == (void *) -1)
      {
           printf("Cannot attach shared memory to process data space!\n");
           exit(2);
      }
      pause();  /*******  Live until this server is brought back to
                 *******  the foreground whereupon we hit CTRL-C.
                 *******/
}


void handler(void)
{
      printf("Ready to kill shared memory space!\n");
      if (shmctl(memid, IPC_RMID, 0) < 0)
      {
           printf("Cannot remove shared memory from system!\n");
           exit(3);
      }
}

#include <sys/types.h>  /**************  Shared Memory Writer  ***************/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
main()
{
      int memid, i;
      char *shmptr;
      struct shmid_ds buff;

      if ((memid = shmget(ftok("shm",0), 0, SHM_R | SHM_W |
                          SHM_R >> 3 | SHM_W >> 6)) < 0)
      {
           printf("Cannot create shared memory!\n");
           exit(1);
      }
      if ((shmptr = shmat(memid, NULL, 0)) == (void *) -1)
      {
           printf("Cannot attach shared memory to process data space!\n");
           exit(2);
      }
      if (shmctl(memid, IPC_STAT, &buff) < 0)
      {
           printf("Cannot get shared memory buffer from server!\n");
           exit(3);
      }
      for (i = 0; i < buff.shm_segsz; i++) *shmptr++ = i + 65;
}
#include <stdio.h> /****************  Shared Memory Reader  ******************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
main()
{
      int memid, i;
      char *shmptr;
      struct shmid_ds buff;

      if ((memid = shmget(ftok("shm",0) , 0, SHM_R | SHM_W |
                          SHM_R >> 3 | SHM_W >> 6 | IPC_CREAT)) < 0)
      {
           printf("Cannot create shared memory!\n");
           exit(1);
      }
      if ((shmptr = shmat(memid, NULL, 0)) == (void *) -1)
      {
           printf("Cannot attach shared memory to process data space!\n");
           exit(2);
      }
      if (shmctl(memid, IPC_STAT, &buff) < 0)
      {
           printf("Cannot get shared memory buffer from server!\n");
           exit(3);
      }
      for (i = 0; i < buff.shm_segsz; i++, shmptr++) putchar(*shmptr);
}
/**************  Output by Reader after shm&; shmw; shmr  ***************/
ABCDEFGHIJKLMNOPQRSTUVWXYZ
/******************  Important Notes About Shared Memory  *****************/

1.  Since external processes can read or write shared memory by knowing
    the unique key (given to function ftok), it is important to prevent
    readers and writers from having simultaneous access to shared memory.
    The easiest (and safest!!) way of doing this is to create a file
    of zero bytes and then a WRITER does this:

        struct flock lock;

        fd = open(well_known_name, O_RDWR);
        lock.l_type   = F_WRLCK;
        lock.l_start  = 0;
        lock.l_len    = 1;
        lock.l_whence = SEEK_SET; 
        lock.l_pid    = getpid();
        fcntl(fd, F_SETLK, &lock);
        /***********  All your overlays on memory in here.  ***********/
        lock.l_type   = F_UNLCK;
        fcntl(fd, F_SETLK, &lock);

        Obviously, I have not included tests of fcntl's return value
        but you must because a -1 return means YOU DID NOT GET THE
        LOCK AND THEREFORE SHOULD NOT WRITE!!!!! 

2.  A shared memory READER will do the same thing but will ask
    for a READ LOCK (lock.l_type = F_RDLCK).

3.  Even though the file has no bytes, the lock.l_len of 1 will still work!!    
        
4.  Using semaphores is another way of controlling memory access but
    semaphores are DANGEROUS because if processes exit abnormally they
    will leave semaphores (and their various states of lock/unlock)
    in memory for an indefinite amount of time!  One-byte file locks
    are safer and their execution speed penalty is too small to worry
    about!


#include <sys/types.h>
#include <sys/mman.h>    /*****  Contains definition of mmap  *****/
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
main()
{
   char buf[1000];
   int fd1, fd2, fd3;
   struct stat statbuf;
   caddr_t start, dst, newdst;
   struct flock lock;

   fd1 = open("testfile1", O_RDONLY);
   fd2 = open("testfile2", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR |
               S_IRGRP | S_IWGRP);
   fd3 = open("testfile3", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR |
               S_IRGRP | S_IWGRP);

   fstat(fd1, &statbuf);   /*****  Create an empty testfile2  *****/
   lseek(fd2, statbuf.st_size - 1, SEEK_SET);
   write(fd2, "", 1);      /*****  This marks location of EOF *****/

   start    = mmap(0, statbuf.st_size, PROT_READ,  
                   MAP_SHARED, fd1, 0);
   dst      = mmap(0, statbuf.st_size, PROT_WRITE,
                   MAP_SHARED,fd2,0);
   newdst   = mmap(0, 1000, PROT_WRITE,
                   MAP_SHARED,fd3,0);

   memcpy(dst, start, statbuf.st_size);  /***  Reads from testfile1 and ***/
                                         /***  and writes to testfile2! ***/
   system("cat testfile2");
   memcpy(dst + 3, "XXX", 3);
   system("cat testfile2");

   memset(buf, 0, 1000);     /*****  Play around with textfile1  *****/
   memcpy(buf, start, 5);
   printf("%s\n", buf);     

   lseek(fd3, 1000, SEEK_SET);
   write(fd3, "", 1);
   strcpy(buf, "What's up, Doc?\n");
   memcpy(newdst, buf, strlen(buf));  /*****  Writes to testfile3!!  *****/
   close(fd3);
   system("cat testfile3");
} 
/****************************  Program  Output  **************************/

abcdefghij    /******  Testfile2 after first memcpy  ******/
abcXXXghij    /******  Testfile2 after overwrite.    ******/

abcde         /******  First five chars. from memcpy ******/
What's up, Doc?   /******  Cat of textfile3  ******/