This is my code.
int main(int argc, char *argv[]) {
int shmid;
char *shmc;
char *shmp;
pid_t pid;
shmid = shmget(IPC_PRIVATE, 3 * sizeof(char), 0666 | IPC_CREAT);
pid = fork();
if (pid == 0) {
shmc = (char *) shmat(shmid, NULL, 0);
shmc[0] = argv[1];
shmc[1] = argv[2];
shmc[2] = argv[3];
shmdt(shmc);
}else{
wait(NULL);
shmp =(char*) shmat(shmid,NULL, 0);
char *arg_vec[]={"./test", &shmp[1], &shmp[2],NULL};
execv("./test", arg_vec);
shmdt(shmp);
shmctl(shmid, IPC_RMID, NULL);
}
}
char *arg_vec[]={"./test", &shmp[1], &shmp[2],NULL};
In this line, I was trying to pass 2, 3 to another c program. But it passes 23 and 3. I wonder why and how can I fix the problem. Any help is appreciated. Thank you.
Function execv expects an array of pointers to strings. What you provide matches the type but not the logic behind:
char *arg_vec[]={"./test", &shmp[1], &shmp[2],NULL};
The addresses you use to initialize the parameter array are only pointers to single char, no strings.
In shmp all elements only have 1 byte and they are located at consecutive memory addresses. There is no place for some terminating 0 byte that would make your array a valid string.
You need to provide and initialize more space:
(Assuming you can ensure that numbers are only 1 digit)
shmid = shmget(IPC_PRIVATE, 3 * sizeof(char[2]), 0666 | IPC_CREAT);
char (*shmc)[2] = shmat(shmid, NULL, 0);
sprintf(shmc[0], "%d", number[0]);
...
char (*shmp)[2] = shmat(shmid, NULL, 0);
printf("%s, %s\n",shmp[1], shmp[2]);
char *arg_vec[]={"./test", shmp[1], shmp[2], NULL};
I leave it for you to ensure proper lengths and adapt in case you need larger numbers.
Related
I was wondering if it is possible to obtain the size of a shared memory segment in C created from shmget without having the size of the segment as a part of the data? I'm trying to allocate a dynamic int array and need to find the size of the array in the child process.
Main process:
int sizeOfArray = 3;
int shm = shmget(IPC_PRIVATE, sizeof(int) * sizeOfArray, IPC_CREAT | 0666);
int *a = (int*) shmat(shm, NULL, 0);
a[0] = 0;
a[1] = 1;
a[2] = 2;
if (fork() == 0) {
char *args[3];
char shmID[11];
bzero(shmID, 11);
intToString(shm, shmID); // custom function that does what the name implies
args[0] = "slave";
args[1] = shmID;
args[2] = NULL;
execvp("slave", args);
return -1;
}
wait(NULL);
shmdt((void*) a);
shmctl(shm, IPC_RMID, NULL);
Child process (slave):
int shm = atoi(argv[1]);
int *ptr = (int*) shmat(shm, NULL, 0);
//TODO: find length of int array in shared memory
shmdt((void*) ptr);
return 0;
I found that if you use shmctl and the IPC_STAT flag, you can get the number of bytes allocated to the shared memory segment. Then you can just divide it by sizeof(int) to get the size of your array.
struct shmid_ds buf;
shmctl(shm, IPC_STAT, &buf);
int length = (int) buf.shm_segsz / sizeof(int);
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 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 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
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)