I am implementing IPC using shared memory using mmap. The structure i am using for sharing is
struct shared{
sem_t P;
sem_t C;
sem_t M;
int prod_status;
char** queue;
int buffer_size;
int queue_start;
int queue_after_last; //pointing to buffer index after the last element in the buffer
int queue_count;
};
The size of the buffer is passed as command line argument.
int main(int agrc, char* argv[]){
int N_buff=atoi(argv[1]);
struct shared* shared_data=(struct shared*)mmap(NULL,sizeof(struct shared),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
//printf("hello\n");
shared_data->buffer_size=N_buff;
shared_data->queue=(char**)mmap(NULL,sizeof(N_buff),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
for(int i=0;i<N_buff;i++){
shared_data->queue[i]=(char*)mmap(NULL,70*sizeof(char),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
}
shared_data->queue_start=0;
shared_data->queue_after_last=0;
shared_data->queue_count=0;
shared_data->prod_status=1;
sem_init(&shared_data->P,1,N_buff);
sem_init(&shared_data->C,1,0);
sem_init(&shared_data->M,1,1);};
The queue is accessed by other process. I am using the queue as pipe. The question is, everytime I allocated memory using
shared_data->queue[i]=(char*)mmap(NULL,70*sizeof(char),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
It will allocate whole page of memory. Is there any other memory efficient way of implementing this using mmap? I am using fork after this code to spawn a child process, so I guess I can use pointers for IPC between parent and child using this method.
Your code had some bugs.
The second mmap
call used sizeof(N_buff)
[which is always 4] instead of: sizeof(*shared_data->queue) * N_buff
It is possible to do a single mmap
for all the data [see below].
Here's the annotated and corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/sem.h>
#include <sys/mman.h>
struct shared {
sem_t P;
sem_t C;
sem_t M;
int prod_status;
char **queue;
int buffer_size;
int queue_start;
// pointing to buffer index after the last element in the buffer
int queue_after_last;
int queue_count;
};
int
main(int agrc, char *argv[])
{
int N_buff = atoi(argv[1]);
struct shared *shared_data;
shared_data = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
// printf("hello\n");
shared_data->buffer_size = N_buff;
// NOTE/BUG: sizeof(N_buff) is _always_ 4
#if 0
shared_data->queue = mmap(NULL, sizeof(N_buff), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#else
shared_data->queue = mmap(NULL, sizeof(*shared_data->queue) * N_buff,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#endif
// NOTE: sizeof(char) is _always_ 1
for (int i = 0; i < N_buff; i++) {
shared_data->queue[i] = mmap(NULL, 70,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
shared_data->queue_start = 0;
shared_data->queue_after_last = 0;
shared_data->queue_count = 0;
shared_data->prod_status = 1;
sem_init(&shared_data->P, 1, N_buff);
sem_init(&shared_data->C, 1, 0);
sem_init(&shared_data->M, 1, 1);
}
Here's some cleaned up code for a single mmap [I've compiled but not tested it]:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/sem.h>
#include <sys/mman.h>
#define PERQUEUE 70
struct shared {
sem_t P;
sem_t C;
sem_t M;
int prod_status;
char **queue;
int buffer_size;
int queue_start;
// pointing to buffer index after the last element in the buffer
int queue_after_last;
int queue_count;
};
int
main(int agrc, char *argv[])
{
int N_buff = atoi(argv[1]);
struct shared *shared_data = NULL;
size_t total_size = 0;
total_size += sizeof(struct shared);
total_size += sizeof(*shared_data->queue) * N_buff;
total_size += sizeof(PERQUEUE * N_buff);
void *mapbase = mmap(NULL, total_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
void *mapcur = mapbase;
shared_data = mapcur;
mapcur += sizeof(struct shared);
// printf("hello\n");
shared_data->buffer_size = N_buff;
shared_data->queue = mapcur;
mapcur += sizeof(*shared_data->queue) * N_buff;
for (int i = 0; i < N_buff; i++) {
shared_data->queue[i] = mapcur;
mapcur += PERQUEUE;
}
shared_data->queue_start = 0;
shared_data->queue_after_last = 0;
shared_data->queue_count = 0;
shared_data->prod_status = 1;
sem_init(&shared_data->P, 1, N_buff);
sem_init(&shared_data->C, 1, 0);
sem_init(&shared_data->M, 1, 1);
// stuff ...
munmap(mapbase,total_size);
}