简体   繁体   中英

Spawn multiple processes with fork() and pass shared memory key as cmd arg

I have a so-called distributor program which spawns another program af_xdp_user for each IP-address passed to distributor . Before doing this, distributor generates a shared memory:

int create_shrd_memory(uint64_t size) {
    const int shmid = shmget(SHM_KEY, size, IPC_CREAT | IPC_EXCL);
    if(shmid == -1) {
        if(errno == EEXIST) {
            printf("Shared memory with Key %d already exists, continue...\n", SHM_KEY);
            return SHM_KEY;
        } else {
            fprintf(stderr, "Failed to obtain Shared Memory: %s\n", strerror(errno));
            perror("shmget");
            exit(1);
        }
    }

    return shmid;
}

This shared-memory-key is then passed to each sub-process as a command line argument (along several other arguments):

#define SHM_KEY 0x1235

bool global_exit = false;

static void exit_application(int signal)
{
    signal = signal;
    global_exit = true;
}

int main(int argc, char **argv) {

    const uint8_t amnt_of_ip_addrs = argc - 1;

    const int shmid = create_shrd_memory( sizeof(struct stats_record) * amnt_of_ip_addrs );

    char shrdmemid[96];
    char shrdmemidx[96];
    pid_t childs[amnt_of_ip_addrs];

    for(uint8_t ip_index = 1; ip_index < argc; ip_index++) {

        printf("Forked for IP: %s\n", argv[ip_index]);

        pid_t pid = fork();
        if(pid == 0) { /* child */

            static char argv_child[13][18] = { "af_xdp_user", "--dev", "eth20", "--shrdmem",  "", "--shrdmemidx", "", "--progsec", "xdp_sock", "--filename", "af_xdp_kern.o", "-Q", ""};

            sprintf(shrdmemid, "%d", shmid);
            sprintf(shrdmemidx, "%d", ip_index - 1);

            strcpy(argv_child[4], shrdmemid);
            strcpy(argv_child[6], shrdmemidx);
            strcpy(argv_child[12], shrdmemidx);

            printf("Arguments:\n");
            for(uint8_t arg_idx = 0; arg_idx < sizeof(argv_child) / sizeof(argv_child[0]); arg_idx++) {
                printf("\t%s\n", argv_child[arg_idx]);
            }

            execl("af_xdp_user", argv_child[0], argv_child[1], argv_child[2], argv_child[3], argv_child[4], argv_child[5], argv_child[6], argv_child[7], argv_child[8], argv_child[9], argv_child[10], NULL);

        } else if(pid < 0) {
            printf("FORK FAILED!\n");
        } else {
            // childs[ip_index - 1] = pid;
        }
    }

    signal(SIGINT, exit_application);

    while(!global_exit) {
        print_statistics(amnt_of_ip_addrs);
        sleep(2);
    }
}

With print_statistics being a function that accesses (in the future all stats_record structs) the first stats_record -struct of the shared memory and prints the amount of received packets:

void print_statistics(const int amnt_of_processes) {
    printf("STATISTICS:\n");
    char *shmd = shmat(SHM_KEY, NULL, 0);
    struct stats_record *stats = (struct stats_record*)(shmd);
    printf("\tREC PACKETS: %lu\n", stats->rx_packets);
}

Each subprocess with the program af_xdp_user then writes certain statistics about received IP-packets in a struct stats_record like this:

char *shm_data = shmat(cfg->shrdmem_id, NULL, 0);
if(shm_data == -1) {
    fprintf(stderr, "Failed to obain shared memory: %s\n", strerror(errno));
    exit(1);
}
struct stats_record *stats = (struct stats_record*)(shm_data + sizeof(struct stats_record) * cfg->shrdmem_idx);

...

stats->rx_bytes += amnt_of_packets * bytes;
stats->rx_packets += rcvd;

shmdt(shm_data);

I don't know if I got the idea of fork() right but I get this strange output:

$ sudo ./distributor 127.0.0.1
Shared memory with Key 4661 already exists, continue...
Forked for IP: 127.0.0.1
STATISTICS:
Arguments:
        af_xdp_user
        --dev
        eth20
        --shrdmem
        4661
        --shrdmemidx
        0
        --progsec
        xdp_sock
        --filename
        af_xdp_kern.o
        -Q
        0
SHRDMEM-ID: 4661
SHRDMEM-IDX: 0
Segmentation fault
$ RX-Queue: 0
...
Failed to obain shared memory: Invalid argument

Notice the second $ I get on the command line. In my opinion, this means that distributor exited, but I don't know why it would exit?

I did some investigations on your program. Your segmentation fault is caused by this:

char *shmd = shmat(SHM_KEY, NULL, 0);

The shmat function must be used whith the generated ID and NOT the IPC key SHM_KEY .
Let's remember that the diagram is as follows :
1- Call shmget with IPC_MEMORY_KEY to get IPC_MEMORY_ID
2- Call shmat with the generated IPC_MEMORY_ID

In your case char *shmd = shmat(SHM_KEY, NULL, 0); you call shmat with a Key and not an ID . Therefore, your pointer is not valid.
In addition, i noticed that your program created abandoned shared memories:

ipcs -m     

在此处输入图片说明

you must delete them in your code by calling :

shmctl(IPC_MEMORY_ID , IPC_RMID ,NULL); // ID and not Key !  

Or, by commande line :

ipcrm -m MEM_ID (and not Key)  

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM