I created a program to test the execution of shared memory.
One process creates the shared memory and writes to it.
The other reads from it.
It works perfectly, except for printing a string.
First program:
#define mykey 12345
#define perms 0666
struct pdata{
int ppid;
char ptype;
char *pname;
unsigned long pgenome;
};
int main(int argc, char **argv){
int shmid;
char *args[] = {"test2", NULL};
struct pdata *ap;
struct pdata p0={12, 'A', "PIPPO", 100};
shmid = shmget(mykey, sizeof(struct pdata) * 1, perms | IPC_CREAT | IPC_EXCL);
ap = (struct pdata*) shmat(shmid, NULL, 0);
ap[0] = p0;
printf("%s\n", ap[0].pname);
if(execve("test2", args, NULL) == -1){
printf("Errore execve\n");
}
shmdt(ap);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
Second program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#define mykey 12345
#define perms 0666
struct pdata{
int ppid;
char ptype;
char *pname;
unsigned long pgenome;
};
int main(){
int shmid = shmget(mykey, sizeof(struct pdata) * 1, perms);
struct pdata *ap;
ap = (struct pdata*) shmat(shmid, NULL, 0);
printf(
"ap[0].ppid=%d\nap[0].ptype=%c\nap[0].pname=%s\nap[0].pgenome=%lu\n",
ap[0].ppid,
ap[0].ptype,
ap[0].pname,
ap[0].pgenome
);
shmdt(ap);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
It doesn't make sense to put a pointer in shared memory. The receiving process now knows the address of the string in the other process' memory space, but that doesn't do it any good. Instead, put the string itself in shared memory.
For example, change:
char *pname;
to:
char pname[512];
And adjust the rest of your program appropriately.
Related
I am trying to create client server communication through named pipe. From my client I want to send current time. I am trying to use time() function but the time won't appear on my server side terminal. I just see provided text. What am I doing wrong?
server
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
char *pathname = "/tmp/myfifo";
int make_fifo = mkfifo(pathname, 0666);
char str[80];
for(;;){
int opn = open(pathname, O_RDONLY);
read(opn, str, sizeof(str));
close(opn);
}
return 0;
}
client
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
int main() {
char *pathname = "/tmp/myfifo";
time_t current_time = time(0);
char str[80];
int fd = open(pathname, O_WRONLY);
fgets(str, 80, stdin);
write(fd, str, sizeof(str));
write(fd, (void*) current_time, sizeof(current_time));
close(fd);
return 0;
}
What am I doing wrong?
client: Not passing the address of current_time.*1
// write(fd, (void*) current_time, sizeof(current_time));
write(fd, ¤t_time, sizeof(current_time)); // Add &
server: not reading the time.
Ignoring return values of read()/write().
*1 Avoid casting like (void*) current_time. Casting tends to hide errors.
I am trying to get the parent directory stats.
If I wrtie code like below it return error: Bad address
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <dirent.h>
int main(int agrc, char * argv[]){
struct stat *buffer;
int res = stat("..", buffer);
if(res != 0){
perror("error");
exit(1);
}
//printf("%d", buffer->st_ino);
}
But If I write code like this below, there is no problem.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <dirent.h>
int main(int agrc, char * argv[]){
/* struct stat *buffer; */
struct stat buffer;
int res = stat("..", &buffer);
if(res != 0){
perror("error");
exit(1);
}
//printf("%d", buffer->st_ino);
printf("%d", buffer.st_ino);
}
I do not know why the result is different.
The variable buffer of definition struct stat * buffer is a pointer of struct stat
The &buffer is also a pointer of struct stat
The function is defined as below in manpage
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
...
I expected the result to be both successful, why the result is different? anyone can help, thanks a lot.
With struct stat buffer; , there is memory allocated for buffer on the stack.
But with struct stat *buffer; there is no memory allocated for buffer. You have to use a memory allocation function to allocate memory. This allocation happens on what is known as heap.
struct stat *buffer = malloc(sizeof(struct stat));
Note that stat() stats the file pointed to by path and fills in buf. So if buf does not point to memory that the program owns, it will result in error: Bad address.
I'm writing some code for a project and I have an issue when I try to update an area of shared memory with another process.
Basically one process create a shared memory, then it creates one child that, using execve, execute a process the aim of which is to update that shared memory knowing its key.
At the end the main process prints all the datas from the shm to stdout.
At that point I have noticed that shm has not been updated.
I can't understand why. I've tried with regular assignment (=) or assigning every field with a function (updatef), but it doesn't work.
(Of course in the real program I used semaphores to regulate the access to shm, i wrote this code to minimize the code to see the problem)
Process t:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666
struct pdata{
pid_t ppid;
char ptype;
char pname[maxname];
unsigned long pgenome;
};
void updatef(struct pdata a, struct pdata p){
a.ppid = p.ppid;
a.ptype = p.ptype;
strcpy(a.pname, p.pname);
a.pgenome = p.pgenome;
}
int main(){
int shmid;
struct pdata *addr;
shmid = shmget(mykey, sizeof(struct pdata) * shmsz, IPC_CREAT | perms);
addr = (struct pdata*) shmat(shmid, NULL, 0);
for(int i=0; i<shmsz; i++){
addr[i].ppid = -1;
}
switch(fork()){
case 0:
{
char *args[] = {"u", NULL};
execve("u", args, NULL);
}
break;
}
sleep(2);
for(int i=0; i<shmsz; i++){
printf("%d %c %s %lu\n", addr[i].ppid, addr[i].ptype, addr[i].pname, addr[i].pgenome);
}
shmdt(addr);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
Process u:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666
struct pdata{
pid_t ppid;
char ptype;
char pname[maxname];
unsigned long pgenome;
};
void updatef(struct pdata a, struct pdata p){
a.ppid = p.ppid;
a.ptype = p.ptype;
strcpy(a.pname, p.pname);
a.pgenome = p.pgenome;
}
int main(){
int shmid;
struct pdata *addr;
struct pdata p;
shmid = shmget(mykey, sizeof(struct pdata) * shmsz, perms);
addr = (struct pdata*) shmat(shmid, NULL, 0);
p.ppid = getpid();
p.ptype = 'A';
strncpy(p.pname, "PIPPO", maxname);
p.pgenome = 10;
for(int i=0; i<shmsz; i++){
updatef(addr[i], p);
}
shmdt(addr);
return 0;
}
Short answer is of course passing pointer instead of value and that'll do
updatef(&arr[i], p);
Long answer lies in pass by value and pass by reference, when updatef is called with addr[i] as in
updatef(arr[i], p);
essentially the value is copied to calling function and never gets reflected to attached pointer viz addr as a result the original addr pointer get unchanged on the other hand when we pass the address like
updatef(&addr[i], p);
//or
updatef(addr+i, p);
reference is passed which inturn will update the contents pointed to by addr+i pointer
to add on IMO splitting the code will make this more presentable and readable and maintainable and bla bla bla here is a bit
File 1 - s.h, keep shared and global data here
#ifndef S_H_INCLUDED
#define S_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#define mykey 100
#define maxname 100
#define shmsz 5
#define perms 0666
struct pdata{
pid_t ppid;
char ptype;
char pname[maxname];
unsigned long pgenome; };
#endif
t.c
#include "s.h" // include global header here
int main(){
int shmid;
struct pdata *addr;
shmid = shmget(mykey, sizeof(struct pdata) * shmsz, IPC_CREAT | perms);
addr = (struct pdata*) shmat(shmid, NULL, 0);
for(int i=0; i<shmsz; i++){
addr[i].ppid = -1;
}
switch(fork()){
case 0:
{
char *args[] = {"u", NULL};
execve("u", args, NULL);
}
break;
}
sleep(2);
for(int i=0; i<shmsz; i++){
printf("%d %c %s %lu\n", addr[i].ppid, addr[i].ptype, addr[i].pname, addr[i].pgenome);
}
shmdt(addr);
shmctl(shmid, IPC_RMID, 0);
return 0;
}
u.c
#include "s.h" // common included here
static void updatef(struct pdata *a, struct pdata p){
a->ppid = p.ppid;
a->ptype = p.ptype;
strcpy(a->pname, p.pname);
a->pgenome = p.pgenome;
}
int main(){
int shmid;
struct pdata *addr;
struct pdata p;
shmid = shmget(mykey, sizeof(struct pdata) * shmsz, perms);
addr = (struct pdata*) shmat(shmid, NULL, 0);
p.ppid = getpid();
p.ptype = 'A';
strncpy(p.pname, "PIPPO", maxname);
p.pgenome = 10;
for(int i=0; i<shmsz; i++){
updatef(addr+i, p);
}
shmdt(addr);
return 0;
}
and the final build step
gcc t.c -o t
gcc u.c -o u
in this program about shared memory(Producer/Consumer) with semaphores(on DEBIAN) when I use the strncmp function with the string "end", in order to turn on 0 a flag(running) to kill a while cycle,strncmp doesn't recognize the word end that I insert into the shell. Thank you.
This is only the first process that I want to use:
//CONSUMER
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "semafori.h" //semaphores SYSTEM V functions
#include <sys/shm.h>
#include <string.h>
#define SHM_KEY (key_t)1234
#define SEM_KEY (key_t)5678
#define WRITE_SEM 0
#define READ_SEM 1
#define TEXT_SIZE 2048
struct SharedData{
unsigned int count;
char text[TEXT_SIZE];
};
int main(void)
{
int running=1;
void *shmP;
struct SharedData * p;
int shmID;
int semID;
semID=semget(SEM_KEY,2,IPC_CREAT|0666);
SEM_SET(semID, WRITE_SEM,1);
SEM_SET(semID, READ_SEM, 0);
shmID=shmget(SHM_KEY, sizeof(struct SharedData), IPC_CREAT|0666);
shmP=shmat(semID, (void *)0, 0);
printf("Memoria agganciata all'indirizzo: %X\n", (int)shmP);
p=(struct SharedData *)shmP;
while(running!=0){
if(SEM_P(semID, READ_SEM)==-1) exit(EXIT_FAILURE);
if (strncmp(p->text, "end", 3) == 0) {
running = 0;
}
else {
printf("Numero scambi effettuato: %u\nHai scritto: %s\n", p->count, p->text);
}
if(SEM_V(semID, WRITE_SEM)==-1) exit(EXIT_FAILURE);
}
if(shmdt(shmP)==-1){
fprintf(stderr, "shmdetach failed\n");
exit(EXIT_FAILURE);
}
if(shmctl(shmID, IPC_RMID, 0)==-1){
fprintf(stderr, "shmctl RMID failed\n");
exit(EXIT_FAILURE);
}
SEM_DEL(semID, 0);
exit(EXIT_SUCCESS);
}
This is the second process:
PRODUCER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include "semafori.h"
#define SHM_KEY (key_t)1234
#define SEM_KEY (key_t)5678
#define WRITE_SEM 0
#define READ_SEM 1
#define TEXT_SIZE 2048
struct SharedData{
unsigned int count;
char text[TEXT_SIZE];
};
int main(void)
{
int running=1;
unsigned int count=0;
void *shmP;
struct SharedData *p;
int shmID, semID;
char buffer[TEXT_SIZE];
semID=semget(SEM_KEY, 2, IPC_CREAT|066);
shmID=shmget(SHM_KEY, sizeof(struct SharedData),IPC_CREAT|0666);
shmP=shmat(shmID, (void *)0, 0);
p=(struct SharedData*)shmP;
while(running!=0)
{
count++;
if(SEM_P(semID, WRITE_SEM)==-1) exit(EXIT_FAILURE);
printf("Inserisci testo: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(p->text, buffer, TEXT_SIZE);
p->count=count;
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
if(SEM_V(semID, READ_SEM)==-1) exit(EXIT_FAILURE);
}
if(shmdt(shmP)==-1){
fprintf(stderr, "shmdt failure\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
I resolved the problem with debug method. In the shmat argument i wrote semID instead of shmID shmP=shmat(semID, (void *)0, 0)
Thank you everybody.
[RESOLVED]
When I reach the line routerInfo->areaID, I got segment fault: 11 on that part.
It seem that I do not allocate the memory successfully.
I just do not know why.
Can any one solve this problem?
My header is like this:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include<memory.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <semaphore.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include <stdbool.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#define QUEUE_SIZE 300
#define MAX_CONN 10
#define TYPE_ROUTE 1
#define TYPE_TERMINAL 2
#define CONN_INIT false
#define CONN_ESTB true
#define CSPORT 39246
struct localInfo{
char router_ID[16];
int helloTime;
int protocol_Version;
int update_Interval;
int area_ID;
int neighborNum;
};
//shared information struct
and My main function is:
#include "BasicHeader.h"
int shared_hello, shared_lsa, shared_ping, shared_data, shared_localInfo;//using shared memory
pid_t childpid;//using for child process
int main(){
printf("Starting router ... ");
sleep(1);
key_t keyForLocalInfo = ftok(".", 1);
shared_localInfo = shmget ( keyForLocalInfo , sizeof(struct localInfo) , IPC_CREAT) ;
if (shared_localInfo == -1) {perror("error creating");exit(1);}
printf("shared_localInfo: %d\n", shared_localInfo);
//creating the queue for shared_localInfo
system("ipcs -m");
//show the shm status
//creating the sharing memory finished
struct localInfo *routerInfo = (struct localInfo*) shmat (shared_localInfo, (void *)0, 0);
if (routerInfo == NULL) {
perror("shmat");exit(1);
}
routerInfo->area_ID = 0;
routerInfo->helloTime = 45;
routerInfo->neighborNum = 0;
routerInfo->protocol_Version = 1;
routerInfo->update_Interval = 180;
shmdt(routerInfo);
int err = 0;
if ((err = shmctl(shared_localInfo, IPC_RMID, 0) == -1))
perror("shmctl shared_localInfo");
}
Change the permissions on semget to allow access e.g.
shmget(keyForLocalInfo, sizeof(struct localInfo),
IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
Note that shmat returns a ptr set to -1, not NULL, and thus the error check was not catching the error. The code should have been
struct localInfo *routerInfo = (struct localInfo*) shmat (shared_localInfo, (void *)0, 0);
if (routerInfo == (void *) -1)
{
perror("shmat");
exit(1);
}