Использование семафоров POSIX между пространствами имен ядра Linux

Я работаю над приложением C, используя пространства имен Linux, и одна вещь, которая возникла, — это необходимость сигнализировать дочернему пространству имен от родителя с помощью семафора (или чего-то подобного). Вот что я пытаюсь сделать в данный момент:

#define _GNU_SOURCE
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <semaphore.h> 

//A stack for the container
#define STACK_SIZE (1024 * 1024)
static char stack[STACK_SIZE];

//The semaphore
sem_t semaphore;

int child(void* arg){
    int semval;

    //Print the semaphore state as read from the new namespace
    for(int i=0;i<6;i++){
        sem_getvalue(&semaphore, &semval);
        printf("Semaphore state: %d.\n", semval);
        sleep(1);
    }

    return 1;
}

int main(){
    //Init a shared POSIX semaphore with the value zero
    sem_init(&semaphore, 1, 0); 

    //Create the child namespace
    pid_t pid = clone(child, stack+STACK_SIZE, CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL);

    //Wait, then post the semaphore
    sleep(3);
    printf("Posting semaphore\n");
    sem_post(&semaphore);

    //Wait for it to return
    waitpid(pid, NULL, 0);

    return 0;
}

Насколько я понимаю, это должно запустить child в новом пространстве имен, где он несколько раз выдаст значение семафора. Мы должны иметь возможность видеть, когда родительский процесс в родительском пространстве имен публикует его, однако мы этого не делаем:

Semaphore state: 0.
Semaphore state: 0.
Semaphore state: 0.
Posting semaphore
Semaphore state: 0.
Semaphore state: 0.
Semaphore state: 0.

Семафор инициализируется как общий, и удаление CLONE_NEWIPC из вызова клона также не исправляет этого (насколько я понимаю, это в любом случае касается только изоляции SysV IPC, а не этого семафора POSIX).

Еще одна особенность этого заключается в том, что если мы инициализируем семафор другим значением (например, sem_init(&semaphore, 1, 3);), дочернее пространство имен будет читать это начальное значение:

Semaphore state: 3.
Semaphore state: 3.
Semaphore state: 3.
Posting semaphore
Semaphore state: 3.
Semaphore state: 3.
Semaphore state: 3.

Таким образом, он, по-видимому, не полностью не может получить доступ к семафору — он просто не видит, когда он опубликован. Как вы должны это сделать? Есть ли какой-то особый трюк с общей памятью, который мне нужно настроить, чтобы заставить его работать между пространствами имен, или я просто делаю что-то не так?


person DodoDude700    schedule 01.01.2021    source источник


Ответы (1)


sem_* предполагает, что память семафора разделяется между процессами/потоками.

Когда вы clone/fork, вы получаете другую копию.

Чтобы это исправить, добавьте CLONE_VM к аргументу flags [предпочтительно].

Или убедитесь, что семафор находится в общей памяти (например, mmap, shmget и т. д.), прежде чем выполнять clone.

person Craig Estey    schedule 02.01.2021
comment
Спасибо! Сделал это, mmaping анонимную общую память, и теперь это работает. Я знаю, что анонимная общая память доступна только процессу сопоставления и его дочерним процессам, но есть ли способ контролировать, какой из этих дочерних процессов может получить к ней доступ, если их несколько? - person DodoDude700; 02.01.2021