簡體   English   中英

在 docker 容器內使用 membarrier

[英]Use a membarrier inside a docker container

我有一個程序需要能夠處理 SIGTERM。 為此,我需要 sigterm 處理程序將設置的sig_atomic_t全局標志。 為了使主代碼能夠可靠地讀取該變量,我需要在處理程序和主代碼中都使用一個 membarrier。

正如我現在所擁有的,它是這樣的:

static  int             mb_cmd;
static  sig_atomic_t    sigterm;


static
int     mb_init(void);
static
int     sigterm_init(void);
static
void    sigterm_handler(int sig);


inline
int     membarrier(int cmd, int flags)
{
        return  syscall(__NR_membarrier, cmd, flags);
}


int     main(void)
{
        int     status;

        status  = 1;
        if (sigterm_init())
                goto err;

        do {
                // do stuff
                asm volatile ("" : : : "memory");
        } while (!sigterm);

        return  0;
err:
        fprintf(stderr, "ERROR: main(): %i\n", status);
        perrorx(NULL);

        return  status;
}


static
int     mb_init(void)
{
        static bool     done = false;
        int             cmd;
        int             status;

        if (done)
                return  0;

        status  = 1;
        cmd     = membarrier(MEMBARRIER_CMD_QUERY, 0);
        if (cmd < 0)
                goto err;

        if (cmd & MEMBARRIER_CMD_PRIVATE_EXPEDITED) {
                status  = 2;
                mb_cmd  = MEMBARRIER_CMD_PRIVATE_EXPEDITED;
                if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0))
                        goto err;
        } else if (cmd & MEMBARRIER_CMD_GLOBAL_EXPEDITED) {
                status  = 3;
                mb_cmd  = MEMBARRIER_CMD_GLOBAL_EXPEDITED;
                if (membarrier(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, 0))
                        goto err;
        } else {
                mb_cmd  = MEMBARRIER_CMD_GLOBAL;
        }

        status  = 4;
        if (membarrier(mb_cmd, 0))
                goto err;
        done    = true;
        return  0;
err:
        fprintf(stderr, "ERROR: mb_init(): %i\n", status);
        return  status;

}

static
int     sigterm_init(void)
{
        struct sigaction        sa = {0};
        int                     status;

        status  = 1;
        if (mb_init())
                goto err;

        sigterm = false;
        membarrier(mb_cmd, 0);

        status++;
        sigemptyset(&sa.sa_mask);
        sa.sa_handler   = &sigterm_handler;
        if (sigaction(SIGTERM, &sa, NULL))
                goto err;
        return  0;
err:
        fprintf(stderr, "ERROR: sigterm_init(): %i\n", status);
        return  status;
}

static
void    sigterm_handler(int sig)
{

        (void)sig;

        sigterm = true;
        membarrier(mb_cmd, 0);
}

當我在我的計算機上運行該程序時,它工作正常,但在 docker 上它顯示以下錯誤( errno為 1):

ERROR: mb_init(): 1
ERROR: sigterm_init(): 1
ERROR: main(): 1
./rob:
    rob.c:184:
    main():
    E1 -    Operation not permitted

如何在應該在 docker 上運行的程序中使用內存屏障?

默認情況下, membarrier系統調用不在 Docker seccomp 白名單中,因此如果要使用它,則需要將修改后的配置文件傳遞給 docker docker run命令:

docker run --security-opt seccomp=/path/to/seccomp/profile.json myimage

我不確定為什么沒有列入白名單,您可以詢問 docker 開發人員這是錯誤還是預期配置。

為了使主代碼能夠可靠地讀取該變量,我需要在處理程序和主代碼中都使用一個 membarrier。

不,只需將其volatile sig_atomic_t ISO C 保證將使您的代碼正常工作,而無需在源代碼中編寫任何明確的障礙。 (基本上象無鎖_Atomic與mo_relaxed排序,除了有序WRT。其它揮發性訪問。)

如果你確實需要一個內存屏障,你不需要membarrier系統調用,只是asm("" ::: "memory")迫使商店或負載發生至少一次的循環。

如果您有另一個線程從內存執行弱排序加載,但無法優化掉(從循環中提升membarrier()可能會很有用。 如果您在生產者線程中的兩個存儲之間執行此操作,那么membarrier()可能會將另一個核心上的輕松負載有效地轉換為獲取負載。

由於您已經在閱讀器中使用了編譯時完整屏障(以阻止非易失性負載被提升出循環),並且檢查 exit_now 或 keep_running 標志沒有順序wrt。 其他代碼,你不需要那個。


ISO C 只保證volatile sig_atomic_t任何東西,而不是簡單的sig_atomic_t (通常只是int )。 使用sig_atomic_t的唯一原因是您將它與volatile

實際上, volatile int甚至對其他線程可見,而不僅僅是在信號處理程序和暫停運行信號處理程序的線程之間。 (因為真正的 C 實現在緩存一致的硬件上運行,並且不進行硬件競爭檢測等)但此時您只是在滾動自己的無鎖原子,而應該使用 _Atomic _Atomic int 另請參閱https://electronics.stackexchange.com/questions/387181/mcu-programming-c-o2-optimization-breaks-while-loop/387478#387478以了解單線程和中斷(或信號)處理程序之間的原子性。

另請參閱何時將 volatile 與多線程一起使用? -基本上都不使用C11 _Atomicstdatomic.h 我的回答解釋了為什么它在實踐中有效,以及究竟會發生什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM