chataign
chataign

Reputation: 732

shmget with IPC_EXCL

I'm having issues using shmget() to manage memory segments. According to the man page, if both IPC_CREAT and IPC_EXCL flags are set, shmget should fail if it is asked to create a segment for a key that already exists.

What I'm seeing is that shmget creates a new segment for the same key (with a new shmid) regardless. The code below illustrates this issue. I'm running two instances of it, one in 'creator' mode, one in 'client' mode.

./test 10 0
./test 10 1

The creator allocates a memory segment for key=10, then attaches to it. The client also attaches to the segment. Running ipcs -m I can see that the segment exists and that two processes are attached to it.

Then I make the creator destroy the segment, and as expected ipcs shows that it is marked for destruction, with 1 process still attached. What's strange, is that if I start the creator again, with the same key, it creates a new segment instead of failing since a segment already exists?

Thanks for your help!

#include <sys/shm.h>
#include <sys/stat.h>
#include <errno.h>

#include <stdlib.h>
#include <vector>
#include <iostream>
#include <stdexcept>
using namespace std;

int main( int argc, char** argv )
{
   cout << "usage: " << argv[0] << " <key> <mode (0=creator 1=client)>" << endl;
   if ( argc < 3 ) return 0;

   int key  = atoi( argv[1] );
   int mode = atoi( argv[2] );

   cout << "key=" << key << endl;
   cout << "mode=" << mode << endl;

   char c;
   int shmid=-1;
   int size = 100; // bytes

   try
   {
      if ( mode == 0 ) // creator
      {
         cout << "creating segment" << endl;
         int flags = ( IPC_CREAT | IPC_EXCL | 0666 );
         shmid = shmget( key, size, flags );

         if ( shmid== -1 )
            throw runtime_error("failed to create segment");

         cout << "created: shmid=" << shmid << endl;
      }
      else if ( mode == 1 )
      {
         shmid = shmget( key, 0, 0 );

         if ( shmid== -1 )
            throw runtime_error("failed to load");

         cout << "loaded: shmid=" << shmid << endl;
      }

      cout << "attach? (press key to continue)" << endl;
      cin >> c;

      void* data = shmat( shmid, NULL, 0 );

      if ( data == (void *) -1 )
         throw runtime_error("failed to attach");

      cout << "attached to id=" << shmid << endl;

      cout << "destroy? (press key to continue)" << endl;
      cin >> c;

      if ( shmctl( shmid, IPC_RMID, NULL ) == -1 )
         throw runtime_error("failed to destroy");

      cout << "destroyed" << endl;
   }
   catch( const exception& e )
   {
      cout << e.what() << " errno=" << errno << endl;
   }
}

Upvotes: 0

Views: 7006

Answers (1)

Hristo Iliev
Hristo Iliev

Reputation: 74485

You should pay closer attention to the output of ipcs. Using your example code with a key of 10.

The server has created the segment:

$ ipcs -m
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x0000000a 1470791680 hristo     666        100        1

The client is attached, the server has marked the segment for destruction:

$ ipcs -m
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 1470791680 hristo     666        100        1          dest
^^^^^^^^^^

As no new processes are expected to be able to find and attach such segments by their key, the key is being zeroed out. That's why you can create a new one with the same key.

Upvotes: 4

Related Questions