Friday, May 24, 2013

Shared memory code sample 1.0

A few lines of code may help understanding shared memory, ISM and DISM.
Compile the following code to 64-bits to get beyond the 4 GiB barrier.
In Solaris Studio 12.3 this simply requires compilation option -m64.
 
/*
 * File:   main.cpp
 * Author: AZ
 *
 * Created on May 21, 2013, 3:06 PM
 */

#include <iostream>

#include <sys/ipc.h>
#include <sys/shm.h>

/*
 * This is just a raw demonstration of the shared memory API.
 * To avoid leaks use "resource acquisition is initialization".
 */
  
int main()
{
   //
   // Play with 17 GiB of shared memory!
   //
  
   std::size_t const size = 17UL * 1024UL * 1024UL * 1024UL;

   std::cout << "Getting shared memory. ";

   int id = ::shmget( 1, size, IPC_CREAT | IPC_EXCL | 0660 );

   if ( id == -1 )
   {
      std::cout << "Failure!" << std::endl;
   }
   else
   {
      std::cout << "Success!" << std::endl;

      std::cout << "Attaching to shared memory. ";

      //
      // For a "standard" shared memory segment, 
      // don't pass any flags, that is, pass 0.
      //
      // SHM_RND [Optional]
      // Asks to round down the address to a page boundary.
      // Not necessary for ISM or DISM.
      //
      // SHM_SHARE_MMU
      // Asks for a ISM segment locked in physical memory.
      //
      // SHM_PAGEABLE
      // Asks for a DISM segment pageable (virtual memory).
      //
  
      void * p = ::shmat( id, 0, SHM_SHARE_MMU );

      if ( reinterpret_cast < intptr_t > ( p ) == -1 )
      {
         std::cout << "Failure!" << std::endl;
      }
      else
      {
         std::cout << "Success!" << std::endl;

         std::cout << "Using shared memory." << std::endl;
  
         //         
         // Touch the whole shared segment.
         // Fill it with '*'.
         //
         // This will force the amount reserved
         // to be actually allocated (at least with DISM).
         //

         ::memset( p, '*', size );

         std::cout << "Detaching shared memory. ";

         switch ( ::shmdt( p ) )
         {
            case 0:
               std::cout << "Success!" << std::endl;
               break;

            case -1:
               std::cout << "Failure!" << std::endl;
               break;

            default:
               std::cout << "?" << std::endl;
               break;
         }
      }

      //
      // End of fun!
      //
  
      std::cout << "Removing shared memory. ";

      switch ( ::shmctl( id, IPC_RMID, 0 ) )
      {
         case 0:
            std::cout << "Success!" << std::endl;
            break;

         case -1:
            std::cout << "Failure!" << std::endl;
            break;

         default:
            std::cout << "?" << std::endl;
            break;
      }
   }

   return 0;
}

To take advantage of the above code excerpt for learning, a debugger is required.
Step over the shared memory API calls and watch the CLI ipcs and swap output.
More precisely, the commands are ipcs -mA and swap -sh and swap -lh.

By the way, why do I chose to play with 17 GiB?
That's because my particular test system had 18 GiB to offer.
For more detail showing some real output check shared memory run sample 1.0.
In time I have also added a DISM version with manual locking.