Unable to access the shared memory contents - c

I 'm working on a sample program on mmap and shared memory. Here is the piece of code I was trying,
Process B
#include<stdio.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<malloc.h>
typedef struct sh_mem_t{
int offset;
char *buffer;
}sh_mem;
int main(){
int fd;
sh_mem *shm_obj;
fd = shm_open("/myshm",O_RDWR,0777);
if(fd == -1){
perror("fd:ERROR");
return -1;
}
shm_obj = mmap(0,sizeof(sh_mem),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(shm_obj == MAP_FAILED){
perror("shm_obj:ERROR");
return -1;
}
printf("\n offset : %d \n",shm_obj->offset);
// printf("\n Good work! : %s \n",shm_obj->buffer);
return 0;
}
Process A
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<sys/sem.h>
typedef struct sh_mem_t{
int offset;
char *buffer;
}sh_mem;
int main(int argc,char *argv[]){
int file_size = 0;
int fd_sh = 0;
sh_mem *shmptr = NULL;
int fd = 0;
char offset[2];
int no_bytes_read = 0;
int read_size = 10;
int count = 0;
int ret_val = 0;
/* Variables for semaphore */
int ret = 0;
int semid = 0;
key_t sem_key = 0;
struct sembuf op[1];
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
};
union semun arg;
/* Validate the i/p parameters */
if(argc < 3){
perror("argc:Did u forget the I/P file and the count 0?");
return -1;
}
printf("File : %s",argv[1]);
count = atoi(argv[2]);
/* Create a semaphore */
semid = semget(sem_key,1,IPC_CREAT | 0777);
if(semid == -1){
perror("semid:");
return -1;
}
arg.val = 1;
ret = semctl(semid,0,SETVAL,arg);
/* Open the file to read the contents */
fd = open(argv[1],O_RDONLY);
/* Calculate the total size of the file */
file_size = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
printf("\n File Size is : %d \n",file_size);
/* Create a new memory object */
fd_sh = shm_open("/myshm",O_RDWR | O_CREAT,0777);
/* Set the memory object's size */
if((ftruncate(fd_sh,sizeof(sh_mem))) == -1){
perror("ftruncate:ERROR");
return -1;
}
/* Map the Memory object */
shmptr = mmap(0,sizeof(sh_mem),PROT_READ | PROT_WRITE,MAP_SHARED,fd_sh,0);
/* Allocate the memory for the buffer */
shmptr->buffer = malloc((sizeof(char)*file_size));
printf("\nThe Map address is : 0x%08x\n",shmptr);
/* Copy the contents to the shared memory */
read(fd,&offset,1);
if(count == 0){
shmptr->offset = 0;
}
while(shmptr->offset < file_size){
/* Semaphore section Start */
op[0].sem_num=0;
op[0].sem_op=-1;
op[0].sem_flg=0;
semop(semid,op,1);
printf("\n ProcessA Entering! \n");
printf("\n initial offset value : %d \n",shmptr->offset);
if(shmptr->offset > 0){
shmptr->buffer = shmptr->buffer + shmptr->offset;
ret_val = lseek(fd,shmptr->offset,SEEK_SET);
}
no_bytes_read = read(fd,shmptr->buffer,read_size);
shmptr->offset = (read_size + shmptr->offset);
printf("\n offset : %d \n",shmptr->offset);
printf("\n contents : %s \n",shmptr->buffer);
sleep(10);
op[0].sem_op = 1;
semop(semid,op,1);
printf("\n ProcessA Leaving ! \n");
/* Semapore section End*/
}
/* Detach from the shared memory */
shmdt(shmptr);
close(fd);
close(fd_sh);
return 0;
}
I have process A, which has put the data into the shared memory containing the structure values offset and buffer. Process B wants to access the contents stored in the shared memory(offset,buffer), but I could able to access only offset. When tried to access the buffer i'm getting a segmentation fault. Why am i getting a seg fault. As the shared object is mapped to the shared memory.
Process A will put 10 bytes into the shared memory and will go to sleep, then again it continues to put the next 10 bytes and so on.

When tried to access the buffer i'm getting a segmentation fault.
buffer is declared as pointer as part of your mapped memory:
typedef struct sh_mem_t{
int offset;
char *buffer;
}sh_mem;
Transferring pointers between processes does not make sense, since the pointer does not have any meaning in the slave process - the data it points to still resides in the master process.
You need to include the actual data you want to transfer from master to slave process:
typedef struct sh_mem_t{
int offset;
char buffer[BUFSIZE];
}sh_mem;
With the updated code in the question, the following changes are necessary to make it work:
In both A and B, change the declaration of the shared memory struct to something like
typedef struct sh_mem_t{
int offset;
char buffer[1024];
}sh_mem;
In A, remove the malloc() for shmptr->buffer. Also remove the line where you adjust the buffer by adding the offset (shmptr->buffer = shmptr->buffer + shmptr->offset;) - that needs to be handled differently, if you still need it
In B, uncomment the line which prints the Good work! output.
With these changes, I was able to start the A process like ./A data.txt 0. When I then start the B process, it prints both offset and buffer content, as it was last printed by the A process.
Some additional remarks
You should use a header file to declare the sh_mem struct, and include this file in both your .c files, to make sure the declaration is consistent between A and B.
With the solution I posted above, the application will crash with file sizes > 1024. You need to handle this accordingly, to make sure to not exceed the buffer size.
Why isnt it working with pointers
You can not access (non-shared) memory from the master process in the slave process, especially not by simply passing a pointer through the shared memory (this would make the shared memory concept obsolete). The memory which you allocated with malloc() in your master process is not part of the shared memory segment, so it is not accessible from the slave process.
In addition, mmap(), by default, is not guaranteed to return the same virtual address in both processes. So, even when you pass a pointer which points to a location inside the shared memory segment in the master, it does not point anywhere useful inside the slave process, unless you pass specific parameters to mmap(). See mmap(2) for more details.

Related

Accessing a shared memory buffer in another process

I am trying to solve the producer consumer problem using mutexes and a shared buffer, but am having trouble accessing values in my shared buffer struct, specifically the char array. When I invoke the producer.c file in one terminal and print the values (the input is a txt file of the alphabet) using
printf("%c", newBuff->bytes[newBuff->rear]);
the chars do appear as normal, however when I do the same thing in consumer.c, but with
printf("%c", newBuff->bytes[newBuff->front]);
the values appear blank. The newBuff->front value is zero, so it should print the letter a. When I access other values in my struct in consumer.c like front, count, or rear they are correct. Share memory creation as well as attachment also works properly so I believe the issue is either I am not storing the char values properly in the array or I am trying to access them incorrectly. In the code below I placed the printf in the loop for producer.c and then outside the loop for consumer.c so I know for a fact a value is present before the consumer starts extracting data.
Consumer.c
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
int count;
int endOfFile;
char bytes[1024];
} buffer;
int main(int argc, char const *argv[]) {
int i=0;
FILE *file = fopen(argv[1], "w");
if (argc != 2){
printf("You must enter in a file name\n");
}
int shmid, swapCount=0;
char swapBytes[] = "";
char path[] = "~";
key_t key = ftok(path, 7);
buffer* newBuff;
if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("successful creation\n");
newBuff->front = 0;
newBuff->count = 0;
newBuff->endOfFile = 0;
pthread_mutexattr_t attr;
pthread_condattr_t condAttr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&newBuff->lock, &attr);
pthread_condattr_init(&condAttr);
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&newBuff->shout, &condAttr);
} //shared memory creation
else if ((shmid = shmget(key, 0, 0)) != -1){
printf("%d\n", shmid);
printf("successful attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("%c\n", newBuff->count);
}
else{
printf("oops\n");
exit(0);
}
pthread_mutex_lock(&newBuff->lock);
printf("%c\n", newBuff->bytes[newBuff->front]);
while (newBuff->endOfFile != 1)
{
while (newBuff->count == 0){
pthread_cond_signal(&newBuff->shout);
pthread_cond_wait(&newBuff->shout, &newBuff->lock);
}
newBuff->front = ((newBuff->front + 1)%SIZE);
newBuff->count--;
}
pthread_mutex_unlock(&newBuff->lock);
shmdt(&newBuff);
//pthread_mutexattr_destroy(&attr);
//pthread_condattr_destroy(&condAttr);*/
return 0;
}
Producer.c
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
int count;
int endOfFile;
char bytes[1024];
} buffer;
int main(int argc, char const *argv[]) {
FILE *file = fopen(argv[1], "r");
if (argc != 2){
printf("You must enter in a file dumbass\n");
}
int shmid;
char path[] = "~";
key_t key = ftok(path, 7);
buffer* newBuff;
printf("dfasdfasdf\n");
if ((shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL)) != -1) {
newBuff = (buffer*) shmat(shmid, 0, 0);
printf("successful creation\n");
newBuff->front = 0;
newBuff->count = 0;
newBuff->endOfFile=0;
pthread_mutexattr_t attr;
pthread_condattr_t condAttr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&newBuff->lock, &attr);
pthread_condattr_init(&condAttr);
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&newBuff->shout, &condAttr);
} //shared memory creation
else if ((shmid = shmget(key, 0, 0)) != -1){
printf("successful attachment\n" );
newBuff = (buffer*) shmat(shmid, 0, 0);
}
else{
printf("oops\n");
exit(0);
}
printf("%d\n", shmid);
pthread_mutex_lock(&newBuff->lock);
while (fscanf(file, "%c", &newBuff->bytes[newBuff->rear]) != EOF) //read in file
{
printf("%c\n", newBuff->bytes[newBuff->rear]);
while (newBuff->count >= SIZE){ //buffer is full
//("%c\n", newBuff->bytes[newBuff->rear]);
pthread_cond_signal(&newBuff->shout);
pthread_cond_wait(&newBuff->shout, &newBuff->lock);
}
//printf("%c\n", newBuff->bytes[newBuff->rear]);
newBuff->rear = ((newBuff->front + 1)%SIZE);
newBuff->count++;
}
newBuff->endOfFile = 1;
pthread_cond_signal(&newBuff->shout);
pthread_mutex_unlock(&newBuff->lock);
shmdt(&newBuff);
//pthread_mutexattr_destroy(&attr);
//pthread_condattr_destroy(&condAttr);
return 0;
}
There are several difficulties with your code, some already addressed in comments:
ftok() requires the path passed to it to designate an existing file, but the path you are passing does not.
You request less shared memory than you actually need: only the size of the buffer content, not of a whole struct buffer. Because the amount of shared memory actually allocated will be rounded up to a multiple of the page size, this may end up being ok, but you should ensure that it will be ok by requesting the amount you actually need.
System V shared memory segments have kernel persistence, so once created, they will continue to exist until they are explicitly removed or the system is rebooted. You never remove yours. You also initialize its contents only when you first create it. Unless you manually delete it between runs, therefore, you'll use old data -- with the end-of-file indicator set, for instance -- on the second and subsequent runs. I suggest having the consumer schedule it for removal.
The consumer prints only one byte of data from the buffer, and it does so before verifying that there is anything to read.
After adding a byte to the buffer, the producer does not update the available byte count until after signaling the consumer. At best, this is wasteful, because the consumer will not see the change in count until the next time (if any) it wakes.
The producer updates the rear index of the buffer incorrectly, based on the current front value instead of on the current rear value. The data will therefore not be written into the correct places in the buffer array.
Once the producer sets the endOfFile flag, the consumer ignores all but one of any remaining unread bytes.
If the producer leaves the count zero when it finishes, the consumer will deadlock.
I find that modified versions of your programs addressing all of these issues successfully and accurately communicate data through shared memory.
Update:
Also,
The way in which consumer and / or producer initializes the mutex and condition variable is not itself safe. It is possible for whichever process attempts the shmget() second (or third, or ...) to access those objects before the first finishes initializing them. More generally, once a shared memory segment is attached, there is no inherent memory barrier involved in writing to it. To address these issues, the natural companion to SysV shared memory is SysV semaphores.

Can't read a file using producer-consumer thanks to processes and semaphores

Generalities and functioning of my program
NB : you will be able to test my program (only one file, containing the main function). I give you the entire code at the end of this question.
I wrote a program which can be used to illustrate the producer-consumer algorithm, with UNIX-Processes. The producer creates some value, for example 5, writes it into a RAM shared_buffer and then writes the latter into a file test.txt. The consumer assigns to this shared_buffer the content of the file test.txt and takes some value from the RAM buffer, shared_buffer.
I use functions to convert my shared_buffer into the file, and reciprocally : arrayToFile and fileToArray. Both are presented at the end of this question.
The shared_buffer has a size of 1 + 10 cases : the first one contains the number of full cases (ie. : with a 5 writen) and the 10 others can be filled either with 5 or nothing.
The first case is useful for the producer, to know where to write next value (ie. : in which case).
The file of course has also 1 + 10 cases. The file is needed because I use processes and not threads (not-shared memory, thus).
shared_buffer's initialisation is contained in the main function. shared_buffer's accesses (in reading and in writing) are contained in consumer's function and in producer's function, respectively. These codes are presented at the end of this question.
Access to shared_buffer and overall to the file are of course under mutual exclusion and three semaphores are used. The mutexe impedes producer and consumer to access it at the same time, and the two other semaphores are used to guarantee that the producer won't try to put a new element if there isn't enough place, and that the consumer won't try to take an element if there isn't any element. Well, it's just the producer-consumer algorithm.
Finally, producer's process runs until the end of time, and so does the consumer's process.
The declaration and initialisation of these three semaphores are presented at the end of this question.
My problem
There is only one problem : when both producer's process and consumer's process are running until the end of times while(TRUE), arrayToFile and fileToArray tell me that the file's opening failed. If I erase one or both while(TRUE), this error disapears (but thus, my program doesn't make its job).
So this problem appears only when both while(TRUE) are writen.
I think it's because I don't make good use of the mutexe. But I couldn't give you more explanations.
Source
Code is highly commented.
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/sem.h>
#include <stdlib.h>
#define TRUE 1
#define ERR_NBR_ARGS "ERROR. Argument needed. Use as follows.\n"
int fileToArray(char *, int *, int);
int arrayToFile(char *, int *, int);
void check_if_command_arguments_are_correct(int);
void mutual_exclusion_produce(int, char*, int*, int);
void mutual_exclusion_consume(int, char*, int*, int);
int main(int argc, char* argv[]) {
check_if_command_arguments_are_correct(argc);
// FILE'S PATH
char* file_path = argv[1];
// DECLARATION AND INITIALISATION OF THE SHARED RESOURCE
int shared_buffer_number_of_elements = 10;
int shared_buffer[shared_buffer_number_of_elements + 1];
shared_buffer[0] = 0;
arrayToFile(file_path, shared_buffer, shared_buffer_number_of_elements);
// FILE'S KEY (used to make processes able to use the same semaphores)
key_t key = ftok(argv[0], '0');
if(key == - 1) {
perror("ftok");
exit(EXIT_FAILURE);
}
// DECLARATION AND INITIALISATION OF THE THREE SEMAPHORES
int semid = semget(key, 3, IPC_CREAT|IPC_EXCL|0666); // Declaration of the semaphores
if(semid == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
int array_semaphores_values[3];
array_semaphores_values[0] = 1;
array_semaphores_values[1] = shared_buffer_number_of_elements;
array_semaphores_values[2] = 0;
int sem_controller = semctl(semid, 3, SETALL, array_semaphores_values); // Initialisation of the semaphores - 2th parameter is the array's size
if(sem_controller == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
// THE TWO FORKS - CREATION OF BOTH PRODUCER AND CONSUMER
pid_t producer = fork();
if(producer == -1) {
perror("fork");
exit(EXIT_FAILURE);
} else if(producer == 0) { // The producer process
mutual_exclusion_produce(semid, file_path, shared_buffer, shared_buffer_number_of_elements);
} else { // The main process
pid_t consumer = fork();
if(consumer == - 1) {
perror("fork");
exit(EXIT_FAILURE);
} else if(consumer == 0) { // The consumer process
mutual_exclusion_consume(semid, file_path, shared_buffer, shared_buffer_number_of_elements);
}
}
semctl(semid, 0, IPC_RMID, 0); // The semaphores are freed
}
void mutual_exclusion_produce(int semid, char* file_path, int* buffer, int size) {
/* The producer does the following :
* 1. It decrements the free cases semaphore ;
* 2. It decrements the mutex ;
* 3. It writes the buffer
* 4. It increments the mutex ;
* 5. It increments the full cases semaphore ;
* */
while(TRUE) {
// DECREMENTS FREE CASES SEMAPHORE AND DECREMENTS MUTEX
struct sembuf operation_decrement_free_cases;
operation_decrement_free_cases.sem_num = 2;
operation_decrement_free_cases.sem_op = -1;
operation_decrement_free_cases.sem_flg = 0;
struct sembuf operation_decrement_mutex;
operation_decrement_mutex.sem_num = 0;
operation_decrement_mutex.sem_op = -1;
operation_decrement_mutex.sem_flg = 0;
semop(semid, &operation_decrement_free_cases, 0);
semop(semid, &operation_decrement_mutex, 0);
// WRITES THE BUFFER INTO THE FILE
buffer[++buffer[0]] = 5;
arrayToFile(file_path, buffer, size);
// INCREMENTS THE MUTEX AND INCREMENTS THE FULL CASES SEMAPHORE
struct sembuf operation_increment_full_cases;
operation_decrement_free_cases.sem_num = 1;
operation_decrement_free_cases.sem_op = +1;
operation_decrement_free_cases.sem_flg = 0;
struct sembuf operation_increment_mutex;
operation_decrement_mutex.sem_num = 0;
operation_decrement_mutex.sem_op = +1;
operation_decrement_mutex.sem_flg = 0;
semop(semid, &operation_increment_mutex, 0);
semop(semid, &operation_increment_full_cases, 0);
}
}
void mutual_exclusion_consume(int semid, char* file_path, int* buffer, int size) {
/*
* The consumer does the following :
* 1. It decrements the full cases semaphore ;
* 2. It decrements the mutex ;
* 3. It reads the buffer ;
* 4. It increments the mutex ;
* 5. It increments the free cases semaphore ;
* */
while(TRUE) {
// DECREMENTS FULL CASES SEMAPHORE AND DECREMENTS MUTEX
struct sembuf operation_decrement_full_cases;
operation_decrement_full_cases.sem_num = 1;
operation_decrement_full_cases.sem_op = -1;
operation_decrement_full_cases.sem_flg = 0;
struct sembuf operation_decrement_mutex;
operation_decrement_mutex.sem_num = 0;
operation_decrement_mutex.sem_op = -1;
operation_decrement_mutex.sem_flg = 0;
semop(semid, &operation_decrement_full_cases, 0);
semop(semid, &operation_decrement_mutex, 0);
// READS THE FILE AND PUT THE CONTENTS INTO THE BUFFER
fileToArray(file_path, buffer, size);
// INCREMENTS THE MUTEX AND INCREMENTS THE FREE CASES SEMAPHORE
struct sembuf operation_increment_free_cases;
operation_decrement_full_cases.sem_num = 2;
operation_decrement_full_cases.sem_op = +1;
operation_decrement_full_cases.sem_flg = 0;
struct sembuf operation_increment_mutex;
operation_decrement_mutex.sem_num = 0;
operation_decrement_mutex.sem_op = +1;
operation_decrement_mutex.sem_flg = 0;
semop(semid, &operation_increment_mutex, 0);
semop(semid, &operation_increment_free_cases, 0);
}
}
void check_if_command_arguments_are_correct(int argc) {
if(argc != 2) {
fprintf(stderr, ERR_NBR_ARGS);
fprintf(stderr, "program_command <file_buffer>\n");
exit(EXIT_FAILURE);
}
}
int fileToArray(char *pathname, int *tab, int size) {
int cible;
if ( (cible = open(pathname,O_RDONLY)) < 0){
fprintf(stderr,"fileToArray - impossible to open the file\n");
return -1;
}
if (read(cible,tab,(size+1) * sizeof(int)) !=(size+1) * sizeof(int)) {
fprintf(stderr,"fileToArray - impossible to read the file\n");
return -1;
}
close(cible);
return 0;
}
int arrayToFile(char *pathname, int *tab, int size) {
int cible;
if ( (cible = open(pathname,O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0){
fprintf(stderr,"arrayToFile - impossible to open the file\n");
return -1;
}
if (write(cible,tab,(size+1) * sizeof(int)) !=(size+1) * sizeof(int)) {
fprintf(stderr,"arrayToFile - impossible to write the file\n");
return -1;
}
close(cible);
return 0;
}

Segmentation Fault occurs after using global variable in several function

I'm currently programming my Bachelor Project what consists an RFB-Client and a Shared Memory. The initialisation of the RFB-Client is done, the Shared Memory is created. My teacher told me to decouple the code and I wrote several functions and used a global variable for the shared memory.
But now a segmentation fault occurs while trying to read the content of the global variable. I debugged the code and found out: The content of the global variabel "my_shm" is always "0x00" :-/
Could you please help me?
These are the portions of code where the problem occurs:
(I know, this is a long code, but sending just parts of it would be useless...)
char *my_shm; --> //global variable
int SHM_init (int shmid, char* shm, key_t key, long int size) {
/* Create a new (System V) shared memory segment of the specified size */
shmid = shmget(key, SHM_SIZE, IPC_CREAT|0777);
/* Check if SHM creation was successful */
if (shmid < 0) {
/* DBG: Debug message to show which point of the program has been passed */
DBG_PRINT("C\n");
/* Check if creation failed because of already existing SHM */
if (EEXIST == errno) {
/* DBG: Debug message to show which point of the program has been passed */
DBG_PRINT("CC\n");
/* Delete already existing SHM with shmctl */
shmctl(shmid, IPC_RMID, NULL);
} else {
/* DBG: Debug message to show which point of the program has been passed */
DBG_PRINT("CCC\n");
}
/* Creation and initialization of SHM failed */
return -1;
}
/* Attach the SHM data pointer to the previously created SHM segment */
shm = shmat(shmid, NULL, 0);
if(shm == (char *) -1) {
/* Attaching failed */
return -1;
}
DBG_PRINT("Shared Memory Initialization successful\n");
/* Creation and initialization of shared memory was successful */
return 0;
}
void RFB_update(rfbClient* client) {
DBG_PRINT("RFB_update called\n");
int i,j;
rfbPixelFormat* pformat=&client->format;
DBG_PRINT("A\n");
/*bytesPerPix: variable which stores Bytes per Pixel*/
int bytesPerPix = pformat->bitsPerPixel/8;
DBG_PRINT("B\n");
/*row= width of frame*bytes per Pixel*/
int row=client->width*bytesPerPix;
DBG_PRINT("C\n");
char byte_to_write;
//as long as j is smaller than 128*(width*bytesPerPix)
for(j=0;j<client->height*row;j+=row) {
//as long as i is smaller than 128 * bytesPerPix
for(i=0;i<client->width*bytesPerPix;i+=bytesPerPix) {
/*frameBuff: Pointer on FrameBuffer*/
unsigned char* frameBuff = client->frameBuffer+j+i;
unsigned int v;
if(bytesPerPix==4)
v=(unsigned int*)frameBuff;
byte_to_write = ((v>>pformat->redShift)*256/(pformat->redMax+1));
SHM_write_byte(my_shm,byte_to_write);
byte_to_write = ((v>>pformat->greenShift)*256/(pformat->greenMax+1));
SHM_write_byte(my_shm,byte_to_write);
byte_to_write = ((v>>pformat->blueShift)*256/(pformat->blueMax+1));
SHM_write_byte(my_shm,byte_to_write);
}
}
DBG_PRINT("RFB_update successful, Shared Memory is filled\n");
}
int SHM_write_byte (char** shm, char byte) {
/*Check if pointer to SHM is valid */
if (shm == (char **) -1) {
/* Pointer is invalid */
return -1;
}
shm = byte;
shm++;
return 0;
}
int main (int argc, char *argv[]) {
if (SHM_init(shmid, my_shm, SHM_KEY, SHM_SIZE) != 0) {
DBG_PRINT("Shared Memory initialized\n");
/* Couldn't initialize SHM,initializing failed */
return -1;
}
/* Initialize RFB Client */
if (RFB_client_init(rfb_client, (FinishedFrameBufferUpdateProc)RFB_update) != 0) {
DBG_PRINT("Couldn't initialize client\n");
/* Couldn't initialize Client,initializing failed */
return -1;
}
--> everywhere the variable "my_shm" is used: the content is: 0x00...
This seems to be a very common problem here on stackoverflow.com today, and the problem is that you pass arguments to function by value and not by reference.
What that means is that when you pass an argument to a function, its value is copied, and the function only work on the copy locally inside the function. As you should know, modifying a copy will of course not modify the original.
C does not have pass by reference, but it can be emulated by using pointers. In your case, since you have a pointer you need to pass a pointer to the pointer using the address-of operator, like
SHM_init(shmid, &my_shm, SHM_KEY, SHM_SIZE)
// ^
// |
// Note ampersand (address-of operator) here
You of course need to modify the function to actually accept a pointer to the pointer:
int SHM_init (int shmid, char** shm, key_t key, long int size)
And of course use the dereference operator * when using the variable:
*shm = shmat(shmid, NULL, 0);

Sharing an array of structs using mmap

I am trying to create an array of structs that is shared between a parent and child processes. I am getting a segmentation fault when trying to access the array data.
I feel certain that the problem has something to do with the way I'm using pointers, as this is an area I'm not very comfortable with.
Please note that I edited out most of the code that didn't seem relevant.
/* structure of Registration Table */
struct registrationTable{
int port;
char name[MAXNAME];
int req_no;
};
main() {
/* the registrationTable is to be a shared memory space with each child
process able to access and update. No concurrency controls are
implemented. The parent process is responsible for cleaning up after
the kiddies.
*/
struct registrationTable base_table[REG_TABLE_SIZE];
for (int i = 0; i < REG_TABLE_SIZE; i++) {
base_table[i].req_no = 0;
memset(base_table[i].name, '\0', MAXNAME);
base_table[i].port = 0;
}
printf("\nMapping Shared Memory\n");
//set up shared memory space
//void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
// addr = NONE, prot = PROT_NONE, flags = MAP_SHARED
struct registrationTable *table = mmap(base_table, sizeof(base_table),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
while(1){
pid_t child = fork();
if (child == 0) {//is child
for(int i = 0; i < REG_TABLE_SIZE; i++) {
printf("\nExamining table looking for client at %s port: %d\n",
packet_reg.data, clientAddr.sin_port);
printf("\ntable[1].req_no: %d", ta[i].req_no);
//segmentation fault on next line
if (strcmp(table[i].name, packet_reg.data) == 0
&& table[i].port == clientAddr.sin_port) {
table[i].req_no++;
}
You haven't initialized content of the table after it was allocated by mmap. So it contains garbage. And so strcmp(table[i].name, packet_reg.data) has a great chance to go over allocated buffers and access e.g. non-allocated memory.
initialize table properly;
use strncmp for the comparison there.

how to pass data using shared memory and save the received data to file

I am new to linux environment. I just know the basics of C. I am trying to learn linux programming. For this I am trying an example on shared memory. Please someone help me with this example.
I am trying to send person details (like name, phone number & address) to another process using Shared memory. After receiving the data by the second process, I am trying to save received data into a file. This is the task I am doing.
I am able to send just the name and receive it in the second process. Can someone please help how to send the data(like name, phone number & address) to second process and in the second process it must print the data and it should save the data to a file.
Here is my code:
address.c
char *shared_memory;
int main()
{
int select;
int segment_id;
char* shared_memory;
int segment_size;
key_t shm_key;
const int shared_segment_size = 0x6500;
shm_key = ftok("/home/madan/programs/shm_tok",'C');
if(shm_key < 0) {
printf("failed to create the key %s\n",strerror(errno));
}
/* Allocate a shared memory segment. */
segment_id = shmget (shm_key, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
if(segment_id < 0) {
printf("error geting the segment id %s\n",strerror(errno));
}
printf("segment ID:%d\n", segment_id);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p\n", shared_memory);
/* I want to send these details to the shared memory. Can someone suggest me the correct way to send these details to shared memory so that second process can retrieve them*/
sprintf(shared_memory, "maddy\n");
sprintf(shared_memory, "767556686");
sprintf(shared_memory, "Ontario");
system("./address-insert");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/
* Deallocate the shared memory segment.*/
shmctl (segment_id, IPC_RMID, 0);
}
addres-insert.c
int main ()
{
int segment_id;
char* shared_memory;
FILE *fp;
char *name;
int segment_size;
key_t shm_key;
shm_key = ftok("/home/madan/programs/shm_tok",'C');
const int shared_segment_size = 0x6500;
/* Allocate a shared memory segment. */
segment_id = shmget (shm_key, shared_segment_size,
S_IRUSR | S_IWUSR);
if(segment_id < 0) {
printf("error:[%s]",strerror(errno));
}
printf("segment id %d\n",segment_id);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
if(shared_memory == NULL) {
printf("failed to attach the shared memory %s",strerror(errno));
}
printf ("shared memory2 attached at address %p\n", shared_memory);
/* printing the data from shared memory send by first process*/
printf ("name=%s\n", shared_memory);
/*copying the data in shared memory so i can save them to a file*/
strcpy(name, shared_memory);
printf("%s", name);
/*here i have to save the data to a file. But i don't know how to do it, can someone help me with this please*/
/* Detach the shared memory segment. */
shmdt (shared_memory);
return 0;
}
For saving the data in a file, you can use file stream. For that you have to know about file streams.
Hope these link will help.
http://linux.die.net/man/3/fopen
http://en.wikipedia.org/wiki/C_file_input/output
Here comes the example program which I particularly typed, compiled and attached it for your reference.
#include<sys/types.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
struct mystruct // you can make your own structure if you want to pass many data
{
int i;
float f;
char c;
int arr[3];
}myObj = {1,1.1,'C',{100,1000,10000}};
main()
{
int shmid;
char* addr1;
key_t key;
//file to key. Generates a unique key
key = ftok("/home/muthu/Desktop/anyfile.txt",'T');
shmid = shmget(key,sizeof(struct mystruct),IPC_CREAT|SHM_R|SHM_W);
printf("shmid = %d",shmid);
addr1 = shmat(shmid,0,0);
printf("\nIPC SHARED MEMORY");
//copying your structure at the shared location.
memcpy(addr1,&myObj,sizeof(myObj));
printf("\nMESSAGE STORED");
}
And for shared memory 2.....
//<All necessary header files>
//<same my struct declaration here>
main()
{
int shmid;
char* addr1;
FILE* fp;
key_t key;
struct mystruct* myObj2;
//Generate the same unique key. Must provide the same file here too.
key = ftok("/home/muthu/Desktop/anyfile.txt",'T');
shmid = shmget(key,sizeof(struct mystruct),SHM_R|SHM_W);
addr1 = shmat(shmid,0,0);
myObj2 = (struct mystruct*)malloc(sizeof(struct mystruct)*1);
if(shmid == -1)
printf("\nShared memory error");
//Retrieve the stored information, form the shared location.
memcpy(myObj2,addr1,sizeof(struct mystruct));
fp = fopen("/home/muthu/Desktop/MyFile.txt","w"); //open a file stream
if(fp == NULL)
printf("\nError on opening file stream.\n");
fprintf(fp,"\nIPC SHARED MEMORY");
fprintf(fp,"\nMESSAGE RECIEVED FORM THE SHARED MEMORY IS..\n");
fprintf(fp,"\ninteger: %d",myObj2->i);
fprintf(fp,"\nfloat: %f",myObj2->f);
fprintf(fp,"\nchar: %c",myObj2->c); //write to the file
fprintf(fp,"\narr: %d %d %d",myObj2->arr[0],myObj2->arr[1],myObj2->arr[2]);
fprintf(fp,"\nDATA RECIEVED.");
fclose(fp); //close the file stream
printf("\nMessage successfully stored!");
}
Here is a snippet that you can use
fp = fopen("filename","a+");
fwrite(name, 1, strlen(name),fp);
fclose(fp);
You can store all your three fields onto a structure and load the structure onto the Shared Memory. In this way you are assured to have all the fields under one structure.
In the process that reads the SHM you can use the File Stream utils as mentioned above by others.

Resources