am using C on OSx and using shmget() to get memory to be used between two different programs i
have a structure of 2 int values
does this mean if i want a size of 27 instead it will have to be 54 and how would this work with the pointers used for the structure or any help would be greatly appreciated
No, you need to use sizeof on the struct. You can't guarantee how the implementation will pad the values inside the struct, so you don't assume the size of them. Also, if the size changes later due to adding member(s) to the struct, the memory allocation will still work correctly.
Then use that value from sizeof to multiply by the number of instances of the struct you intend to use in the shared memory area.
Assume you have a struct like this:
typedef struct {
int aCount;
int bCount;
int cCount;
} data_t;
This below function will create shared memory for the specified size.
int shared_memory_create(size_t memory_size)
{
int shm_key = shmget(IPC_PRIVATE, memory_size, IPC_CREAT | IPC_EXCL | 0666);
if(shm_key < 0) {
perror("Failed to Create Shared Memory Key");
exit(0);
}
return shm_key;
}
If you want to create shared memory to accommodate 27 elements, call the function shared_memory_create as shown below:
shm_key = shared_memory_create(27*sizeof(data_t));
Related
I'm doing some programming for an old system which has unreliable dynamic memory allocation functions (malloc, calloc, realloc, etc...).
I started toying with the idea of loading a file without using any of those functions. Designate a pointer with a memory address on which I would get the file content loaded, this pointer would increase as I iterate through the file copying the content I need to my struct variables or assigning the pointers of my internal structs to this new address. Any new file would be loaded at the end address of the previous one.
for a simple structs likes this:
typedef struct A
{
int a;
int b;
int c;
}A;
A a;
I copy the content with a simple memcpy and then increase the pointer
memcpy(&a, pointer_to_the_file, sizeof(A));
pointer_to_the_file += sizeof(A)
This worked fine. For structs on which before I would use some dynamic allocations like:
typedef struct B
{
A* p_a;
A* p_b;
}B;
B b;
I assign the pointers directly:
b->p_a = (B *)pointer_to_the_file;
//then increase the pointer
pointer_to_the_file += sizeof(B) * num_of_p_a_elements;
This also seemed to work OK.
But it was when I move to more complex structures that I started having some problems:
typedef struct C
{
A p_a_1;
A* p_a_2;
B** p_b;
}C;
C *p_c;
Here I don't know how to approach it correctly. I did:
p_c = (C *)pointer_to_the_file;
But I did not get the expected results for p_a_1, although the address of p_c was pointing at the right location where the correct values for p_a_1 were located. I tried using C p_c[0]; and then the values of p_a_1 were correct, but I don't know why that is working so I don't want to build it upon this and then find out later on it causes issues.
Also, I cannot wrap my head about how could I assign p_c->p_b (a non square 2d matrix) using the [0] trick.
Is this at all possible (reading structs like this from a file without using dnyamic memory alloc functions)? If so, what would be the best approach to do it?
I see two routes for this:
Either you use some global variables and implement you own memory allocation (and maybe even replace the one for malloc and co. by linking two your implementation).
Or you a globale buffer to read chunks of the files into memory, like:
uint8_t buffer[1024];
int read_chunk(int fd) {
int bytes_read = 0;
while (bytes_read < 1024) {
ssize_t res = read(fd, &buffer + bytes_read, 1024 - bytes_read);
if (res < 0) return -1;
else if (res == 0) break;
else {
bytes_read += res;
}
}
return bytes_read;
}
and then with a function with the signature
void parse(uint8_t* data, C* p_c);
you can parse you file in stack allocated mempory like.
C p_cs[2];
read_chunk(fd);
for (int i = 0; i < 2; i++) {
parse(&buffer + (sizeof(C)*i), &p_cs[i]);
}
But imho you should go with the first suggestion if possible.
I am developing code to use in the COOJA simulator. I used malloc() for all of the dynamic memory allocations. While the simulation is running, COOJA motes restart periodically and at last I get an error which tells me the reason is I'm using malloc().
I'm thinking of using Contiki's specific memory allocation class named "mmem". I could not found any example of using it. Here is an example in which I used malloc() to allocate memory to a string named sent.
How do I replace using malloc() to use mmem instead of malloc()?
char *sent;
sent = (char*)malloc(120);
strncpy(sent , "example" , 7);
strncat(sent , "|", 1);
From Contiki’s github Wiki
Here is an example of how to use the managed memory allocator:
#include "contiki.h"
#include "lib/mmem.h"
static struct mmem mmem;
static void
test_mmem(void)
{
struct my_struct {
int a;
} my_data, *my_data_ptr;
if(mmem_alloc(&mmem, sizeof(my_data)) == 0) {
printf("memory allocation failed\n");
} else {
printf("memory allocation succeeded\n");
my_data.a = 0xaa;
memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data));
/* The cast below is safe only if the struct is packed */
my_data_ptr = (struct my_struct *)MMEM_PTR(&mmem);
printf("Value a equals 0x%x\n", my_data_ptr->a);
mmem_free(&mmem);
}
}
The example above shows a basic example of how the managed memory
library can be used. On line 4, we allocate a variable, mmem, that
identifies the managed memory object that we are about to allocate. On
line 13, we use the mmem variable as an argument for mmem_alloc() to
allocate space for a structure of sizeof(my_data) bytes. If the
allocation succeeded, we copy the values from an existing structure
into the allocated structure, pointed to by MMEM_PTR(&mmem).
Individual members of allocated structure can then be accessed by a
type cast of MMEM_PTR(&mmem) to struct my_struct *, as shown on line
20. Note that the cast is only safe if the struct is packed. The managed memory is finally deallocated on line 21 by calling
mmem_free().
.
EDIT:
From the code you've pasted in the comments, there is no need to use malloc or the mmem-module. Just allocate on the stack. Maybe try something like this instead:
/* Allocate memory on the stack */
char sent[120];
/* Manipulate strings */
strncpy(sent , "reqid" , 5);
strncat(sent, "|", 1);
/* Send UDP packet */
uip_udp_packet_send(mcast_conn, sent, strlen(sent));
/* Print out string sent */
printf(" (msg: %s)\n", sent);
EDIT 2:
Here is a page on heap vs stack. and here is a stackoverflow question about dynamic allocation on embedded devices and the problems it involves.
This question already has answers here:
C - shared memory - dynamic array inside shared struct
(5 answers)
Closed 5 years ago.
I am working on a server with forking which stores a map(k->v) of strings in shared memory. I want to do it very simplistic but am lost in pointers and in what exactly I need to copy. So I extracted the relevant code which looks like this:
struct key_value {
char key[32];
char value[32];
};
struct key_value **map;
int *map_size;
int shmid = shmget(IPC_PRIVATE, sizeof(struct key_value**), 0600);
map = (struct key_value**) shmat(shmid, 0, 0);
int shmid_size = shmget(IPC_PRIVATE, sizeof(int), 0600);
map_size = (int*) shmat(shmid_size, 0, 0);
*map_size = 0;
//the above happens before fork()
char *c = "abc";
int shmid_struct = shmget(IPC_PRIVATE, sizeof(struct key_value*), 0600);
struct key_value *entry = (struct key_value*) shmat(shmid_struct, 0, 0);
*entry->key = *c;
printf("%s\n", map[0]->key);
//smhdt's & shmctl's
So what I want is to copy that string "abc" from *c into the map so into shared memory. Clearly, I do not yet fully understand pointers and structs so am hoping someone can clear it up. I currently get a segfault 'somewhere in main' (thanks gdb...).
Note that I am ok with the map having a fixed max_size for now (though would be great if dynamic).
EDIT: it's been pointed out in an answer that having a char* in the struct is difficult, so to use char[x] instead. Have updated the code to reflect that, but still not working.
Structures which contain pointers cannot be safely stored in shared memory, as the pointers are meaningless outside the process that created them. Even if the shared memory region is mapped at the same address in each process (which is true if the memory was mapped before a fork(), but may be false in other scenarios), pointers into non-shared memory will not behave properly, as each process may have different data at that address.
If you want to store strings in shared memory, you will need to store them as explicit character arrays, e.g.
struct key_value {
char key[32];
char value[32];
};
or use another scheme, such as storing an offset into a string table in the shared memory region.
Generally speaking, though, shared memory is not a good tool for inter-process communication. If your application depends on being able to share data in memory, threading is probably a better approach.
I'm looking at some example code and trying to figure this out but am stuck. I'm just trying to create a buffer of 10 ints and have my shared memory pointers point to that. Can someone help me understand what this code is actually doing and where I went wrong?
int shmem_id; /* shared memory identifier */
int *shmem_ptr[BUFSIZE]; /* pointer to shared segment */
key_t key = 4455; /* a key... */
int size = 2048; /* 2k memory */
int flag = 1023; /* permissions */
char keystr[10];
sprintf (keystr, "%d", key);
shmem_id = shmget (key, size, flag); /* create a shared memory segment */
shmem_ptr = shmat (shmem_id, (void *) NULL, 1023);
In reality I want it to a buffer of 10 struct items.
typedef struct widget{
char color[10];
};
Your declaration:
int *shmem_ptr[BUFSIZE];
declares shmem_ptr to be an array of pointers to integers. You just want a pointer to integers, so it should be:
int *shmem_ptr;
If the memory points to widget structures, you can do:
typedef struct widget {
char color[10];
} widget;
widget *shmem_ptr;
You don't need to declare the length when declaring a pointer. The length is specified when the shared memory block is created, not in the program that attaches to it.
I've been trying this for hours, and google all the things I kind think of, but I'm going crazy.
I have a struct:
typedef struct {
int rows;
int collumns;
int* mat;
char* IDs_row;
} mem;
I don't know the sizes of the int* (a Matrix) and char* untill later.
When I do, I create the shared memory like this:
mem *ctrl;
int size = (2 + ((i-1)*num_cons))*sizeof(int) + i*26*sizeof(char); //I have the real size now
shmemid = shmget(KEY, size, IPC_CREAT | 0666);
if (shmemid < 0) {
perror("Ha fallado la creacion de la memoria compartida.");
exit(1);
}
ctrl = (mem *)shmat(shmemid, 0, 0);
if (ctrl <= (mem *)(0)) {
perror("Ha fallado el acceso a memoria compartida");
exit(2);
}
No problem here. Then I give a value to ctrl->rows and collumns, and assign 0 to all the matrix.
But after that, I write something in the char* and bam, segmentation fault.
Debugging the program I saw that both pointers, mat and IDs_row where null. How do I give them the correct values inside the shared memory segment??
I tried removing the char* pointer, just to give it a try, and then the segmentation fault error was in the other program that connected to said shared memory and just checked the values inside the matrix (checking ->rows and ->collumns was succesfull)
First of all, putting absolute pointers in shared memory segments is terrible terible idea - those pointers would only be valid in the process that filled in their values. Shared memory segments are not guaranteed to attach at the same virtual address in every process. On the contrary - they attach where the system deems it possible when shmaddr == NULL is specified on call to shmat(). You could specify the same virtual address when calling shmat() but it is up to you to ensure that nothing else is mapped on that memory region in all participating processes. This is hard to do in a portable manner. What you would most like to do is to either:
1) Allocate one big shared memory segment that accomodates both the mem structure and the two data arrays. Then you should put not absolute pointers but rather pointers relative to the beginning of the memory block and then adjust on usage.
2) Allocate three different shared memory segments but instead of putting pointers, put the shared memory IDs as returned by shmget():
typedef struct {
int rows;
int collumns;
int mat_id;
int IDs_row_id;
} mem;
When you need to access the matrix or the IDs array just attach to the shared memory ID stored in the corresponding field.
Pay attention though that using the same KEY in subsequent invocations of shmget() will not produce the expected result unless KEY == IPC_PRIVATE. It is best to use a the fixed key value for the shared memory block with the descriptor (of type mem) and IPC_PRIVATE for the other two memory blocks otherwise the three calls will actually return the same shared memory block - the first one will create it and the next two will simply return its ID since a block with that key already exists.
ctrl = (mem *)shmat(shmemid, 0, 0);
This only assigns valid memory to the ctrl pointer, not to ctrl->mat or ctrl->IDs_row.
You probably want:
mem *ctrl;
shmemid = shmget(KEY, sizeof(ctrl), IPC_CREAT | 0666);
//allocate memory for the structure
ctrl = (mem *)shmat(shmemid, 0, 0);
//allocate memory for the int*
shmemid = shmget(KEY,((i-1)*num_cons))*sizeof(int), IPC_CREAT | 0666);
ctrl->mat = (int*)shmat(shmemid, 0, 0);
//allocate memory for the char*
shmemid = shmget(KEY,i*26*sizeof(char), IPC_CREAT | 0666);
ctrl->IDs_row = (char*)shmat(shmemid,0,0);