If I have some struct
struct processData{
int *a;
int *b;
}
And I set up my shared memory ID as
int shmid = shmget(1234, sizeof(processData), IPC_CREAT | 0666);
Where 1234 is my key
Would I set up my actual shared struct like this..
processData* pData =(processData *) shmat(shmid, NULL, 0);
And then shouldn't I be able to change things around in seperate processes like:
pData -> a = SOME_NUMBER;
When I do this, all of my processes aren't interacting with the same piece of memory and I'm clueless why.
The members *a and *b in your structure processData are integer pointer type. Attaching a shared memory to your process does not make them point to a memory location inside the shared memory. Secondly the shared memory that you are creating using the shmget() function in the first place has only enough space to hold a processData data type. You will need some additional memory space to hold two int data types which *a and *b will point to and off course these memory spaces should also be shared so that other processes can access it.
So the solution to your problem will be something like this.
//Create the shared memory to hold the structure.
shmid=shmget(KEY1,sizeof(struct processData),IPC_CREAT|0666);
//Attach it to the process.
pData=shmat(shmid,0,0);
//Create a shared memory to hold an integer which will be pointed by *a.
shmid=shmget(KEY2,sizeof(int),IPC_CREAT|0666);
//Attach the shared memory to the location pointed by *a.
pData->a=shmat(shmid,0,0);
//Create a shared memory to hold an integer which will be pointed by *b.
shmid=shmget(KEY3,sizeof(int),IPC_CREAT|0666);
//Attach the shared memory to the location pointed by *b.
pData->b=shmat(shmid,0,0);
This is the way you should create and attach the shared memories to all the processes that are going to access the shared memory.
(Note: You do not need to create 3 separate shared memories using 3 separate key values. It can also be done by creating a single chunk of shared memory of sufficient size using 1 key and then seeking the pointers to the their respective positions inside the shared memory. It is a little complicated that is why I have given a simple example for better understanding.)
Now coming to the next problem. Since you are using pointers in your structure you cannot assign values to them like this, pData -> a = SOME_NUMBER;. Because, pData -> a is a pointer, to assign some value to it you need to deference it. So it will be done like this.
*(pData -> a) = SOME_NUMBER;
Similarly to read the value in other processes will also need to derefence it there.
SOME_NUMBER = *(pData -> a);
When in your local process you copy the pointer of a int into your struct with:
pData -> a = some-pointer;
you are actually copying the logical memory address (which is valid in your current process) into the shared memory.
When from another process you read such value, it will be a logical memory address occupied by something else (possibly also out of current addressable space).
Related
I'm creating a server and a client that are both accessing shared memory and changing the data in the shared memory.
I've used shm_open to open the shared memory, ftruncate to change the size of the shared memory, and mmap to map the shared memory object of type struct.
I want to create a function that accesses the shared memory via a file descriptor and returns a pointer to the struct.
For example:
XStruct * accessMem(int fd){ /*what to do here? */};
I'm not sure how to go about this, or what functions to use in order to access the shared memory. Any help would be great.
This is homework, so an explanation would be very helpful.
Thanks!
You will have to use (or implement a memory allocator to act on the block you received from mmap).
One simple implementation could be to use a bump allocator.
Store the value of the pointer you received from mmap. Every time you need to allocate memory for a struct, increment the pointer by sizeof (struct) and return the original pointer.
void *allocator_top; // Define a global pointer to top of the "heap" area.
.
.
.
allocator_top = mmap(...); // Do this wherever you perform the mmap
.
.
Xstruct * accessMem(){
void *temp = allocator_top;
// Need to check here if you have exceeded the amount of space mapped. If yes, you need to expand and add more pages.
allocator_top += sizeof(Xstruct);
return temp;
}
Edit : If you have multiple shared regions and want to allocate from them separately, you can take a void **allocator_top as an argument to accessMem() and pass the top of the region you want to allocate from.
I have 2 programs which need to share memory. Let's call one program A, the other one B.
There is a struct in this format for this purpose:
struct town_t {
int population;
char * name;
}
In program A, data gets written to shared memory using mmap. This works for program A. (It uses strcpy for the name)
Program B's purpose is to simply read the data. This too works with mmap. Accessing the shared memory's population field works without any problems. However, accessing the population field gives a segmentation fault.
Since I used strcpy, the entire string should be in the shared memory right?
I use the following flags to get the pointer to shared memory, which returns no error.
tptr = (struct town_t *) mmap(0, 1024, PROT_READ, MAP_SHARED, shm_fd, 0)
How could I make it so I can actually read the string (char*) from program B?
There's no point in putting a pointer in shared memory. A pointer gives a location inside the address space of a particular process. It would have no meaning to another process with another address space. (With some complicated exceptions such as a pointer to memory allocated before a call to fork accessed by related processes running the same executable.)
You can store the string data itself in shared memory if you wish. For example, this will work:
#define MAX_NAME_SIZE 100
struct town_t
{
int population;
char name[MAX_NAME_SIZE];
};
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.
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;
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.
My process is accessing a shared memory that is already created. The pointer attached to the shared memory is a structure containing a pointer and 2 or 3 variables.
eg:
typedef struct _info_t{
int id;
char c;
}info_t;
typedef struct _details_t{
int buff_id;
info_t* info;
}details_t;
details_t* details = shmat(shmid,(void*)0,0);
printf("\n %d \n",details->info->id); // gives me a segmentation fault
If a memory segment is shared between more than one process, there's no guarantee it will be mapped at the same address, so you cannot store pointers in shared memory segment. Try to avoid using pointers, use offsets or arrays (if possible).
shmat(2) is a syscall (on Linux). It may fail. So at least code
details_t* details = shmat(shmid,(void*)0,0);
if (!details) { perror("shmat"); exit(EXIT_FAILURE); };
and you cannot put (easily) pointers in shared memory, since the address is specific to each process.
I have two structures :
struct bets{
int bets[36];
int last_bet;
}bets
struct board{
int type;
bets *bet;
}board
I created a chunk of shad memory of sizeof(board). So, I got a pointer to the Board in shared memory (lest call it ptr).
I did created a new board and bets structure,
board *b, bets * bts, .... added board->bet = bts.
Now, I copied the "b" to ptr
memcpy(ptr, bts, sizeof(board)).
I can access the ptr->type.
But when I try to access
ptr->bet->last_bet, I get a segmentation-fault error.
I also tried copying like this:
board *b;
memcpy(ptr, b, sizeof(board));
bets *bts;
memcpy(ptr->bet, bts, sizeof(bets)).
Still getting segmentation-fault error.
How can I copy both struct one inside of the other and still have access to the nested one?
Standard "deep copying" into shared memory is not useful because the pointers, even if they point into the shared memory segment, are local to your process's virtual address space and won't be the same when another process maps the shared memory. Instead of pointers, you need to store offsets from the beginning of the shared memory segment. size_t would be an appropriate type.