I have a program where I want to set up a pointer to a struct as shared memory. I think I've set up the shared memory correctly in the main method; then I call a function to initialize the struct, and fork. However, the child process can't access the shared memory; the parent process works as expected, which isn't that big of a surprise. I know for sure that the child process executes and works, but it cannot access the shared memory, so the function doesn't really do much besides print out printf statements.
struct OverSharedData{
struct SharedData ** rep;
int rop;
};
void initialize( struct OverSharedData * bill){
bill->rep = (struct SharedData**)malloc(sizeof(struct SharedData*)*consumerthreads);
int on =0;
for (on=0; on<consumerthreads; on++) {
*(bill->rep+on) = (struct SharedData *)malloc(sizeof(struct SharedData));
init(*(bill->rep + on), on); //
}}
int main(int argc, const char * argv[])
{
databases(argv[1]); /* Takes care of setting up the database*/
categories(argv[2]); /*Takes care of setting up the book categories*/
bookorders = argv[3];
key_t key = ftok("garbage.txt", 71);
int eyedee = shmget(key, sizeof(struct OverSharedData ),
IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (eyedee == -1)
{
perror("shmget");
exit(1);
}
struct OverSharedData *remp = (struct OverSharedData *) shmat(eyedee, 0, 0);
if (remp == (void *) -1)
{
perror("shmat");
exit(1);
}
initialize(remp);
struct SharedData * d = *(remp->rep + 0);
printf("Hallo\n");
shmctl(eyedee, IPC_RMID, 0);
pid_t forkk = fork();
if (forkk==0) {
/*THIS DOES NOT WORK*/
printf("Entered consumer check: %d\n", remp->rop);
int z = 0;
pthread_t Consumer_Threads[consumerthreads];
for (z=0; z<consumerthreads; z++) {
remp->rop = z;
d = *(remp->rep + z);
d->da = z;
pthread_create((Consumer_Threads+z), 0, Consumer, d);
}
for (z = 0; z<consumerthreads; z++) {
pthread_join(Consumer_Threads[z], NULL);
}
shmdt(remp);
}
else{
/*THIS WORKS*/
printf("Entered Producer: %d\n",remp->rop);
pthread_t Produc;
pthread_create(&Produc, 0, Producer, remp);
pthread_join(Produc, NULL);
printf("Hey guys: %d\n", remp->rop);
shmdt(remp);
}
My guess is that I didn't initialize the struct correctly, but I'm not all too clear what I'm doing wrong. I left out some of the other initializing code but I figured since I can't even access the int in the OverSharedData struct, it's more of a matter where I can't access the struct in the first place.
The problem is that your shared data (the single OverSharedData object) contains pointers to non-shared data. You need to allocate all the data that you want shared in the shared memory segment, rather than with malloc. Something like:
static void *shared_available;
static size_t shared_left;
void init_shared(size_t size) {
key_t key = ftok("garbage.txt", 71);
int eyedee = shmget(key, size,
IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (eyedee == -1) {
perror("shmget");
exit(1); }
shared_available = shmat(eyedee, 0, 0);
if (shared_available == (void *) -1) {
perror("shmat");
exit(1); }
shared_left = size;
}
void *alloc_shared(size_t size) {
void *rv = shared_available;
if (size > shared_left) {
fprintf(stderr, "Ran out of shared memory!\n");
exit(1); }
shared_available = (char *)rv + size;
shared_left -= size;
return rv;
}
OverSharedData *initialize() {
init_shared(sizeof(struct OverSharedData) +
sizeof(struct SharedData *) * consumerthreads +
sizeof(struct SharedData) * consumerthreads)
OverSharedData *bill = alloc_shared(sizeof(OverSharedData));
bill->rep = alloc_shared(sizeof(struct SharedData*)*consumerthreads);
for (int on=0; on<consumerthreads; on++) {
bill->rep[on] = alloc_shared(sizeof(struct SharedData));
init(&bill->rep[on], on); }
}
The above will still have problems if the init routine tries to store pointers to non-shared memory into the SharedData struct (you don't show the definition of either, so we can't say).
If you want to be able to more flexibly allocate and manage shared memory across processes, you really need to use a general purpose shared memory allocator/manager, such as this
Related
I am trying to create Client/Server application based on master/slave architecture. The parent Server is responsible for handling new socket requests from client and uses fork() in which the client interaction happens.
I want to create a Linked List in the application in which the child processes add nodes and it is accessible to every other child. I have tried creating share memory using mmap and shmget but other processes are not able to read the linked list after the first child creates the list.
node structure:
struct node{
char data[1024];
struct node *next;
};
mmap approach:
void* create_shared_memory(size_t size){
int protection = PROT_READ |PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
shmget approach:
void * my_malloc(int size)
{
void * ptr = NULL;
key_current = key_first++;
int shm_id;
if ((shm_id = shmget(key_current, size , IPC_CREAT | 0666)) < 0) {
perror("shmget error.");printf("errno= %d EINVAL=%d \n ", errno , EINVAL);
return NULL;
}
if ((ptr = shmat(shm_id, NULL, 0)) == (void *) - 1) {
perror("shmat error");
//exit(1);
return NULL;
}
current_index ++ ;
shm_id_arr[current_index] = shm_id ;
return ptr;
}
I solved this by creating an array with predefined number of node elements in the parent process using shared memory and initializing all of the indices before the server listens for client requests and uses fork().
#define MAX_NODES 1000
typedef struct node{
char data[1024];
} node;
node *nodes;
void init_array(){
int id;
if((id = shmget(12345, sizeof(node)*MAX_NODES , IPC_CREAT | 0666) < 0){
perror("shmget error");
}
nodes = (node*) shmat(id, NULL, 0);
}
Hi i want to implement a client-server program that communicates with each other via shared memory.
in the server side i have two threads. a writer thread and a reader thread. the writer thread puts some data into the queue and the reader thread reads from it and passes the data to the client side via shared memory.each client that has shmid can attach itself to it and read data from it...
right now i get segmentation fault at client side when it comes to attach to shared memory.
here is my code:
server side:
typedef struct shared_mem {
char imgDir[100];
int client_id;
int read_client;
sem_t shm_sem;
}shared_mem;
shared_mem *shared;
int main(int argc , char *argv[])
{
pthread_t writer_t, reader_t;
queue_t = (struct Queue*) malloc(sizeof(Queue));
queue_t->head = 0;
queue_t->tail = 0;
sem_init(&queue_t->empty, 0, QUEUE_SIZE);
sem_init(&queue_t->full, 1, 0);
int shmid;
key_t key;
key =3434;
//Create the segment and set permissions.
if ((shmid = shmget(key, sizeof(struct shared_mem), IPC_CREAT | 0666)) < 0)
{
perror("shmget error");
if(errno==EEXIST)
{
fprintf(stderr,"shared memory exist... ");
exit(1);
}
}
fprintf(stdout,"shared mem created with id: %d\n",shmid);
if( pthread_create( &reader_t , NULL , reader_thread , &shmid) < 0)
{
perror("could not create reader thread");
return 1;
}
puts("reader thread assigned");
if( pthread_create( &writer_t , NULL , writer_thread , NULL) < 0)
{
perror("could not create writer thread");
return 1;
}
puts("writer thread assigned");
pthread_join(reader_t, NULL);
pthread_join(writer_t, NULL);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
//---------
void *reader_thread(void * id)
{
char imgPath[100];
FILE *image_fd;
char * img_filename;
char imgBuf[1024];
int readed_img_data;
char imgcount[10];
char * shm_addr;
int shm_id = *((int *)id);
shared = (struct shared_mem *) shmat(shm_id, NULL, 0);
if ((int) shared == -1)
{
printf("*** shmat error (server) ***\n");
exit(1);
}
memset(shared, 0, sizeof(struct shared_mem));
sem_init(&shared->shm_sem, 1, 1);
shared->read_client = 0;
shared->client_id = 1;
//printf("shared address: %s", &shared);
while (1)
{
printf("Here in thread reader!\n");
sem_wait(&queue_t->full);
sem_wait(&shared->shm_sem);
if (queue_t->tail != queue_t->head)
{
memmove(imgPath,queue_t->imgAddr[queue_t->head],strlen(queue_t->imgAddr[queue_t->head])-1);
imgPath[strlen(queue_t->imgAddr[queue_t->head])-1] = '\0';
queue_t->head = (queue_t->head + 1) % QUEUE_SIZE;
}
sem_post(&queue_t->empty);
printf("imagepath size: %d...\n",sizeof(imgPath));
memcpy(&shared->imgDir, &imgPath, sizeof(imgPath));
printf("shared contents: %s\n",(char *) &shared->imgDir);
shared->read_client = 0;
sem_post(&shared->shm_sem);
} //end while
if(shmdt(shm_addr) != 0)
fprintf(stderr, "Could not close memory segment.\n");
return 0;
}
clientSide():
typedef struct shared_mem {
char imgDir[100];
int client_id;
int read_client;
sem_t shm_sem;
}shared_mem;
shared_mem *shared;
int main(int argc , char *argv[])
{
char server_data[1024];
int server_data_len = 1024;
char imgDir[100]= "client_/"; // directory where client store image
char imgPath[100]; // image address which client pop from shared memory
char *imgFilename;
char imgcount[10] = "";
int readed_img_data;
int shmid;
key_t key;
key = 3434;
shmid = shmget(key, sizeof(struct shared_mem), 0666);
printf("get shmid: %d\n ", shmid);
if ((shared = (struct shared_mem *) shmat(shmid, NULL, 0)) == (void *) -1)
{
perror("shmat error");
return 1;
}
shared->client_id = 0;
sprintf(imgDir,"%s", shared->imgDir);
//keep communicating with server
while(1)
{
printf("\nReceiving new file...\n");
sem_wait(&shared->shm_sem);
memcpy(&imgPath, &shared->imgDir, 100);
memcpy(&read_client, &shared->read_client, 4);
if (read_client == 0)
read_client = 1;
memcpy(&shared->read_client, &read_client, 4);
sem_post(&shared->shm_sem);
FILE * Client_img = fopen(imgPath,"r");
if (!Client_img)
printf("%s not created!", imgPath);
fseek(Client_img, 0, SEEK_END); // seek to end of file
long size = ftell(Client_img); // get current file pointer
rewind(Client_img);
printf("size: %ld", size);
imgFilename= strrchr(imgPath,'/');
if(imgFilename)
++imgFilename;
else
{
imgFilename = (char*)malloc(100 * sizeof(char));
memmove(imgFilename,imgPath, strlen(imgPath));
}
strcat(imgDir, imgFilename);
printf("imgDir:%s", imgDir);
FILE * written_img = fopen(imgDir, "wa");
int read_sz = fread(server_data, sizeof(char), size, Client_img);
int write_sz = fwrite(server_data, sizeof(char), read_sz, written_img);
fclose(Client_img);
fclose(written_img);
}//while
if(shmdt(shm) != 0)
fprintf(stderr, "Could not close memory segment.\n");
return 0;
}
I would like to create a server-client program in which the two processes pass information between each other using shared memory
information to be passed:
typedef struct shared_mem{
int board[BOARD_SIZE * BOARD_SIZE];
int goal;
}shared_mem;
shared_mem *msg;
server:
int main(int argc, char **argv) {
int shmid;
key_t key=ftok("2048_client", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
/*
* Create the segment
*/
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
(*msg).goal=64;
}
client:
int main(int argc, char **argv) {
int shmid;
key_t key=ftok("2048_client", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
/*
* Create the segment.
*/
if ((shmid = shmget(key, sizeof(msg), 0)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
printf("dscsadc: %d",msg->goal);
}
I am new to shared memory and i would like to understand why it doesn't work and how it is supposed to work. I am getting "shmat: Permission denied"
The problem is that you create the shared memory segment with 0000 permissions, so no-one can read or write it.
Change the shmget() call from:
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT)) < 0) {
to:
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
Only the user running the program can access the shared memory that is created.
Note that POSIX shmget()
says:
The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg.
If you're not limited to C only, look at the boost library. It enables you to create shared memory segments for interprocess communication.
using boost::interprocess;
shared_memory_object shm_obj
(create_only, //only create
"shared_memory", //name
read_write //read-write mode
);
http://www.boost.org/doc/libs/1_54_0/doc/html/interprocess/sharedmemorybetweenprocesses.html
Other then that, you can always use pipes, or if you're thinking about windows - COM.
I am trying to share some data between parent and child process. For the first time I can write and read data to shared memory. However if I want to write one more data, I got truncate error. I know something is wrong with my code. I feel like I need to implement base address part but I don't know how to do it.
void *attach_shmem(int shmem_fd, int object_size){
void *addr;
/* resize it to something reasonable */
if (ftruncate(shmem_fd, object_size) == -1){
perror("failed to resize shared memory object\n");
exit(EXIT_FAILURE);
}
addr = mmap(base, object_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmem_fd, 0);
if (addr == MAP_FAILED){
perror("failed to map shared memory object\n");
exit(EXIT_FAILURE);
}
return addr;
}
void *map_shmem(char *path, int object_size){
int shmem_fd;
/* open one that has already been created */
shmem_fd = shm_open(path, O_RDWR, S_IRUSR | S_IWUSR);
if (shmem_fd == -1){
fprintf(stdout, "failed to open shared memory object\n");
exit(EXIT_FAILURE);
}
return attach_shmem(shmem_fd, object_size);
}
void add_ip_to_shared_memory(char *ip, int val, int num)
{
sem_t *sem = sem_open("/basag_sem", 0);
struct SharedMem *node;
char ip_binary[100];
void *addr;
strcpy(ip_binary, transform_ip_to_bits(ip));
node = malloc(sizeof(struct SharedMem));
strcpy(node->ip, strndup(ip_binary, num));
node->val = val;
//semaphore block
sem_wait(sem);
//add node to shared memory
addr = map_shmem("gungor_shmem", sizeof(*node));
memcpy(addr, node, sizeof(*node));
base = addr;
sem_post(sem);
free(node);
//semaphore release
//write_to_screen(node->ip);
setbuf(stdout, NULL);
}
I am trying to write a code that shares a structure type, but im getting segmentation error when tryign to write in a structure member in the shared memory, the shared memory is between a parent and child process. as im showing in the code, im just tryin to access the struct member for now, so i can use semaphore later for synch.
Thanx in advance.
typedef struct file
{
char *shmPtr;
} file_entry;
int main (void)
{
int shmid;
int n;
file_entry *entries;
if (fork() == 0) {
/*wait for a while*/
if ((shmid = shmget(20441, sizeof(file_entry), 0666)) == -1) {
printf("shmget");
exit(2);
}
entries = (file_entry*) shmat(shmid, 0, 0);
if (entries->shmPtr == (char *) -1) {
printf("problem2");
exit(2);
}
printf("\nChild Reading ....\n\n");
printf("%s\n", entries->shmPtr[0]);
printf("%s\n", entries->shmPtr[1]);
putchar('\n');
printf("\nDone\n\n");
} else {
if ((shmid = shmget(20441, sizeof(file_entry), IPC_CREAT | 0666)) == -1) {
printf("problem3");
exit(2);
}
entries = (file_entry *) shmat(shmid, 0, 0);
if (entries->shmPtr == (char *) -1) {
printf("problem4");
exit(2);
}
printf("done attachment"); /*the parent prints this statment, then segmentation fault*/
entries->shmPtr[0]='a';
entries->shmPtr[1]='b';
putchar('\n');
wait();
shmdt(&shmid);
}
exit(0);
}
shmat returns a pointer to the shared memory area. In your code, after the call to shmat, entries points to the shared region. You are then treating the first few bytes of that shared area as a pointer to char (shmPtr). The value of shmPtr is uninitialized, and it points to some random location. Then you try to write to it and get a segfault.
Edit:
As Richard suggested, you could get rid of the struct and just use a char *. However, I'm guessing the reason you are using a struct and not just a char * is that you are planning to add some extra fields to the struct in the future. If that's the case, you can use a flexible array member:
typedef struct file
{
int flag;
int blah;
char shmPtr[];
} file_entry;
and the allocation becomes
shmget(20441, sizeof(file_entry) + bufsize, IPC_CREAT | 0666)
Of course, if the buffer size is fixed, you could just hardcode it:
typedef struct file
{
int flag;
int blah;
char shmPtr[BUFSIZE];
} file_entry;
/* ... */
shmget(20441, sizeof(file_entry), IPC_CREAT | 0666)