C Shared Memory Reader-Writer Segmentation Fault - c

Here is a Synchronized Reader and Writer. The target is passing data between these two Processes via a Shared Memory.
The Writer opens a Shared Memory through a Structure and writes Some Data. I am getting Segmentation Fault(Core Dumped) error message.
The code is compiled through the following command in Ubuntu.
g++ Writer.c -o Writer -lrt
g++ Reader.c -o Reader -lrt
And these two Processes are run by-
./Writer
./Reader
The Writer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(void){
struct MemData{
char* FileName;
int LastByteLength;
int ReadPointer;
int WritePointer;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
int BufferSize=51200;//FILE BUFFER SIZE 50 KB
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
fchmod(SD, S_IRWXU|S_IRWXG|S_IRWXO);
if(ftruncate(SD, sizeof(MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
//THE FOLLOWING TYPECASTING AVOIDS THE NEED TO ATTACH THROUGH shmat() in shm.h HEADER I GUESS.
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
M->FileName=(char*)"xaa";
M->LastByteLength=0;
M->ReadPointer=-1;
M->WritePointer=-1;
memset(M->Data, '\0', strlen(M->Data));
}
/*
FILE *FP= fopen(FileName, "rb");
if(FP!= NULL){
unsigned long int FilePosition;
fseek(FP, 0, SEEK_SET);
FilePosition=ftell(FP);
fclose(FP);
}
*/
close(SD);
return 0;
}
The Reader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(void){
struct MemData{
char* FileName;
int LastByteLength;
int ReadPointer;
int WritePointer;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
int BufferSize=51200;//FILE BUFFER SIZE 50 KB
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
fchmod(SD, S_IRWXU|S_IRWXG|S_IRWXO);
if(ftruncate(SD, sizeof(MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
//THE FOLLOWING TYPECASTING AVOIDS THE NEED TO ATTACH THROUGH shmat() in shm.h HEADER I GUESS.
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
printf("\n%s", M->FileName);
printf("\n%d", M->LastByteLength);
printf("\n%d", M->ReadPointer);
printf("\n%d", M->WritePointer);
}
/*
FILE *FP= fopen(FileName, "rb");
if(FP!= NULL){
unsigned long int FilePosition;
fseek(FP, 0, SEEK_SET);
FilePosition=ftell(FP);
fclose(FP);
}
*/
munmap(M,sizeof(MemData));
close(SD);
return 0;
}

Based on your comments, the issue is because of the way you're assigning and passing the FileName value.
M->FileName=(char*)"xaa";
This results in M->FileName holding a pointer to a string in the writer process' memory. Dereferencing this pointer in the reader process results in a segmentation fault due to the filename being stored in the writer process memory, which is not shared with the reader. You need to store the characters themselves in the shared memory, not a pointer to writer process memory.
If you can safely assume the maximum length of the filename string, you can change your struct to store the entire string rather than a pointer: change char* FileName; to char FileName[256]; or some other fixed length value. You will need to use strcpy rather than direct assignment after making this change: change M->FileName=(char*)"xaa"; to strcpy(M->FileName, "xaa");.
If you want a dynamic length string, you can call mmap again to allocate shared memory for just the string, and then store the pointer to this shared memory string in FileName.

Related

C Reader Writer Mutexes for a Copying a File using Shared Memory and Ring Buffer

I want to build a File Copier using Reader-Writer Synchronization Paradigm.
The Writer initializes the both of the Mutexes. The FullMutex is denoting how many Buffers are available to Write and the FreeMutex is denoting how many Buffers are available to Read.
The Writer waits when the Block is Full.
The WritePointer and ReadPointer is using the Ring Buffer. Therefore I have used Mod Operation.
The Block Size=M.
The Buffer Size=B.
There are N number of Buffers.
So, M=N*B.
The File Size=2M.
And therefore BufferCount is actually advancing File Pointer.
When all Bytes are written, I am issuing FileEnding=1.
The compilation commands are-
g++ Writer.c -o Writer -lpthread -lrt
g++ Reader.c -o Reader -lpthread -lrt
And in 2 different comand prompts are open and the commands are issued-
./Writer
./Reader
Now I do not know why it is not copying and do not know how to use sem_post.
Here is the Writer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(void){
struct MemData{
sem_t FullMutex;
sem_t FreeMutex;
char FileName[128];
int ReadPointer;
int WritePointer;
int FileEnding;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
//int BufferSize=51200;//FILE BUFFER SIZE 50 KB
int BufferSize=2;//EXPERIMENATION
unsigned char Buf[BufferSize];
int BufferCount=0;
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
fchmod(SD, S_IRWXU|S_IRWXG|S_IRWXO);
if(ftruncate(SD, sizeof(MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
sem_init(&M->FullMutex, 1, 0);
sem_init(&M->FreeMutex, 1, NumberOfBuffers);
strcpy(M->FileName, "aaa.txt");
M->FileEnding=0;
M->ReadPointer=0;
M->WritePointer=0;
memset(M->Data, '\0', strlen(M->Data));
}
char FileName[128]="aaa.txt";
FILE *FP= fopen(FileName, "rb");
if(FP!= NULL){
struct stat StatBuf;
if(stat(FileName, &StatBuf)==-1){
printf("failed to fstat %s\n", FileName);
exit(EXIT_FAILURE);
}
long long FileSize=StatBuf.st_size;
printf("\nFile Size: %lld", FileSize);
long long FilePosition=ftell(FP);
FilePosition=ftell(FP);
long long CopyableMemorySize=FileSize-FilePosition;
printf("\nCopyable File Size: %lld", CopyableMemorySize);
int NumberOfFileBuffers=CopyableMemorySize/BufferSize;
printf("\n Number Of File Buffers: %d", NumberOfFileBuffers);
while(1){
sem_wait(&M->FreeMutex);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fread(Buf, sizeof(unsigned char), BufferSize, FP);
int FreeMutexValue;
sem_getvalue(&M->FreeMutex, &FreeMutexValue);
int FullMutexValue;
sem_getvalue(&M->FullMutex, &FullMutexValue);
printf("\nMutexes-Free: %d and Full: %d", FreeMutexValue, FullMutexValue);
printf("\nBuffer Writing: %s", BufferCount);
memcpy(&M->Data[M->WritePointer*BufferSize], &Buf, sizeof(Buf)*sizeof(unsigned char));
BufferCount++;
M->WritePointer=(M->WritePointer+1)%NumberOfBuffers;
if(BufferCount>=NumberOfFileBuffers && M->WritePointer==M->ReadPointer){
M->FileEnding=1;
break;
}
sem_post(&M->FullMutex);
}
fclose(FP);
}
close(SD);
return 0;
}
The Reader is using the Mutex opened by the Writer.c.
All the Block Size, Buffer Size and Number of Buffers are same like the Writer.c.
When the Reader gets FileEnding==1, it breaks the loop since there is nothing to process.
The Reader destroy the Mutex and deallocates Memory.
Here is the Reader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(void){
char FileName[128]="bbb.txt";
struct MemData{
sem_t FullMutex;
sem_t FreeMutex;
char FileName[128];
int ReadPointer;
int WritePointer;
int FileEnding;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
//int BufferSize=51200;//FILE BUFFER SIZE 50 KB
int BufferSize=2;//EXPERIMENATION
unsigned char Buf[BufferSize];
int BufferCount=0;
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}
FILE *FP= fopen(FileName, "wb");
if(FP!= NULL){
while(1){
sem_wait(&M->FullMutex);
int FreeMutexValue;
sem_getvalue(&M->FreeMutex, &FreeMutexValue);
int FullMutexValue;
sem_getvalue(&M->FullMutex, &FullMutexValue);
printf("\nMutexes-Free: %d and Full: %d", FreeMutexValue, FullMutexValue);
printf("\nBuffer Writing: %d", BufferCount);
printf("\nReadPointer: %d", M->ReadPointer);
printf("\nWritePointer: %d", M->WritePointer);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fseek(FP, BufferCount*BufferSize, SEEK_SET);
fwrite(&M->Data[M->ReadPointer*BufferSize], sizeof(unsigned char), BufferSize, FP);
BufferCount++;
M->ReadPointer=(M->ReadPointer+1)%NumberOfBuffers;
if(M->FileEnding){
fclose(FP);
break;
}
sem_post(&M->FreeMutex);
}
}
munmap(M,sizeof(MemData));
close(SD);
return 0;
}
The input(aaa.txt) file contains these lines-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
The output(bbb.txt) file contains these lines-
1
2
3
4
5
6
7
8
9
10
11
12
13
14

C File Data into Shared Memory

I like to open a binary file and then like to check some headers and after that reading I like to get FilePosition through ftell() and I am assigned a Struct into a Shared Memory. I like to get file data into that Struct in a loop. But I am getting this error-
MWriter.c:71:43: error: invalid conversion from ‘char’ to ‘void*’ [-fpermissive]
fread(M->Data[i*BufferSize], sizeof(char), BufferSize, FP+FilePosition);
I like to open a binary file and then like to check some headers and after that reading I like to get FilePosition through ftell() and I am assigned a Struct into a Shared Memory. I like to get file data into that Struct in a loop. But I am getting this error-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(void){
struct MemData{
char FileName[128];//POINTER PUTS DATA INTO NON-SHARED MEMORY
int LastByteLength;
int ReadPointer;
int WritePointer;
char Data[512000];//MEMORY BLOCK SIZE: 500 KB
};
int SD;
struct MemData *M;
int NumberOfBuffers=10;
int BufferSize=51200;//FILE BUFFER SIZE 50 KB
SD= shm_open("/program.shared", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
if(SD< 0){
printf("\nshm_open() error \n");
return EXIT_FAILURE;
}
fchmod(SD, S_IRWXU|S_IRWXG|S_IRWXO);
if(ftruncate(SD, sizeof(MemData))< 0){
printf ("ftruncate() error \n");
return EXIT_FAILURE;
}
//THE FOLLOWING TYPECASTING AVOIDS THE NEED TO ATTACH THROUGH shmat() in shm.h HEADER I GUESS.
M=(struct MemData*)mmap(NULL, sizeof(MemData), PROT_READ|PROT_WRITE, MAP_SHARED, SD, 0);
if(M== MAP_FAILED){
printf("mmap() error");
return EXIT_FAILURE;
}else{
strcpy(M->FileName, "xaa");
M->LastByteLength=0;
M->ReadPointer=-1;
M->WritePointer=-1;
memset(M->Data, '\0', strlen(M->Data));
}
char FileName[128]="xaa";
FILE *FP= fopen(FileName, "rb");
if(FP!= NULL){
struct stat StatBuf;
if(stat(FileName, &StatBuf)==-1){
printf("failed to fstat %s\n", FileName);
exit(EXIT_FAILURE);
}
long long FileSize=StatBuf.st_size;
printf("\n File Size: %lld", FileSize);
long long FilePosition=ftell(FP);
FilePosition=ftell(FP);
long long CopyableMemorySize=FileSize-FilePosition;
printf("\n Copyable File Size: %lld", CopyableMemorySize);
int NumberOfFileBuffers=CopyableMemorySize/BufferSize;
printf("\n Number Of File Buffers: %d", NumberOfFileBuffers);
for(int i=0; i<NumberOfFileBuffers; i++){
if(abs(M->WritePointer-M->ReadPointer)==NumberOfBuffers){
//WAIT
}else{
fread(M->Data[i*BufferSize], sizeof(char), BufferSize, FP+FilePosition);
}
}
fclose(FP);
}
close(SD);
return 0;
}

mmap is wiping my file instead of copying it

So I'm using mmap to then write to another file. But the weird thing is, when my code hits mmap, what it does is clears the file. So I have a file that's populated with random characters (AB, HAA, JAK, etc...). What it's supposed to do is use mmap as read basically and then write that file to the new file. So that first if (argc == 3) is the normal read and write, the second if (argc ==4) is supposed to use mmap. Does anyone have any idea why on Earth this is happening?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>
int main(int argc, char const *argv[])
{
int nbyte = 512;
char buffer[nbyte];
unsigned char *f;
int bytesRead = 0;
int size;
int totalBuffer;
struct stat s;
const char * file_name = argv[1];
int fd = open (argv[1], O_RDONLY);
int i = 0;
char c;
int fileInput = open(argv[1], O_RDONLY);
int fileOutPut = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
fstat(fileInput, &s);
size = s.st_size;
printf("%d\n", size);
if (argc == 3)
{
printf("size: %d\n", size);
printf("nbyte: %d\n", nbyte);
while (size - bytesRead >= nbyte)
{
read(fileInput, buffer, nbyte);
bytesRead += nbyte;
write(fileOutPut, buffer, nbyte);
}
read(fileInput, buffer, size - bytesRead);
write(fileOutPut, buffer, size - bytesRead);
}
else if (argc == 4)
{
int i = 0;
printf("4 arg\n");
f = (char *) mmap (0, size, PROT_READ, MAP_PRIVATE, fileInput, 0);
/* This is where it is being wipped */
}
close(fileInput);
close(fileOutPut);
int who = RUSAGE_SELF;
struct rusage usage;
int ret;
/* Get the status of the file and print some. Easy to do what "ls" does with fstat system call... */
int status = fstat (fd, & s);
printf("File Size: %d bytes\n",s.st_size);
printf("Number of Links: %d\n",s.st_nlink);
return 0;
}
EDIT: I wanted to mention that the first read and write works perfectly, it is only when you try to do it through the mmap.
If you mean it's clearing your destination file, then yes, that's exactly what your code will do.
It opens the destination with truncation and then, in your argc==4 section, you map the input file but do absolutely nothing to transfer the data to the output file.
You'll need a while loop of some description, similar to the one in the argc==3 case, but which writes the bytes in mapped memory to the fileOutput descriptor.

‘ltrunc’ was not declared in this scope

I have problem with creating shared memory between two processes.
I getting this error, and I don't know what to do because I think a have all libraries included.
Log...
g++ exc8.c -o exc8
exc8.c: In function ‘int main(int, char**)’:
exc8.c:29:37: error: ‘ltrunc’ was not declared in this scope
size = ltrunc(fd, B_SIZE, SEEK_SET);
Code...
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#define B_SIZE 4
char* memory = new char[4];
int main(int argc, char *argv[]) {
int size, fd;
char *buf;
char memory[4];
fd = shm_open(memory, O_RDWR|O_CREAT, 0774);
if (fd < -0) {
perror("open");
exit(-1);
}
size = ltrunc(fd, B_SIZE, SEEK_SET);
if(size < 0) {
perror("trunc");
exit(-1);
}
buf = (char *)mmap(0, B_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(buf == NULL) {
perror("map");
exit(-1);
}
}
I don't know where ltrunc() comes from, but
you can set the size of a shared memory object with ftruncate():
if (ftruncate(fd, B_SIZE) == -1) {
// Handle error
}
(from http://pubs.opengroup.org/onlinepubs/009695299/functions/shm_open.html).
ltrunc is not a standard function. It seems defined in QNX Platform using qcc as the compiler, which truncates a file at given position. Probably POSIX provides the truncate() and ftruncate() functions for the job.

Writing struct to mapped memory file (mmap)

I have a problem to write struct into a mapped memory file.
I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.
When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c
sprintf((char*) file_memory, "%d\n", i);
and in line 25 of mmap.read.c
sscanf (file_memory, "%d", &integer);
There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.
The struct that I want to write and read:
#define CHANNELS 20
typedef dataholder struct {
int value[CHANNELS];
time_t time;
int hash;
}dataholder;
mmap.read.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
int integer;
/* Open the file. */
fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
printf("file opened\n");
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("memfile opened\n");
close (fd);
printf("file closed\n");
/* Read the integer, print it out, and double it. */
while(1) {
sscanf (file_memory, "%d", &integer);
printf ("value: %d\n", integer);
usleep(100000);
}
//sprintf ((char*) file_memory, "%d\n", 2 * integer);
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
mmap.write.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd, i;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
//lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
//lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
for(i=0; i<10000; i++) {
sprintf((char*) file_memory, "%d\n", i);
//goto a;
usleep(100000);
}
a:
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
Thanks a lot in advance.
First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.
To write a structure, you have three choices:
Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.
Write the structure, field-by-field, as text using e.g. sprintf to the correct position.
Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.
The simplest way is to just use a pointer:
dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */
Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:
dataholder dh_other = *dh;
or
*dh = dh_other;

Resources