Создайте несколько процессов с помощью fork () и передайте ключ разделяемой памяти как cmd arg - PullRequest
0 голосов
/ 02 марта 2020

У меня есть так называемая distributor программа, которая порождает другую программу af_xdp_user для каждого IP-адреса, переданного distributor. Перед этим 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;
}

Этот ключ общей памяти затем передается каждому подпроцессу в качестве аргумента командной строки (вместе с несколькими другими аргументами):

#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);
    }
}

С print_statistics - функцией, которая обращается (в будущем ко всем структурам stats_record) к первой stats_record -структуре разделяемой памяти и печатает количество полученных пакетов:

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);
}

Каждый подпроцесс с программой af_xdp_user затем записывает определенную статистику о полученных IP-пакетах в struct stats_record следующим образом:

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);

Я не знаю, получил ли я идею 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

Обратите внимание на второе $, которое я получаю в командной строке. На мой взгляд, это означает, что distributor завершено, но я не знаю, почему оно завершится?

1 Ответ

0 голосов
/ 03 марта 2020

Я провел несколько исследований по вашей программе. Ваша ошибка сегментации вызвана этим:

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

Функция shmat должна использоваться с сгенерированным ID , а НЕ с ключом IP C SHM_KEY.
Давайте вспомним, что диаграмма выглядит следующим образом:
1 - вызовите shmget с помощью IPC_MEMORY_KEY, чтобы получить IPC_MEMORY_ID
2 - вызовите shmat с помощью сгенерированного IPC_MEMORY_ID

В вашем случае char *shmd = shmat(SHM_KEY, NULL, 0); вы звоните shmat с Key, а не с ID. Следовательно, ваш указатель недействителен.
Кроме того, я заметил, что ваша программа создала заброшенные общие воспоминания:

ipcs -m     

enter image description here

вы должны удалите их в своем коде, позвонив по номеру:

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

или по коммандной строке:

ipcrm -m MEM_ID (and not Key)  

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...