简体   繁体   English

使用 fork() 生成多个进程并将共享内存密钥作为 cmd arg 传递

[英]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 .我有一个所谓的distributor程序程序,它为传递给distributor程序的每个 IP 地址生成另一个程序af_xdp_user Before doing this, distributor generates a shared memory:在此之前, distributor生成一个共享内存:

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: print_statistics是一个函数,它访问(将来所有stats_record结构)共享内存的第一个stats_record -struct 并打印接收到的数据包数量:

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:每个带有程序af_xdp_useraf_xdp_user然后在struct stats_record写入有关接收到的 IP 数据包的某些统计信息,如下所示:

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:我不知道我对fork()的想法是否正确,但我得到了这个奇怪的输出:

$ 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?在我看来,这意味着distributor退出了,但我不知道它为什么会退出?

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 . shmat函数必须与生成的ID一起使用,而不是 IPC密钥SHM_KEY
Let's remember that the diagram is as follows :让我们记住图表如下:
1- Call shmget with IPC_MEMORY_KEY to get IPC_MEMORY_ID 1- 使用IPC_MEMORY_KEY调用 shmget 以获取IPC_MEMORY_ID
2- Call shmat with the generated IPC_MEMORY_ID 2- 使用生成的IPC_MEMORY_ID调用 shmat

In your case char *shmd = shmat(SHM_KEY, NULL, 0);在你的情况下char *shmd = shmat(SHM_KEY, NULL, 0); you call shmat with a Key and not an ID .您使用Key而不是ID调用shmat 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)  

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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