user3268401
user3268401

Reputation: 329

Using mmap() to map for multiple processes to share memory region

For a project I have to do I have to use:

void *ptr = mmap(NULL, N, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);

where N is the number of bytes of RAM to ask for from the OS.

When this statement executes, what is ptr pointing to? Is it pointing to the start of the shared memory between processes? Also, if in this memory space say I want to store 1,000 int pointers, do I need to have N = 1000 * sizeof(int *);?

And assuming that I am correct, where is the second place in memory that I can store something? Is it at ptr + 1 or ptr + 4 because an int * is 4 bytes on a 32-bit system?

Thank I appreciate it.

Upvotes: 3

Views: 3725

Answers (2)

datenwolf
datenwolf

Reputation: 162164

void *ptr = mmap(
    NULL, N,
    PROT_READ|PROT_WRITE,
    MAP_SHARED|MAP_ANONYMOUS,
    0, 0);

where N is the number of bytes of RAM to ask for from the OS.

Here's one important constraint you must follow: N must be an integer multiple of the system's page size (or if mapping hugepages, an integer multiple of a hugepage's size). Usually it's 4096 bytes, but the actual value is reported by sysconf(PAGESIZE).

When this statement executes, what is ptr pointing to?

The beginning of the portion of the address space this particular mapping has been created at. With a non-anonymous mapping you can map the same memory several times at different addresses (this is a neat trick to implement transparent ringbuffers).

Is it pointing to the start of the shared memory between processes?

At this particular point, it's just pointing to some memory. There's nothing shared about this yet. The mapping however will be shared after a fork (or a clone with the right flags); this already is process shared memory, but you probably will want to also execve into a different executable.

Also, if in this memory space say I want to store 1,000 int pointers, do I need to have N = 1000 * sizeof(int *);?

Well, technically you need to have n * sysconf(PAGESIZE) == N >= 1000 * sizeof(int*); however why do you want to share int pointers? Unless you have those pointers point into (another) shared memory region, that's at the same address in every process that uses those pointers, it's pretty useless to share pointers. Of course after a fork the address space of the processes is identical, but a execve will unmap all previous mappings, and you'd have to use non-anonymous mmap with MAP_FIXED and a filedescriptor obtained with, e.g., memfd_create, and use the first parameter of mmap where exactly to map it at (which might fail, or overmap a previously existing mapping).

What you can sensibly share is offsets and bulk data.

Oh, and just to eliminate any confusion: Placing a pointer in a shared memory region will not automagically share the memory it's pointing to.

And assuming that I am correct, where is the second place in memory that I can store something? Is it at ptr + 1 or ptr + 4 because an int * is 4 bytes on a 32-bit system?

It's just plain memory, that you can use, as if it were allocated with malloc. Cast the pointer to whatever type you see fit and use it as usual.

Upvotes: 1

Ian
Ian

Reputation: 861

Since mmap is not defined in standard C, I'm assuming you're using this: http://linux.die.net/man/2/mmap

The return value is a pointer to the memory:

On success, mmap() returns a pointer to the mapped area. On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set appropriately. On success, munmap() returns 0, on failure -1, and errno is set (probably to EINVAL).

You are calculating N correctly.

However, you'll probably have problems using addition with a void* pointer, so cast your pointer to an int* to do addition.

int* p = ptr;
int* nextP = p + 1;

Upvotes: 1

Related Questions