I am trying to write a file with data into my shared memory segment. However everything I have tried seems just to give the error Segmentation fault. I have been searching the internet for help for more then one day.
int main(int argc, char *argv[]).
{
int sm;
char *data;
int pid=atoi(argv[1]);
int key=atoi(argv[2]);
char (*d)[1025];
data=(char*) malloc(1025);
//put the data in the shared memory segment
FILE *file=fopen(argv[3], "r"); //r for read
if (file==0)
{printf("Could not open file");}
else
{
while(fgets(data, 1025, file)!=NULL)
{
fputs(data, file);
// puts(d);
}
fclose(file);
}
//access shared memory
//S_IWUSR gives owner the write permession
sm = shmget(key, 1024, S_IWUSR);
//create a pointer to the shared memory segment
d = shmat(sm, (void *)0, 0); //shared memory id, shmaddr, shmflg
//for (int j=0; j<100; j++)
strcpy(d[0], data);
shmdt(d); //detach the shared memory segment
//remove the shared memory segment
shmctl(sm, IPC_RMID, NULL);
}
Any help would be greatly appreciated
Thanks in advance
EDIT: added malloc
EDIT2: maybe I should rephrase my question, my problem is to get the data into my shared memory
+1 about rjayavrp answer
And I can add that data is not allocated... This is just a pointer and not a array of chars..
Moreover what are you trying to do with
char (*d)[1025];
A quick and dirty example :
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SIZE_SHARED_MEMORY 1024
int main(int argc, char *argv[])
{
int sm = -1;
char *d = NULL;
FILE *file = NULL;
key_t key = 0;
int ret = 0;
if (argc != 4)
{
return 1;
}
key = atoi(argv[2]);
//access shared memory
sm = shmget(key, SIZE_SHARED_MEMORY, IPC_CREAT | 0600);
if (sm == -1)
{
perror("shmget : Failed");
return 2;
}
//create a pointer to the shared memory segment
d = shmat(sm, (char *)0, 0);
if (d == (void *)-1)
{
perror("shmat : Failed");
return 3;
}
// Open the file
file = fopen(argv[3], "r");
if (file == NULL)
{
perror("fopen : Failed");
ret = 4;
}
else
{
if(fgets(d, SIZE_SHARED_MEMORY, file) == NULL)
{
perror("fgets : Failed");
ret = 5;
}
fclose(file);
}
shmdt(d); //detach the shared memory segment
// remove the shared memory segment ???
// Don't understand why you are doing this
shmctl(sm, IPC_RMID, NULL);
return ret;
}
File is opened in read mode only.
change it to rw+ which will open a file in read/write mode. If the file is not available, it will be created.
fputs(data, file); here file is opened in read-only mode but write is happening.
But Im not sure, why you trying to write the read data to same file. You should consider your design first. 2. char (*d)[1025]; is a pointer to an char array of size 1025. You are using it in strcpy(). 3. memory should be allocated for data either statically or dynamically.
Related
I have 2 threads and they should use the same memory. Main method should start both threads. Trå A must read the contents of a file and share it with Trå B. Trå B must also receive the data that Trå A has shared and loop through and count the number of bytes in the file. Both Threads run but on the last step before the program terminates before I memory segment fault. I use Semaphore to communicate between the Threads. here i my code:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#define BUFFER_SIZE 4096
typedef struct _Buffer
{
int size;
char data[BUFFER_SIZE];
} Buffer;
sem_t task1, task2;
void *thread_A(void *arg);
void *thread_B(void *arg);
int main(int argc, char *argv[])
{
Buffer *memory = malloc(sizeof(Buffer));
sem_init(&task1, 0, 0);
sem_init(&task2, 0, 0);
pthread_t thread_A_id;
pthread_t thread_B_id;
pthread_create(&thread_A_id, NULL, &thread_A, &memory);
pthread_create(&thread_B_id, NULL, &thread_B, &memory);
if (pthread_join(thread_A_id, NULL) != 0)
{
perror("Error joining thread A");
exit(1);
}
if (pthread_join(thread_B_id, NULL) != 0)
{
perror("Error joining thread B");
exit(1);
}
free(memory);
return 0;
}
void *thread_A(void *arg)
{
Buffer *buffer = (Buffer*) arg;
FILE *pdf_file = fopen("file.pdf", "rb");
if (pdf_file == NULL)
{
perror("Can not open the file");
}
printf("size of struct %ld\n", sizeof(Buffer));
buffer->size = fread(&buffer->data, sizeof(char), BUFFER_SIZE, pdf_file);
fclose(pdf_file);
sem_post(&task1);
sem_wait(&task2);
printf("A is out\n");
return NULL;
}
void *thread_B(void *arg)
{
printf("IAM IN TREAD B");
Buffer *buffer = (Buffer*) arg;
sem_wait(&task1);
int i=0;;
int byte_counts[256] = {0};
while (buffer->size != i) {
unsigned char byte = buffer->data[i];
byte_counts[byte]++;
i++;
}
for (int i = 0; i < 256; i++)
{
printf("Byte-value %02X: %d\n", i, byte_counts[i]);
}
sem_post(&task2);
printf("threadB is done 2\n");
return NULL;
}
memory is a pointer to a Buffer (Buffer *), and by taking its address, you get a pointer to a pointer to a buffer (Buffer **):
Buffer *memory = malloc(sizeof(Buffer));
...
pthread_create(&thread_A_id, NULL, &thread_A, &memory);
pthread_create(&thread_B_id, NULL, &thread_B, &memory);
But in the thread functions, you're assuming that arg is a Buffer *:
Buffer *buffer = (Buffer*) arg;
This causes undefined behaviour.
Clearly there's one indirection too many; memory is already a pointer so we don't need to take its address:
pthread_create(&thread_A_id, NULL, &thread_A, memory);
pthread_create(&thread_B_id, NULL, &thread_B, memory);
If file fails to open, fread will return -1 and it's not checked. So the loop in thread_B will read first garbage from buffer->data and then will continue out of limit (because of comparison with -1).
So, at first, there is missing handling of error from fopen() - thread_a continues after perror, second - missing error check after fread().
By the way, the check for
if (buffer->size == i)
after while (buffer->size != i) is superfluous :)
I have just started learning about virtual memory and I don't understand if I can see the memory that I have allocated with mmap(). The 2 show_maps() print the same text. Shouldn't I also see the allocated memory from mmap() in the second show_maps() and if not is there a way to see it?
#define MAPS_PATH "/proc/self/maps"
#define LINELEN 256
void show_maps(void)
{
FILE *f;
char line[LINELEN];
f = fopen(MAPS_PATH, "r");
if (!f) {
printf("Cannot open " MAPS_PATH ": %s\n", strerror(errno));
return;
}
printf("\nVirtual Memory Map of process [%ld]:\n", (long)getpid());
while (fgets(line, LINELEN, f) != NULL) {
printf("%s", line);
}
printf("--------------------------------------------------------\n\n");
if (0 != fclose(f))
perror("fclose(" MAPS_PATH ")");
}
int main(void)
{
pid_t mypid;
int fd = -1;
uint64_t *pa;
mypid = getpid();
show_maps();
pa=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
show_maps();
}
You did:
pa = mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
If you check the value of pa, you'll find that it is MAP_FAILED
So, the actual mapping did not occur.
This is because you called mmap with an fd value of -1. So, the call had no backing store/file.
To fix this, add MAP_ANONYMOUS:
pa = mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,fd,0);
I am trying to initialize some variables in my struct, but I am getting a seg fault when assigning my front variable to equal zero. Specifically newBuff->front = 0;
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
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 name\n");
}
printf("%lu\n", sizeof(file));
int shmid;
char path[] = "~";
key_t key = ftok(path, 7);
shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL); //shared memory creation
buffer* newBuff = (buffer*) shmat(shmid, 0, 0);
newBuff->front = 0;
You're not checking the value of newBuff returned by shmat() to ensure that it is not invalid, e.g. (void*) -1 (per http://man7.org/linux/man-pages/man2/shmop.2.html). You also need to check the return value of shmget() to ensure that it succeeded in the first place.
Almost certainly, newBuff is -1, and trying to dereference that gives you a segfault.
several things I can see:
Wrong control of the arguments. You are checking them, but are you exiting your program? ;)
You are not checking the result when you invoke functions as shmat. Review the manual (man shmat).
Said the above, I can not see your whole code, but this is my recommendation:
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
char bytes[1024];
} buffer;
int main(int argc, char const *argv[]) {
int shmid = -1;
FILE *file = NULL;
if (argc != 2){
printf("You must enter in a file dumbass\n");
// And you must terminate here your program!
return 1;
}
file = fopen(argv[1], "r");
// Another check that you are not making and can raise a SIGVSEG
if (file == NULL) {
printf("The file '%s' can not be opened\n", argv[1]);
return 1;
}
printf("File size: %lu\n", sizeof(file));
char path[] = "~";
key_t key = ftok(path, 7);
// Another check
if (key == -1) {
fclose(f);
printf("The path '%s' does not exist or cannot be accessed\n", path);
return 1;
}
shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL);
// One more check
if (shmid == -1) {
fclose(f);
printf("An error happened getting shared memory identifier\n");
return 1;
}
buffer* newBuff = (buffer*)shmat(shmid, 0, 0);
// And finally! Another potential source that could raise a SIGVSEG
if (buffer == NULL) {
fclose(f);
printf("An error happened getting the shared memory area\n");
return 1;
}
newBuff->front = 0;
Please! Check every return of the functions! You can not imagine how many real problems happen because such returns are not checked properly because of bad practices.
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.
I have a bit of an issue with one of my projects.
I have been trying to find a well documented example of using shared memory with fork() but to no success.
Basically the scenario is that when the user starts the program, I need to store two values in shared memory: current_path which is a char* and a file_name which is also char*.
Depending on the command arguments, a new process is kicked off with fork() and that process needs to read and modify the current_path variable stored in shared memory while the file_name variable is read only.
Is there a good tutorial on shared memory with example code (if possible) that you can direct me to?
There are two approaches: shmget and mmap. I'll talk about mmap, since it's more modern and flexible, but you can take a look at man shmget (or this tutorial) if you'd rather use the old-style tools.
The mmap() function can be used to allocate memory buffers with highly customizable parameters to control access and permissions, and to back them with file-system storage if necessary.
The following function creates an in-memory buffer that a process can share with its children:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void* create_shared_memory(size_t size) {
// Our memory buffer will be readable and writable:
int protection = PROT_READ | PROT_WRITE;
// The buffer will be shared (meaning other processes can access it), but
// anonymous (meaning third-party processes cannot obtain an address for it),
// so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
return mmap(NULL, size, protection, visibility, -1, 0);
}
The following is an example program that uses the function defined above to allocate a buffer. The parent process will write a message, fork, and then wait for its child to modify the buffer. Both processes can read and write the shared memory.
#include <string.h>
#include <unistd.h>
int main() {
char parent_message[] = "hello"; // parent process will write this message
char child_message[] = "goodbye"; // child process will then write this one
void* shmem = create_shared_memory(128);
memcpy(shmem, parent_message, sizeof(parent_message));
int pid = fork();
if (pid == 0) {
printf("Child read: %s\n", shmem);
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s\n", shmem);
} else {
printf("Parent read: %s\n", shmem);
sleep(1);
printf("After 1s, parent read: %s\n", shmem);
}
}
Here is an example for shared memory :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
int main(int argc, char *argv[])
{
key_t key;
int shmid;
char *data;
int mode;
if (argc > 2) {
fprintf(stderr, "usage: shmdemo [data_to_write]\n");
exit(1);
}
/* make the key: */
if ((key = ftok("hello.txt", 'R')) == -1) /*Here the file must exist */
{
perror("ftok");
exit(1);
}
/* create the segment: */
if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
perror("shmget");
exit(1);
}
/* attach to the segment to get a pointer to it: */
if ((data = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/* read or modify the segment, based on the command line: */
if (argc == 2) {
printf("writing to segment: \"%s\"\n", argv[1]);
strncpy(data, argv[1], SHM_SIZE);
} else
printf("segment contains: \"%s\"\n", data);
/* detach from the segment: */
if (shmdt(data) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
Steps :
Use ftok to convert a pathname and a project identifier to a System V IPC key
Use shmget which allocates a shared memory segment
Use shmat to attache the shared memory segment identified by shmid to the address space of the calling process
Do the operations on the memory area
Detach using shmdt
These are includes for using shared memory
#include<sys/ipc.h>
#include<sys/shm.h>
int shmid;
int shmkey = 12222;//u can choose it as your choice
int main()
{
//now your main starting
shmid = shmget(shmkey,1024,IPC_CREAT);
// 1024 = your preferred size for share memory
// IPC_CREAT its a flag to create shared memory
//now attach a memory to this share memory
char *shmpointer = shmat(shmid,NULL);
//do your work with the shared memory
//read -write will be done with the *shmppointer
//after your work is done deattach the pointer
shmdt(&shmpointer, NULL);
try this code sample, I tested it, source: http://www.makelinux.net/alp/035
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400;
/* Allocate a shared memory segment. */
segment_id = shmget (IPC_PRIVATE, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p\n", shared_memory);
/* Determine the segment's size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf ("segment size: %d\n", segment_size);
/* Write a string to the shared memory segment. */
sprintf (shared_memory, "Hello, world.");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address. */
shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
printf ("shared memory reattached at address %p\n", shared_memory);
/* Print out the string from shared memory. */
printf ("%s\n", shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}
Here's a mmap example:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
* pvtmMmapAlloc - creates a memory mapped file area.
* The return value is a page-aligned memory value, or NULL if there is a failure.
* Here's the list of arguments:
* #mmapFileName - the name of the memory mapped file
* #size - the size of the memory mapped file (should be a multiple of the system page for best performance)
* #create - determines whether or not the area should be created.
*/
void* pvtmMmapAlloc (char * mmapFileName, size_t size, char create)
{
void * retv = NULL;
if (create)
{
mode_t origMask = umask(0);
int mmapFd = open(mmapFileName, O_CREAT|O_RDWR, 00666);
umask(origMask);
if (mmapFd < 0)
{
perror("open mmapFd failed");
return NULL;
}
if ((ftruncate(mmapFd, size) == 0))
{
int result = lseek(mmapFd, size - 1, SEEK_SET);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
/* Something needs to be written at the end of the file to
* have the file actually have the new size.
* Just writing an empty string at the current file position will do.
* Note:
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - An empty string is actually a single '\0' character, so a zero-byte
* will be written at the last byte of the file.
*/
result = write(mmapFd, "", 1);
if (result != 1)
{
perror("write mmapFd failed");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
}
}
else
{
int mmapFd = open(mmapFileName, O_RDWR, 00666);
if (mmapFd < 0)
{
return NULL;
}
int result = lseek(mmapFd, 0, SEEK_END);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
if (result == 0)
{
perror("The file has 0 bytes");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
close(mmapFd);
}
return retv;
}