stoictopia
stoictopia

Reputation: 183

Management of Unix Shared Memory

We know that, shared memory in Windows is implemented via memory mapped files backed by system pagefile, and it is always managed in a reference counted way (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366537(v=vs.85).aspx).

I wonder whether Unix does it in a similar way. Someone (http://stackoverflow.com/q/4278391/939142) says that Unix also manages shm in a reference counted way. I tried the an experiment on Mac OS X, and found that it was not the case.

Using the code supplied in the end, compile two programs: host and client. Type

./host 

which creates a shm, writes (int) 10 at its first address, and quits. Then type

./client <shmid>

to examine the shm segment, which attaches to the shm created, prints the first int, and quits.

Note that we used shmat and shmdt to connect to / disconnect from the shm, and shmget to create the shm.

To destroy the shm, we have to do it manually using shmctl.

Conclusion: shm is not managed as reference counting in Unix, at least for Mac OS X

/************************** host.c ****************************/

#include <stdio.h>
#include <sys/shm.h>
#include <mach/vm_param.h>
#include <assert.h>

int
main(int argc, char** argv)
{
int value = 10;
int id;
void* ptr;
    /* create a new shm */
id = shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | 0666);
assert(id != -1);
    /* attach to the new shm */
ptr = shmat(id, (const void*) NULL, 0);
assert((int*) ptr != -1);
    /* print the id so that client can use */
printf("shm id = %ld\n", id);
printf("address of id = %ld, length = %ld\n", ptr, PAGE_SIZE);
((int*) ptr)[0] = value;
printf("value at address %ld = %ld\n", ptr, *(int*) ptr);
/* detach from the shm and exit */
    shmdt((const void*) ptr);
return 0;
}


/************************** host.c ****************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include "assert.h"
#include <mach/vm_param.h>

int
main(int argc, char** argv)
{
void* ptr;
int id = atoi(argv[1]);
assert(id != -1);
    /* attach to the shm */
ptr = shmat(id, NULL, 0);
assert(ptr != -1);
printf("value at ptr = %ld = %ld\n", ptr, *(int*) ptr);
shmdt((const void*) ptr);
return 0;
}

Upvotes: 4

Views: 960

Answers (1)

A.H.
A.H.

Reputation: 66263

It not pure reference counting. According to shmctl(2):

IPC_RMID: Mark the segment to be destroyed. The segment will only actually be destroyed after the last process detaches it (i.e., when the shm_nattch member of the associated structure shmid_ds is zero). The caller must be the owner or creator,

This means: IPC_RMID will not delete immediately but only after the reference count drops to zero the next time.

This allows you to achieve several goals with the same tool:

  • Either a server/client approach where the server creates, attaches and immediately sets RMID. Then clients can connect as long as the server is here. If the server goes down, the clients should disconect and the resource is cleaned up by the OS.

  • Or the "message" approach: Someone writes a message, pins it to a known location. After that someone else can come, look for a message and act accordingly. This is what you have done. This approach is more open to resource garbage of course. But there are usecases for this.

Upvotes: 2

Related Questions