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.
Related
I'm currently learning the Linux process address space and I'm not sure where these C variables correspond in the process address space.
I know that when a function is called, a new frame is created, it'll contain local variables and other function calls etc..
What I am not sure about is the pointers that are in the frame:
I have this function:
int main(){
char *pointer1 = NULL;
char *pointer2 = (void *)0xDDDDDDDD;
pointer1 = malloc(80);
strcpy(pointer1, "Testing..");
return(0);
}
When main is called, a new frame is created.
Variables are initialized.
What I am not sure about these are the pointers, where does:
*pointer1 correspond to in the process address space - data or text section?
*pointer2 correspond to in the process address space - data or text section?
Does NULL and 0xDDDDDDDD belong to data or text section?
since pointer1 = malloc(80), does it belong to the stack section?
First of all it should be noted that the C specification doesn't actually require local variables to be stored on a stack, it doesn't specify location of automatic variables at all.
With that said, the storage for the variables pointer1 and pointer2 themselves will most likely be put on a stack by the compiler. Memory for them will be part of the stack-frame created by the compiler when the main function is called.
To continue, on modern PC-like systems a pointer is really nothing more than a simple unsigned integer, and its value is the address where it points. The values you use for the initialization (NULL and 0xDDDDDDDD) are simply plain integer values. The initialization is done just the same as for a plain int variable. And as such, the values used for initialization doesn't really exists as "data", instead they could be encoded directly in the machine code, and as such will be stored in the "text" (code) segment.
Lastly for the dynamic allocation, it doesn't change where pointer1 is stored. What is does it simply assigning a new value to pointer1. The memory being allocated is on the "heap" which is separate from any program section (i.e. it's neither in the code, data or stack segments).
As some programmer dude just said, the C spec does not state a region where automatic variables must be placed. But it is usual for compilers to grow the stack to accommodate them there. However, they might end on the .data region, and they will if they were, e.g., defined as static char *pointer1 instead.
The initialization values may or may not exist in a program region either. In your case, since the type of values is int, most architectures will inline the initialization as appropriate machine instructions instead, if instructions with appropriate inline operators are available. In x86_64, for example, a single mov/movq operation will be issued to put the 0 (NULL) or the other int in the appropriate memory location on the stack.
However, variables initialized with global scope, such as static char string[40] = "Hello world" or other initialized global variables end up on the .data region and take up space in there. Compilers may place declared, but undefined, global scoped variables on the .bss region instead.
The question since pointer1 = malloc(80), does it belong to the stack section? is ill-defined, because it comprises two things.
The value pointer1 is a value that will be saved at &pointer1. An address which, given the above consideration, the compiler may have put on the stack.
The result of malloc(80) is a value that refers to a region on the heap, a different region, dynamically allocated outside the mapped program space.
On Linux, the result of calling malloc may even create a new NULL-backed memory region (that is, a transient region that is not permanently stored on a file; although it could be swapped by the kernel).
In essence, you could think of how malloc(80) behaves, as something like (not taking free() into consideration, so this is an oversimplification):
int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
void *result;
if (space_left < req) {
last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
space_left = MALLOC_CHUNK_LENGTH;
}
space_left -= req;
result = last_mapping;
last_mapping += req;
return result;
}
The huge difference between calling malloc and mmap with MAP_PRIVATE is that mmap is a Linux System Call, which must make a kernel context switch, allocate a new memory map and reset the MMU layer for every memory chunk allocated, while malloc can be more intelligent and use a single big region as "heap" and manage the different malloc's and free's in userspace after the heap initialization (until the heap runs out of space, where it might have to manage multiple heaps).
Last section of your doubts i.e. "since pointer1 = malloc(80), does it belong to the stack section? " , I can tell you
In C, dynamic memory is allocated from the heap using some standard library functions. The two key dynamic memory functions are malloc() and free().
The malloc() function takes a single parameter, which is the size of the requested memory area in bytes. It returns a pointer to the allocated memory. If the allocation fails, it returns NULL. The prototype for the standard library function is like this:
void *malloc(size_t size);
The free() function takes the pointer returned by malloc() and de-allocates the memory. No indication of success or failure is returned. The function prototype is like this:
void free(void *pointer);
You can refer the doc
https://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html
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];
};
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.
Let's assume that there is a function store_at(int) which is supposed to store the passed number in a given hexa location as shown below:
void store_at(int val)
{
int *ptr;
ptr = (int *)0x261;
// logic goes here
return;
}
How do we write logic to store val at the given Hex location (0x261 In this case)?
Does saying *ptr = val; work? I vaguely remember reading somewhere that this is not allowed in C.
*ptr = val; works. But you have to make sure this address is allocated and even more, accessible. Without knowing for what you are programming C, I could suggest some ways of prevention on accessing addresses you don't have permission. So it pretty much depends on the architecture and/or operational system you're using.
For example, in ATMEGA32 microcontroller, you don't have any limitation regarding the access of the main memory for it. You can read, write and execute code from/for it:
PORTB = 1;
// Knowing that PORTB is stored at 0x38, you can do the equivalent:
*((unsigned int *)0x0038) = 1;
But that's on embedded systems. Now if you want total access for a memory space (as long as it's in your application sandbox), you can use VirtualProtect for Windows and mprotect for Linux:
int val = 123;
DWORD oldprotection;
VirtualProtect((LPVOID)0x261, sizeof(int), PAGE_EXECUTE_READWRITE, &oldprotection);
*(int *)0x261 = val;
And here is the types of protection you can use with it: Memory Protection Constants.
And a mprotect example:
int val = 123;
mprotect((const void *)(((int)(0x261) / PAGESIZE) * PAGESIZE), sizeof(int), PROT_WRITE | PROT_READ | PROT_EXEC);
*(int *)0x261 = val;
Note that this mprotect example is untested, you may need to increase the size for protection or some other things.
The division by PAGESIZE there is just a trick to align the address correctly. Also note that your address is invalid for Linux, as its division will lead to 0 if PAGESIZE is greater than it (the same as "it will be").
According to the syntax for accessing a address using a pointer, all of these work:
*(int *)0x261 = val;
int *ptr = (int *)0x261;
*ptr = val;
Yes, expression *ptr = val (and even more, *(int *)0x261 = val; ) is perfectly valid in C. But then you're facing technical limitations of runtime environments.
Modern operating systems usually run processes in a sandbox of virtual memory (so processes can't access and spoil memory of some other process) and technically the virtual memory of a process looks like a set of regions which you can access, some in readonly way, some does not allow executing code from here and so on. When you try to access non-available VM region, you'll get SIGSEGV on Unix-like systems or Access Violation error on Windows systems, the same for writing to a read-only memory region and trying to execute code in region where it's prohibited by operating system (for example, you can see virtual memory mappings for a linux process with pid in /proc/$PID/maps.
Memory of a process is usually managed by the operating system (you get new memory from the heap using OS-provided functions like malloc(), calloc(); the stack memory regions are allocated by the OS at process startup), so in user-space programming you virtually never need to reference data by literal pointer.
Another possible environments are kernel-space or bare-metal C programs, where you have all the physical memory available to you, but still you must be aware of what you accessing (it may be ports, a gap in the physical memory, it may be reserved by hardware and so on). Programming such environments is an advanced topic and needs good C experience.