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
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFF_SIZE 1024
typedef struct {
long data_type;
int data_num;
char data_buff[BUFF_SIZE];
} t_data;
int main(){
key_t msqid;
int ndx = 0;
t_data data;
msqid = msgget( (key_t)1234, IPC_CREAT | 0666);
if ( -1 == msqid)
{
perror( "msgget() fail");
exit( 1);
}
return 0;
}
and next, i do
gcc -o parent parent.c
and next,
./parent
but the result is
msgget() fail: Function not implemented
I don't know why the msgget function is not implemented even though this is just simple code.
How can i fix my code??
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.
Can I use the kill() function to send a signal to another process? It should be possible, but kill() fails and I can't understand why.
I have two programs (process_1 and process_2). The first one should set a signal handler to increase a variable, than create a child that uses execve and loads process_2. The other program should send the signal using kill(). I used the shared memory to share process_1's pid through a struct (because I have other variables to share). The code of the first program is as follows:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define KEY_SM 1234
static int value_to_change=0;
typedef struct keys{
pid_t pid_process;
}keynote;
static void test_handler(int signo){
if(signo=SIGUSR1){
printf("received SIGUSR1\n");
value_to_change++;
}
}
int main(){
if((signal(SIGUSR1, test_handler))==SIG_ERR) perror("Errore allocazione SIGUSR1");
int flags = S_IRUSR|S_IWUSR|IPC_CREAT;
size_t shm_size = sizeof(keynote);
int shm_id = shmget(KEY_MC, shm_size, flags);
keynote *chv = shmat(shm_id, NULL, 0);
chv->pid_process=getpid();
printf("%d\n",chv->pid_process);
int process_2;
process_2=fork();
if(process_2==0){
char* argv[]={"process_1", "process_2", NULL};
if((execve("process_2", argv, NULL))<0) perror("execve error");
exit(0);
}else if(process_2<0)perror("fork error");
return 0;
}
The second program code is:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define KEY_SM 1234
typedef struct keys{
pid_t pid_process;
}keynote;
static void signal_to_send(pid_t process){
int ret=kill(process, SIGUSR1);
printf("%d", ret);
}
}
int main(int argc, char **argv){
int pid_of_process_1;
int flags = S_IRUSR|S_IWUSR|IPC_CREAT;
size_t shm_size = sizeof(keynote);
int shm_id = shmget(KEY_MC, shm_size, flags);
keynote *chv = shmat(shm_id, NULL, 0);
signal_to_send(chv->pid_process);
return 0;
}
process_1 does not wait for process_2. It just exits immediately. At which point process_2 may not even have started. So when process_2 sends the signal, process_1 is likely to not exist anymore.
– kaylum
I am trying to code a scalable mutli-process program using semaphores. I already done the multi-process part with semaphores but now I am trying to make it scalable.
The method I would like to implement is adding another semaphore per process that will tell the process how many times he has to run through his code. The problem is that I don't know how to initialize the other semaphores and I am not sure of how to code it altogether.
So my question : how to initialize the other semaphores and what semop should I use ?
I understand that without a code sample it might be hard to answer but I cannot publish the code, if you want more information about my problem feel free to ask.
Thank you for your time and your answers.
Code sample :
/*INITIALIZATION*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} sem0, sem1, sem2;
int main(int argc, char** argv){
int key=ftok("/tmp",'L');
int id=semget(key,3,0600 | IPC_CREAT | IPC_EXCL);
sem0.val=1;
sem1.val=0;
sem2.val=0;
semctl(id,0,SETVAL,sem0);
semctl(id,1,SETVAL,sem1);
semctl(id,2,SETVAL,sem2);
return 0;
}
/*FIRST PROCESS*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
void first(int d){
struct timespec* ts;
ts=malloc(sizeof(struct timespec));
ts->tv_sec=0;
ts->tv_nsec=1000*d;
int i;
char name[6]={'S','T','A','C','K',' '};
for(i=0;i<6;i++){
putchar(name[i]);
fflush(stdout);
nanosleep(ts,NULL);
}
}
struct sembuf in = {0,-1,0};
struct sembuf out = {1,1,0};
int main(int argc,char** argv){
int key=ftok("/tmp",'L');
int id=semget(key,0,0);
while(1){
semop(id,&in,1);
first(strtol(argv[1],NULL,0));
semop(id,&out,1);
}
return 0;
}
/*SECOND PROCESS*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
void first(int d){
struct timespec* ts;
ts=malloc(sizeof(struct timespec));
ts->tv_sec=0;
ts->tv_nsec=1000*d;
int i;
char name[4]={'O','V','E','R'};
for(i=0;i<4;i++){
putchar(name[i]);
fflush(stdout);
nanosleep(ts,NULL);
}
}
struct sembuf in = {1,-1,0};
struct sembuf out = {2,1,0};
int main(int argc,char** argv){
int key=ftok("/tmp",'L');
int id=semget(key,0,0);
while(1){
semop(id,&in,1);
first(strtol(argv[1],NULL,0));
semop(id,&out,1);
}
return 0;
}
/*THIRD PROCESS*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
void first(int d){
struct timespec* ts;
ts=malloc(sizeof(struct timespec));
ts->tv_sec=0;
ts->tv_nsec=1000*d;
int i;
char name[5]={'F','L','O','W','S'};
for(i=0;i<5;i++){
putchar(name[i]);
fflush(stdout);
nanosleep(ts,NULL);
}
putchar('\n');
}
struct sembuf in = {2,-1,0};
struct sembuf out = {0,1,0};
int main(int argc,char** argv){
int key=ftok("/tmp",'L');
int id=semget(key,0,0);
while(1){
semop(id,&in,1);
first(strtol(argv[1],NULL,0));
semop(id,&out,1);
}
return 0;
}
Here we have three process and i am using semaphores. Now what if i want to write the first word(process 1) x times, the second y times and the third z times. What i want to do is adding another semaphore to each process, the value of these semaphores will be the number of times the process must run through it's code. Can someone help me with that, i don't know how to semop on the count semaphores.
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);
}