Allocate a struct from an existing file descriptor - c - c

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.

Related

How to put a variable in a shared memory? [duplicate]

This question already has answers here:
how to use shared memory to communicate between two processes
(3 answers)
Closed 5 years ago.
I have a variable with a value and I want to share it with the proccesses.
Ex:
typedef struct {
unsigned int a;
unsigned int b;
another_struct * c;
} struct1;
...
struct1 A ={...};
...
Now, I want to create a shared memory region and put the A variable in this region. How can i do this?
Shared memory is an operating system feature (which does not exist in C11). It is not "provided" by the C standard.
I guess that you are coding for Linux. BTW, read Advanced Linux Programming.
Read first shm_overview(7). You'll need to synchronize, so read also sem_overview(7).
You'll get some shared memory segment into a pointer and you'll use that pointer.
First, open the shared memory segment with shm_open(3):
int shfd = shm_open("/somesharedmemname", O_RDWR|O_CREAT, 0750);
if (shfd<0) { perror("shm_open"); exit(EXIT_FAILURE); };
Then use mmap(2) on that shfd:
void* ad = mmap(NULL, sizeof(struct1), PROT_READ|PROT_WRITE, MAP_SHARED,
shfd, (off_t)0);
if (ad==MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); };
Then you can cast that address into a pointer:
struct1* ptr = (struct1*)ad;
and use it. (Don't forget to close).
BTW, you don't and you cannot put a variable into a shared memory. You get a pointer to that shared memory and you use it, e.g. ptr->a = 23;
Of course, don't expect the same shared segment to be mapped at the same address (so you can't easily deal with pointer fields like c) in different processes. You probably should avoid pointer fields in shared struct-s.
Notice that C variables exist only at compile time. At runtime, you only have locations and pointers.
PS. Shared memory is a quite difficult inter-process communication mechanism. You should perhaps prefer pipe(7)-s or fifo(7)-s and you'll need to multiplex using poll(2).
Take a look at Beej's Guide to IPC.
I would basically treat the whole shard memory segment as a void* that you can place items at. You could use memcpy, of string.h, to copy A into your shared memory space. However your pointer in A would become invalid and cause a segfault if you attempted to use it in another process connected to shared memory segment.

Shared Memory struct in "On demand" Server in C

I have to create for academic purpose an "On-Demand Server" that is based on the TCP protocol. The client each time sends a KEY and a VALUE that I have to store them in a global struct like the one bellow:
I use a function named "put" to store every KEY and VALUE to the struct and a "get" function that uses the key and finds the correct value:
My problem is that if a client makes a change in the struct the next one won't be able to know. I used semaphores in order to make the server wait until the child finishes and then accept the next child but I have still the same problem.
I read that I have to make the memory of this struct shared in order to make this work using mmaps but still I can't find a proper solution.
I make my first steps in server programming and every help would be great.
My problem is that if a client makes a change in the struct the next one won't be able to know.
As you noted, mmap() is part of the solution...
Shared memory needs of your application can be addressed with _shm_open()_, _shm_unlink()_, mmap etc. as illustrated in this post. And here for additional examples on shared memory
All of the essentials are summarized in the links, but this excerpt describes the basic concept:
shm_open() creates and opens a new, or opens an existing, POSIX
shared memory object. A POSIX shared memory object is in effect a
handle which can be used by unrelated processes to mmap(2) the same
region of shared memory. The shm_unlink() function performs the
converse operation, removing an object previously created by
shm_open().
I also wanted to suggest that dynamic allocation of memory may be of use in creating space for your struct on an as-needed basis. The size of members, as shown are excessively large,
char keys[4096];
char values[4096];
but in comments you state they only need to be 51 bytes. The struct then can be created as a typedef:
struct keyvalue {
char keys[51];
char values[51];
} DATA;
The create an instance of a pointer to your struct:
DATA *pData = {0};
Which can then be sized on an as needed basis using standard malloc, and or realloc
pData = malloc(initialSize*sizeof(DATA));
As size requirements change, use the following to grow memory:
DATA *tmp = {0};
tmp = realloc(pData, newSize);
if(!tmp) return -1;//ensure memory allocation successful
pData = tmp;//tmp includes previous contents of pData, and more space
... //continue using pData
Free pData when it is no longer needed.
free(pData);
To pass this struct in a function, the function might look like this:
void func1(DATA *d, int numElements)
{
...
for(i=0;i<numElements;i++)
{
strcpy(d[i]->keys, "some key");
strcpy(d[i]->values, "some value");
}
...
}
To call that function with a copy of pData, if say it had a 1000 elements:
func1(pData, 1000);

Deallocating struct in C outside function

I am creating struct object in my code and I want to destroy this object. I know, for creating pointers I have to use malloc() to allocate and free() to deallocate pointer or array. But I have question about struct object. I was looking for answers here and I found solution to use brackets {} - placing struct object in brackets, so outside of right bracket struct object will be deallocated. But I am interested to deallocate object in global array. How can I deallocate such object? Example code
typedef struct {
unsigned char m_some_property;
} my_struct;
static my_struct g_myStructArr[10];
int main(void)
{
g_myStructArr[0].m_some_property = 20;
// how to use brackets {} here to deallocate that object?
return 0;
}
Is that possible?
You can't, global variables will be allocated for the lifetime of the program. Also I don't understand why you want to, you should not worry about that since using global variables is very rarely needed. Global variables are allocated when the program starts and deallocated when it ends.
An executable of a C program is divided into following sections:
Text Segment:
Machine code of binary is read into this section. Text segment is often read-only segment in order to prevent from being modified.
Initialized Data Segment:
All global, static, constant and external variables that are initialized are recorded into this section.
Uninitialized Data Segment:
This section contains all uninitialized global and static data and is initialized to zero before program starts executing.
Heap:
Almost all the dynamic memory allocations come from this section.
Stack:
This segment starts from a very high address and grows downwords as functions are called.
Function frames, local variables, return addresses etc. get memory from this segment. As Elias pointed out,
this stack is very different from stack data structure. This is a memory segment where is that is a style in
organizing data. The only common thing in them is that they grow dynamically in LIFO manner.
Coming to your question, you need to declare a pointer in global space like
my_struct *foo;
and in main(), you can allocate required memory dynamically and make this pointer to point to that memory
foo = calloc(10, sizeof (my_struct));
and when you need to deallocate the memory you can use realloc() to resize it.
malloc(), calloc() do not work on global data segment. malloc library hogs a big fat chunk of memory by extending the break point while initializing and hosts dynamic memory allocations done using malloc() et al in that memory area.

Creating and Accessing a struct in shared memory

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).

Storing a pointer in C

I'm trying to create a memory allocation system, and part of this involves storing integers at pointer locations to create a sort of header. I store a couple of integers, and then two pointers (with locations to the next and prev spots in memory).
Right now I'm trying to figure out if I can store the pointer at a location that I could later use as the original pointer.
int * header;
int * prev;
int * next;
...
*(header+3) = prev;
*(header+4) = next;
Then later...
headerfunction(*(header+4));
would perform an operation using the pointer to the 'next' location in memory.
(code for illustration only)
Any help or suggestions greatly appreciated!
Don't do direct pointer manipulation. Structs were made to eliminate the need for you to do that directly.
Instead, do something a bit more like this:
typedef struct
{
size_t cbSize;
} MyAwesomeHeapHeader;
void* MyAwesomeMalloc(size_t cbSize)
{
MyAwesomeHeapHeader* header;
void* internalAllocatorPtr;
size_t cbAlloc;
// TODO: Maybe I want a heap footer as well?
// TODO: I should really check the following for an integer overflow:
cbAlloc = sizeof(MyAwesomeHeapHeader) + cbSize;
internalAllocatorPtr = MyAwesomeRawAllocator(cbAlloc);
// TODO: Check for null
header = (MyAwesomeHeapHeader*)internalAllocatorPtr;
header->heapSize = cbSize;
// TODO: other fields here.
return (uint8_t*)(internalAllocatorPtr) + sizeof(MyAwesomeHeapHeader);
}
What-ever you are doing is not safe because you are trying to write a memory location which is not pointed by header as *(header+3) it will try to write to some other memory location 12 byte far from header pointer & if this newly memory is held by another variable then it will cause problem.
You can do as first of all allocating a big memory & then the start address will give you the source of your memory in which you can use some starting bytes or memory for controlling other parts of the remaining memory with the help of structures.
Akp is correct, just looking at what you are trying to accomplish in your code segment, if you are trying to store integer pointers in header, header should be defined as such:
int **header;
and then memory should be allocated for it.
With regards to the actual memory allocation, if on a Unix machine, you should look into the brk() syscall.
You are building a memory allocation system, and thus we assume you have a trunk of memory somewhere you can use freely to manage allocations and freeings.
As per your question, the header pointer is allocated in the heap memory (by the compiler and libraries) - and you may wonder if it is safe to use that memory since you are allocating memory. It depends on your system, and if there is another (system) memory allocation management.
But what you could do is
main() {
void *header;
void *prev;
void *next;
manage_memory_allocations(&header, &prev, &next); // never returns
}
In this case, the pointers are created on the stack - so the allocation depends on the memory where the processor stack points to.
Note the "never returns" as the memory is "freed" as soon as main ends.

Resources