Question

I've created a program that shows shared memory segment info by shmid (shared memory id) passed as an argument.

Comparing the data with those returned by the command ipcs, it is clear that my program shows some wrong information about shared memory segment.

Can you help me understand why?

Thank you.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>
#include <errno.h>

struct shmem_info {
    int id;
    struct shmid_ds data;
};

int *allocate_int(int n) {
    int *mem;

    if((mem=malloc(n*sizeof(int)))==NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    return mem;
}

struct shmem_info *allocate_shminfo(int n) {
    struct shmem_info *mem;

    if((mem=malloc(n*sizeof(struct shmem_info)))==NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    return mem;
}

int parse_int(char *str) {
    int n;

    n=atoi(str);

    return n;
}

int open_fileRW(char *path) {
    int fd;

    if((fd=open(path,O_RDWR|O_CREAT,0666))==-1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    return fd;
}

void close_file(int fd) {

    if(close(fd)==-1) {
        perror("close");
        exit(EXIT_FAILURE);
    }
}

struct shmid_ds get_shminfo(int id) {
    struct shmid_ds data;

    errno=0;

    if(shmctl(id,IPC_STAT,&data)==-1) {
        switch(errno) {
            case EACCES:
                fprintf(stderr,"Shmid %d: read acces not allowed\n", id);
                exit(EXIT_FAILURE);

            case EINVAL:
                fprintf(stderr,"Shmid %d: invalid shmid\n", id);
                exit(EXIT_FAILURE);

            default:
                perror("shmctl");
                exit(EXIT_FAILURE);
                break;
        }
    }

    return data;
}

void write_shminfo(int fd, struct shmem_info shmi) {
    ssize_t w, tot=0, size=sizeof(struct shmem_info);

    for(;;) {
        errno=0;

        w=write(fd,&shmi,size-tot);

        if(w==-1 && errno!=EINTR) {
            perror("write");
            exit(EXIT_FAILURE);
        }

        if(w==0) return;

        tot+=w;
    }
}

struct shmem_info read_shminfo(int fd) {
    ssize_t r, tot=0, size=sizeof(struct shmem_info);
    struct shmem_info shmi;

    for(;;) {
        errno=0;

        r=read(fd,&shmi,size-tot);

        if(r==-1 && errno!=EINTR) {
            perror("write");
            exit(EXIT_FAILURE);
        }

        if(r==0) return shmi;

        tot+=r;
    }
}

void print_shminfo(FILE *out, struct shmem_info shmi) {
    fprintf(out,"Shmid: %d\n", shmi.id);
    fprintf(out,"Size of segment (bytes): %d\n", (int)shmi.data.shm_segsz);
    fprintf(out,"PID of creator: %d\n", (int)shmi.data.shm_cpid);
    fprintf(out,"No. of current attaches: %d\n", (int)shmi.data.shm_nattch);
    fprintf(out,"Last attach time: %ld\n", shmi.data.shm_atime);
    fprintf(out,"Last detach time: %ld\n", shmi.data.shm_dtime);
    fprintf(out,"Last change time: %ld\n", shmi.data.shm_ctime);
    fprintf(out,"PID of last shmat/shmdt: %d\n", (int)shmi.data.shm_lpid);
    fprintf(out,"Key supplied to shmget(2): %d\n", (int)shmi.data.shm_perm.__key);
    fprintf(out,"Effective UID of owner: %d\n", (int)shmi.data.shm_perm.uid);
    fprintf(out,"Effective GID of owner: %d\n", (int)shmi.data.shm_perm.gid);
    fprintf(out,"Effective UID of creator: %d\n", (int)shmi.data.shm_perm.cuid);
    fprintf(out,"Effective GID of creator: %d\n", (int)shmi.data.shm_perm.cgid);
    fprintf(out,"Permissions + SHM_DEST and ESHM_LOCKED flag: %hd\n", shmi.data.shm_perm.mode);
    fprintf(out,"Sequence number: %hd\n", shmi.data.shm_perm.__seq);
    fprintf(out,"\n");
}

int main(int argc, char *argv[]) {
    int fd, n, i;
    struct shmem_info *shmi;

    if(argc<2) {
        fprintf(stderr,"Usage: %s <shmid> <shmid> ... <shmid>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    n=argc-1;

    argv=argv+1;

    shmi=allocate_shminfo(n);

    for(i=0;i<n;i++) {
        shmi[i].id=parse_int(argv[i]);
    }

    for(i=0;i<n;i++) {
        shmi[i].data=get_shminfo(shmi[i].id);
    }

    fd=open_fileRW("shmid_info-log.txt");

    for(i=0;i<n;i++) {
        write_shminfo(fd,shmi[i]);
    }

    for(i=0;i<n;i++) {
        shmi[i]=read_shminfo(fd);
    }

    for(i=0;i<n;i++) {
        print_shminfo(stdout,shmi[i]);
    }

    close_file(fd);

    free(shmi);

    exit(EXIT_SUCCESS);
}
Was it helpful?

Solution

It is your read_shminfo function which has a problem. It works on a local shmi, instead of dealing with the shmi allocated with shmi=allocate_shminfo(n);`

One way to fix:

void read_shminfo(int fd, struct shmem_info *shmi) {
//    struct shmem_info shmi;
    ssize_t r, tot=0, size=sizeof(struct shmem_info);

    for(;;) {
        errno=0;

        r=read(fd,(void *)&shmi,size-tot);

        if(r==-1 && errno!=EINTR) {
            perror("write");
            exit(EXIT_FAILURE);
        }

        if(r==0)
                return ;

        tot+=r;
    }
}

and in main:

for(i=0;i<n;i++) {
    read_shminfo(fd,&shmi[i]);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top