在 Linux 内核命名空间之间使用 POSIX 信号量
Using POSIX semaphores between Linux kernel namespaces
我正在开发一个使用 Linux 名称空间的 C 应用程序,出现的一件事是需要使用信号量(或类似的东西)从父名称空间向子名称空间发出信号。这是我目前正在尝试做的事情:
#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.
因此,它似乎并非完全无法访问信号量 - 它只是无法看到它何时发布。你应该怎么做?是否需要设置一些特殊的共享内存技巧才能使其在名称空间之间工作,或者我只是在这里做错了什么?
sem_*
假设信号量内存在 processes/threads.
之间 共享
当您 clone/fork
时,您会得到一个不同的副本。
要修复,请将 CLONE_VM
添加到您的标志参数 [首选]。
或者,在执行 clone
.
之前确保信号量在共享内存中(例如 mmap
、shmget
等)
我正在开发一个使用 Linux 名称空间的 C 应用程序,出现的一件事是需要使用信号量(或类似的东西)从父名称空间向子名称空间发出信号。这是我目前正在尝试做的事情:
#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.
因此,它似乎并非完全无法访问信号量 - 它只是无法看到它何时发布。你应该怎么做?是否需要设置一些特殊的共享内存技巧才能使其在名称空间之间工作,或者我只是在这里做错了什么?
sem_*
假设信号量内存在 processes/threads.
当您 clone/fork
时,您会得到一个不同的副本。
要修复,请将 CLONE_VM
添加到您的标志参数 [首选]。
或者,在执行 clone
.
mmap
、shmget
等)